Skip to content

Commit f9e6ba2

Browse files
committed
[test]: Add unit tests
1 parent 45741d5 commit f9e6ba2

File tree

50 files changed

+18669
-7
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+18669
-7
lines changed

packages/shared/lib/testUtil/mockApi/sqle/sqlOptimization/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class SqlOptimization implements MockSpyApy {
1616
this.optimizeSQLReq();
1717
this.getOptimizationRecordReq();
1818
this.getOptimizationSQLs();
19-
this.getOptimizationReq();
19+
this.getOptimizationSQLDetail();
2020
this.getDBPerformanceImproveOverview();
2121
this.getOptimizationOverview();
2222
}
@@ -59,8 +59,8 @@ class SqlOptimization implements MockSpyApy {
5959
return spy;
6060
}
6161

62-
public getOptimizationReq() {
63-
const spy = jest.spyOn(sqlOptimization, 'GetOptimizationReq');
62+
public getOptimizationSQLDetail() {
63+
const spy = jest.spyOn(sqlOptimization, 'GetOptimizationSQLDetailV2');
6464
spy.mockImplementation(() =>
6565
createSpySuccessResponse({
6666
data: optimizationDetailMockData

packages/shared/lib/testUtil/mockModule/mockAntDesignPlots.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const Area = MockPlots;
1717
const Bar = MockPlots;
1818
const RingProgress = MockPlots;
1919
const Scatter = MockPlots;
20+
const Radar = MockPlots;
2021
const mockRegisterShape = jest.fn();
2122
const G2 = {
2223
registerShape: jest.fn()
@@ -138,6 +139,7 @@ export {
138139
Bar,
139140
RingProgress,
140141
Scatter,
142+
Radar,
141143
PieWithCustomRenderCalled,
142144
BarWithCustomRenderCalled,
143145
AreaWithCustomRenderCalled,

packages/sqle/src/page/VersionManagement/Detail/mockData/mockReactFlow.ts renamed to packages/shared/lib/testUtil/mockModule/mockReactFlow.ts

File renamed without changes.

packages/sqle/src/hooks/useInstance/index.test.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,4 +357,61 @@ describe('useInstance', () => {
357357
});
358358
expect(baseElementWithOptions).toMatchSnapshot();
359359
});
360+
361+
describe('getInstanceDbType', () => {
362+
test('should return correct database type when instance is found', async () => {
363+
const requestSpy = mockRequest();
364+
requestSpy.mockImplementation(() =>
365+
resolveThreeSecond([
366+
{ instance_name: 'mysql_instance', instance_type: 'mysql' },
367+
{ instance_name: 'oracle_instance', instance_type: 'oracle' },
368+
{ instance_name: 'postgres_instance', instance_type: 'postgresql' }
369+
])
370+
);
371+
const { result, waitForNextUpdate } = renderHook(() => useInstance());
372+
373+
act(() => {
374+
result.current.updateInstanceList({ project_name: projectName });
375+
});
376+
377+
jest.advanceTimersByTime(3000);
378+
await waitForNextUpdate();
379+
380+
expect(result.current.getInstanceDbType('mysql_instance')).toBe('mysql');
381+
382+
expect(result.current.getInstanceDbType('oracle_instance')).toBe(
383+
'oracle'
384+
);
385+
386+
expect(result.current.getInstanceDbType('postgres_instance')).toBe(
387+
'postgresql'
388+
);
389+
});
390+
391+
test('should return empty string when instance is not found', async () => {
392+
const requestSpy = mockRequest();
393+
requestSpy.mockImplementation(() =>
394+
resolveThreeSecond([
395+
{ instance_name: 'mysql_instance', instance_type: 'mysql' },
396+
{ instance_name: 'oracle_instance', instance_type: 'oracle' }
397+
])
398+
);
399+
const { result, waitForNextUpdate } = renderHook(() => useInstance());
400+
401+
act(() => {
402+
result.current.updateInstanceList({ project_name: projectName });
403+
});
404+
405+
jest.advanceTimersByTime(3000);
406+
await waitForNextUpdate();
407+
408+
expect(result.current.getInstanceDbType('non_existent_instance')).toBe(
409+
''
410+
);
411+
412+
expect(result.current.getInstanceDbType('')).toBe('');
413+
414+
expect(result.current.getInstanceDbType(undefined as any)).toBe('');
415+
});
416+
});
360417
});
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import { fireEvent, screen } from '@testing-library/react';
2+
import { useDispatch, useSelector } from 'react-redux';
3+
import SqlOptimizationResultDrawer from '../SqlOptimizationResultDrawer';
4+
import {
5+
getBySelector,
6+
superRender,
7+
mockUseCurrentProject,
8+
mockUseCurrentUser
9+
} from '@actiontech/shared/lib/testUtil';
10+
import { ModalName } from '../../../../data/ModalName';
11+
import {
12+
updateSqlAnalyzeModalStatus,
13+
updateResultDrawerData
14+
} from '../../../../store/sqlAnalyze';
15+
import useOptimizationResult from '../../../SqlOptimization/Result/hooks/useOptimizationResult';
16+
import { OptimizationSQLDetailStatusEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum';
17+
import { OptimizationResultStatus } from '../../../SqlOptimization/Result/index.type';
18+
import { mockReactFlow } from '@actiontech/shared/lib/testUtil/mockModule/mockReactFlow';
19+
import { optimizationDetailMockData } from '@actiontech/shared/lib/testUtil/mockApi/sqle/sqlOptimization/data';
20+
21+
jest.mock('react-redux', () => ({
22+
...jest.requireActual('react-redux'),
23+
useSelector: jest.fn(),
24+
useDispatch: jest.fn()
25+
}));
26+
27+
jest.mock('../../../SqlOptimization/Result/hooks/useOptimizationResult');
28+
29+
describe('SqlOptimizationResultDrawer', () => {
30+
const mockDispatch = jest.fn();
31+
const mockUseOptimizationResult =
32+
useOptimizationResult as jest.MockedFunction<typeof useOptimizationResult>;
33+
34+
const defaultOptimizationResult = {
35+
optimizationResultStatus: OptimizationResultStatus.RESOLVED,
36+
errorMessage: undefined,
37+
optimizationResult: optimizationDetailMockData,
38+
optimizationResultLoading: false,
39+
getOptimizationResult: jest.fn(),
40+
cancelOptimizationRequestPolling: jest.fn()
41+
};
42+
43+
beforeEach(() => {
44+
mockUseCurrentProject();
45+
mockUseCurrentUser();
46+
jest.useFakeTimers({ legacyFakeTimers: true });
47+
48+
(useDispatch as jest.Mock).mockImplementation(() => mockDispatch);
49+
(useSelector as jest.Mock).mockImplementation((e) =>
50+
e({
51+
sqlOptimization: {
52+
modalStatus: {},
53+
submitLoading: false,
54+
diffModal: {
55+
currentDiffData: null
56+
},
57+
tableStructureModal: {
58+
currentTableData: null
59+
},
60+
optimizationResultModal: {
61+
currentResultData: null
62+
},
63+
queryPlanFlowModal: {
64+
currentQueryPlanData: null
65+
},
66+
queryPlanDiffModal: {
67+
currentQueryPlanDiffData: null
68+
}
69+
},
70+
sqlAnalyze: {
71+
modalStatus: {
72+
[ModalName.Sql_Optimization_Result_Drawer]: true
73+
},
74+
resultDrawer: {
75+
currentResultDrawerData: {
76+
optimizationId: 'test-optimization-id'
77+
}
78+
}
79+
}
80+
})
81+
);
82+
mockUseOptimizationResult.mockReturnValue(defaultOptimizationResult);
83+
mockReactFlow();
84+
});
85+
86+
afterEach(() => {
87+
jest.useRealTimers();
88+
jest.clearAllMocks();
89+
jest.clearAllTimers();
90+
});
91+
92+
it('should render correctly when drawer is open with finished optimization', () => {
93+
const { baseElement } = superRender(<SqlOptimizationResultDrawer />);
94+
95+
expect(screen.getByText('SQL调优结果详情')).toBeInTheDocument();
96+
expect(baseElement).toMatchSnapshot();
97+
});
98+
99+
it('should render loading state when optimization is in progress', () => {
100+
mockUseOptimizationResult.mockReturnValue({
101+
...defaultOptimizationResult,
102+
optimizationResult: {
103+
status: OptimizationSQLDetailStatusEnum.optimizing
104+
}
105+
});
106+
107+
const { baseElement } = superRender(<SqlOptimizationResultDrawer />);
108+
109+
expect(
110+
screen.getByText('优化进行中,预计5-10分钟后完成。感谢您的耐心等待。')
111+
).toBeInTheDocument();
112+
expect(
113+
screen.getByText('也可进入 快捷诊断-SQL调优 页面追踪进度')
114+
).toBeInTheDocument();
115+
expect(baseElement).toMatchSnapshot();
116+
});
117+
118+
it('should render error state when optimization failed', () => {
119+
mockUseOptimizationResult.mockReturnValue({
120+
...defaultOptimizationResult,
121+
optimizationResult: {
122+
status: OptimizationSQLDetailStatusEnum.failed,
123+
status_detail: '优化失败的详细信息'
124+
}
125+
});
126+
127+
const { baseElement } = superRender(<SqlOptimizationResultDrawer />);
128+
129+
expect(screen.getByText('优化失败的详细信息')).toBeInTheDocument();
130+
expect(baseElement).toMatchSnapshot();
131+
});
132+
133+
it('should dispatch close actions when drawer is closed', () => {
134+
superRender(<SqlOptimizationResultDrawer />);
135+
136+
fireEvent.click(getBySelector('.closed-icon-custom'));
137+
138+
expect(mockDispatch).toHaveBeenCalledWith(
139+
updateSqlAnalyzeModalStatus({
140+
modalName: ModalName.Sql_Optimization_Result_Drawer,
141+
status: false
142+
})
143+
);
144+
145+
expect(mockDispatch).toHaveBeenCalledWith(
146+
updateResultDrawerData({
147+
resultDrawerData: null
148+
})
149+
);
150+
151+
expect(
152+
defaultOptimizationResult.cancelOptimizationRequestPolling
153+
).toHaveBeenCalled();
154+
});
155+
156+
it('should call getOptimizationResult when drawer opens with optimization id', () => {
157+
mockUseOptimizationResult.mockReturnValue({
158+
...defaultOptimizationResult,
159+
optimizationResult: undefined
160+
});
161+
162+
superRender(<SqlOptimizationResultDrawer />);
163+
164+
expect(
165+
defaultOptimizationResult.getOptimizationResult
166+
).toHaveBeenCalledWith('test-optimization-id');
167+
});
168+
169+
it('should not call getOptimizationResult when optimization is finished', () => {
170+
const getOptimizationResultSpy = jest.fn();
171+
mockUseOptimizationResult.mockReturnValue({
172+
...defaultOptimizationResult,
173+
getOptimizationResult: getOptimizationResultSpy,
174+
optimizationResult: {
175+
status: OptimizationSQLDetailStatusEnum.finish
176+
}
177+
});
178+
179+
superRender(<SqlOptimizationResultDrawer />);
180+
181+
expect(getOptimizationResultSpy).not.toHaveBeenCalled();
182+
});
183+
});

0 commit comments

Comments
 (0)