Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[test](sqle/RuleList): code review issue and add unit tests #206

Merged
merged 3 commits into from
Feb 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion packages/sqle/src/components/RuleList/RuleList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,18 @@ const RuleList: React.FC<RuleListProps> = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [rules]);

const pageRemainingHeight = useMemo(() => {
// #if [demo || ce]
return pageHeaderHeight + 182;
// #else
return pageHeaderHeight + 127;
// #endif
}, [pageHeaderHeight]);

return (
<>
<RulesStyleWrapper
pageHeaderHeight={pageHeaderHeight}
pageHeaderHeight={pageRemainingHeight}
className="rule-list-wrapper"
// #if [demo || ce]
paddingBottomNone={true}
Expand Down
13 changes: 11 additions & 2 deletions packages/sqle/src/components/RuleList/RuleTypes.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useEffect } from 'react';
import { useEffect, useRef } from 'react';
import { RuleTypesProps } from './index.type';
import { RuleTypeItemStyleWrapper, RuleTypeStyleWrapper } from './style';
import useRuleType from '../../hooks/useRuleType';
import { useControllableValue } from 'ahooks';
import { isEqual } from 'lodash';
import { IRuleResV1 } from '@actiontech/shared/lib/api/sqle/service/common';

export const ALL_RULE_TYPE_CONSTANT = 'ALL';

Expand All @@ -12,6 +14,9 @@
allRulesData,
rules = []
}) => {
const allRulesDataRef = useRef<IRuleResV1[]>();
const rulesRef = useRef<IRuleResV1[]>();

const { getRuleTypeDataSource, ruleTypeData } = useRuleType();

const [internalRuleType, setInternalRuleType] = useControllableValue<string>(
Expand All @@ -27,7 +32,11 @@
);

useEffect(() => {
getRuleTypeDataSource(allRulesData, rules);
if (!isEqual(allRulesDataRef, allRulesData) || !isEqual(rulesRef, rules)) {

Check warning on line 35 in packages/sqle/src/components/RuleList/RuleTypes.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
allRulesDataRef.current = allRulesData;
allRulesDataRef.current = rules;
getRuleTypeDataSource(allRulesData, rules);
}
}, [allRulesData, rules, getRuleTypeDataSource]);

return (
Expand Down
1 change: 0 additions & 1 deletion packages/sqle/src/components/RuleList/index.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export type RuleListProps = {
isAction?: boolean;
actionType?: RuleStatusEnum;
renderDisableNode?: (rule: IRuleResV1) => ReactNode;
isShowEndText?: boolean;
activeDataKeys?: string[];
onActionHandle?: (record: IRuleResV1, type: typeActionType) => void;
enableCheckDetail?: boolean;
Expand Down
7 changes: 1 addition & 6 deletions packages/sqle/src/components/RuleList/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,7 @@ export const RulesStyleWrapper = styled('div')<{
flex-direction: column;
align-items: flex-start;
align-self: stretch;
height: ${({ paddingBottomNone, pageHeaderHeight }) =>
`calc(100vh - ${
paddingBottomNone
? 59 + 68 + 55 + pageHeaderHeight
: 59 + 68 + pageHeaderHeight
}px)`};
height: ${({ pageHeaderHeight }) => `calc(100vh - ${pageHeaderHeight}px)`};
padding: 0 30px ${({ paddingBottomNone }) => (paddingBottomNone ? 0 : '8px')}
40px;
overflow: hidden;
Expand Down
39 changes: 39 additions & 0 deletions packages/sqle/src/components/RuleList/test/RuleList.ce.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @test_version ce
*/

import RuleList from '../RuleList';
import { act, cleanup } from '@testing-library/react';
import { renderWithTheme } from '../../../testUtils/customRender';
import { RuleListProps, RuleStatusEnum } from '../index.type';
import { ruleListMockData } from '../../../testUtils/mockApi/rule_template/data';

describe('sqle/components/RuleList CE', () => {
const onActionHandleSpy = jest.fn();
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.useRealTimers();
cleanup();
});

const customRender = (props: RuleListProps) => {
return renderWithTheme(
<RuleList {...props} onActionHandle={onActionHandleSpy} />
);
};

it('should match snap', async () => {
const { baseElement } = customRender({
pageHeaderHeight: 120,
rules: ruleListMockData,
isAction: true,
actionType: RuleStatusEnum.disabled,
enableCheckDetail: true
});
await act(async () => jest.advanceTimersByTime(3000));
expect(baseElement).toMatchSnapshot();
});
});
180 changes: 180 additions & 0 deletions packages/sqle/src/components/RuleList/test/RuleList.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import RuleList from '../RuleList';
import { act, cleanup, fireEvent, screen } from '@testing-library/react';
import { renderWithTheme } from '../../../testUtils/customRender';
import { getBySelector } from '@actiontech/shared/lib/testUtil/customQuery';
import { RuleListProps, RuleStatusEnum } from '../index.type';
import { ruleListMockData } from '../../../testUtils/mockApi/rule_template/data';
import { RuleResV1LevelEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum';

describe('sqle/components/RuleList', () => {
const onActionHandleSpy = jest.fn();
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.useRealTimers();
cleanup();
});

const customRender = (props: RuleListProps) => {
return renderWithTheme(
<RuleList {...props} onActionHandle={onActionHandleSpy} />
);
};

it('should match snap shot when no rule data', async () => {
const { baseElement } = customRender({ pageHeaderHeight: 100 });
await act(async () => jest.advanceTimersByTime(3300));
expect(baseElement).toMatchSnapshot();
});

it('should match snap shot when has props', async () => {
const { baseElement } = customRender({
pageHeaderHeight: 120,
rules: ruleListMockData
});
await act(async () => jest.advanceTimersByTime(3000));
expect(baseElement).toMatchSnapshot();
});

it('should match snap shot when isAction is true', async () => {
const { baseElement } = customRender({
pageHeaderHeight: 120,
rules: ruleListMockData,
isAction: true
});
await act(async () => jest.advanceTimersByTime(3000));

const ruleItemELe = getBySelector('.infinite-scroll-component ')
.children[0];
fireEvent.mouseEnter(ruleItemELe);
await act(async () => jest.advanceTimersByTime(100));
expect(baseElement).toMatchSnapshot();

const enabledButton = getBySelector('.disabled-rule-item', ruleItemELe);
fireEvent.mouseOver(enabledButton);
await act(async () => jest.advanceTimersByTime(100));
expect(screen.getByText('禁用该规则')).toBeInTheDocument();
fireEvent.click(enabledButton);
await act(async () => jest.advanceTimersByTime(100));
expect(onActionHandleSpy).toBeCalledTimes(1);
});

it('should match snap shot when actionType is enabled', async () => {
const { baseElement } = customRender({
pageHeaderHeight: 120,
rules: ruleListMockData,
isAction: true,
actionType: RuleStatusEnum.enabled
});
await act(async () => jest.advanceTimersByTime(3000));
const ruleItemELe = getBySelector('.infinite-scroll-component ')
.children[0];
fireEvent.mouseEnter(ruleItemELe);
await act(async () => jest.advanceTimersByTime(100));
expect(baseElement).toMatchSnapshot();
const editButton = getBySelector('.edit-rule-item', ruleItemELe);
fireEvent.mouseOver(editButton);
await act(async () => jest.advanceTimersByTime(100));
expect(screen.getByText('编辑该规则')).toBeInTheDocument();
fireEvent.click(editButton);
await act(async () => jest.advanceTimersByTime(100));
expect(onActionHandleSpy).toBeCalledTimes(1);
});

it('should match snap shot when actionType is disabled', async () => {
const { baseElement } = customRender({
pageHeaderHeight: 120,
rules: ruleListMockData,
isAction: true,
actionType: RuleStatusEnum.disabled
});
await act(async () => jest.advanceTimersByTime(3000));
const ruleItemELe = getBySelector('.infinite-scroll-component ')
.children[0];
fireEvent.mouseEnter(ruleItemELe);
await act(async () => jest.advanceTimersByTime(100));
expect(baseElement).toMatchSnapshot();

const enabledButton = getBySelector('.enabled-rule-item', ruleItemELe);
fireEvent.mouseOver(enabledButton);
await act(async () => jest.advanceTimersByTime(100));
expect(screen.getByText('启用该规则')).toBeInTheDocument();
fireEvent.click(enabledButton);
await act(async () => jest.advanceTimersByTime(100));
expect(onActionHandleSpy).toBeCalledTimes(1);
});

it('should match snap shot when has renderDisableNode', async () => {
const { baseElement } = customRender({
pageHeaderHeight: 120,
rules: ruleListMockData,
isAction: true,
actionType: RuleStatusEnum.enabled,
renderDisableNode: () => <span>disable</span>
});
await act(async () => jest.advanceTimersByTime(3000));
expect(baseElement).toMatchSnapshot();
});

it('should match snap shot when enableCheckDetail is true', async () => {
const { baseElement } = customRender({
pageHeaderHeight: 120,
rules: ruleListMockData,
isAction: true,
actionType: RuleStatusEnum.disabled,
enableCheckDetail: true
});
await act(async () => jest.advanceTimersByTime(3000));
expect(baseElement).toMatchSnapshot();
const ruleItemELe = getBySelector('.infinite-scroll-component').children[0];
fireEvent.click(ruleItemELe);
await act(async () => jest.advanceTimersByTime(300));
expect(screen.getByText('查看规则')).toBeInTheDocument();
expect(screen.getByText('规则知识库')).toBeInTheDocument();
expect(baseElement).toMatchSnapshot();
});

it('scroll infinite list', async () => {
const mockInfiniteList = new Array(20).fill('').map((_, index) => ({
annotation: `test rule ${index}`,
db_type: 'mysql',
desc: `test desc ${index}`,
is_custom_rule: true,
level: RuleResV1LevelEnum.normal,
rule_name: `testRuleName${index}`,
type: 'DDL规范'
}));
const { baseElement } = customRender({
pageHeaderHeight: 300,
rules: mockInfiniteList
});
await act(async () => jest.advanceTimersByTime(3000));
fireEvent.scroll(getBySelector('#rule-list-wrapper-id', baseElement), {
y: 50
});
await act(async () => jest.advanceTimersByTime(300));
fireEvent.scroll(getBySelector('#rule-list-wrapper-id', baseElement), {
y: 100
});
await act(async () => jest.advanceTimersByTime(300));
fireEvent.scroll(getBySelector('#rule-list-wrapper-id', baseElement), {
y: 200
});
await act(async () => jest.advanceTimersByTime(300));
fireEvent.scroll(getBySelector('#rule-list-wrapper-id', baseElement), {
y: 300
});
await act(async () => jest.advanceTimersByTime(300));
fireEvent.scroll(getBySelector('#rule-list-wrapper-id', baseElement), {
y: 300
});
await act(async () => jest.advanceTimersByTime(300));
fireEvent.scroll(getBySelector('#rule-list-wrapper-id', baseElement), {
y: 500
});
await act(async () => jest.advanceTimersByTime(300));
expect(baseElement).toMatchSnapshot();
});
});
45 changes: 45 additions & 0 deletions packages/sqle/src/components/RuleList/test/RuleStatus.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import RuleStatus from '../RuleStatus';
import { act, cleanup, fireEvent, screen } from '@testing-library/react';
import { renderWithTheme } from '../../../testUtils/customRender';
import { RuleStatusEnum } from '../index.type';

describe('sqle/components/RuleStatus', () => {
const ruleStatusChangeSpy = jest.fn();
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.useRealTimers();
cleanup();
});

it('should match snap shot when enabled', async () => {
const { baseElement } = renderWithTheme(
<RuleStatus currentRuleStatus={RuleStatusEnum.enabled} />
);
await act(async () => jest.advanceTimersByTime(3000));
expect(baseElement).toMatchSnapshot();
});

it('should match snap shot when disabled', async () => {
const { baseElement } = renderWithTheme(
<RuleStatus currentRuleStatus={RuleStatusEnum.disabled} />
);
await act(async () => jest.advanceTimersByTime(3000));
expect(baseElement).toMatchSnapshot();
});

it('should match snap shot when has ruleStatusChange', async () => {
const { baseElement } = renderWithTheme(
<RuleStatus
currentRuleStatus={RuleStatusEnum.disabled}
ruleStatusChange={ruleStatusChangeSpy}
/>
);
await act(async () => jest.advanceTimersByTime(3000));
fireEvent.click(screen.getByText('已启用'));
await act(async () => jest.advanceTimersByTime(100));
expect(baseElement).toMatchSnapshot();
});
});
Loading
Loading