Skip to content

Commit 563d812

Browse files
authored
Merge pull request #722 from actiontech/fix/issue-670
[fix](AvailabilityZone): Availability zone switching and project linkage issues
2 parents f90bd2f + 5fbb8d3 commit 563d812

File tree

12 files changed

+420
-49
lines changed

12 files changed

+420
-49
lines changed

packages/base/src/hooks/useRecentlySelectedZone/index.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,20 +65,20 @@ const useRecentlySelectedZone = () => {
6565
(zone: IUidWithName) => {
6666
setAvailabilityZone(zone);
6767

68-
const currentReocrd = cloneDeep(recentlySelectedZoneRecord ?? []);
69-
if (currentReocrd.some((v) => v.uid === zone.uid)) {
70-
remove(currentReocrd, (v) => v.uid === zone.uid);
68+
const currentRecord = cloneDeep(recentlySelectedZoneRecord ?? []);
69+
if (currentRecord.some((v) => v.uid === zone.uid)) {
70+
remove(currentRecord, (v) => v.uid === zone.uid);
7171
}
7272

73-
currentReocrd.unshift(zone);
73+
currentRecord.unshift(zone);
7474

75-
if (currentReocrd.length > DEFAULT_MAX_SELECTED_ZONE_NUMBER) {
76-
currentReocrd.pop();
75+
if (currentRecord.length > DEFAULT_MAX_SELECTED_ZONE_NUMBER) {
76+
currentRecord.pop();
7777
}
7878

79-
setRecentlySelectedZoneRecord(currentReocrd);
79+
setRecentlySelectedZoneRecord(currentRecord);
8080

81-
setStorageRecentlySelectedZoneRecord(currentReocrd);
81+
setStorageRecentlySelectedZoneRecord(currentRecord);
8282
},
8383
[
8484
recentlySelectedZoneRecord,
@@ -92,15 +92,15 @@ const useRecentlySelectedZone = () => {
9292
// 如果当前选择的区域在已配置的区域中是不存在的,则从最近选择区域中移除并且删除当前选择的区域
9393
if (!zoneTips?.some((v) => v.uid === availabilityZone?.uid)) {
9494
setAvailabilityZone(undefined);
95-
const currentReocrd = cloneDeep(recentlySelectedZoneRecord ?? []);
96-
currentReocrd.forEach((i) => {
95+
const currentRecord = cloneDeep(recentlySelectedZoneRecord ?? []);
96+
currentRecord.forEach((i) => {
9797
if (i.uid === availabilityZone?.uid) {
98-
remove(currentReocrd, (v) => v.uid === i.uid);
98+
remove(currentRecord, (v) => v.uid === i.uid);
9999
}
100100
});
101-
setRecentlySelectedZoneRecord(currentReocrd);
101+
setRecentlySelectedZoneRecord(currentRecord);
102102

103-
setStorageRecentlySelectedZoneRecord(currentReocrd);
103+
setStorageRecentlySelectedZoneRecord(currentRecord);
104104
}
105105

106106
// 如果当前选择的区域在已配置的区域中存在,但是name不相同,则更新name
@@ -115,15 +115,15 @@ const useRecentlySelectedZone = () => {
115115
...availabilityZone,
116116
name: zoneTips.find((v) => v.uid === availabilityZone?.uid)?.name
117117
});
118-
const currentReocrd = cloneDeep(recentlySelectedZoneRecord ?? []);
119-
currentReocrd.forEach((i) => {
118+
const currentRecord = cloneDeep(recentlySelectedZoneRecord ?? []);
119+
currentRecord.forEach((i) => {
120120
if (i.uid === availabilityZone?.uid) {
121121
i.name = name;
122122
}
123123
});
124-
setRecentlySelectedZoneRecord(currentReocrd);
124+
setRecentlySelectedZoneRecord(currentRecord);
125125

126-
setStorageRecentlySelectedZoneRecord(currentReocrd);
126+
setStorageRecentlySelectedZoneRecord(currentRecord);
127127
}
128128
};
129129

packages/base/src/page/AvailabilityZone/AvailabilityZoneWrapper/__tests__/index.test.tsx

Lines changed: 136 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,36 @@
11
import { cleanup, screen, act, fireEvent } from '@testing-library/react';
22
import { superRender } from '@actiontech/shared/lib/testUtil/superRender';
33
import AvailabilityZoneWrapper from '..';
4-
import { useLocation, Outlet, useNavigate } from 'react-router-dom';
4+
import { useLocation, Outlet, useNavigate, useParams } from 'react-router-dom';
55
import { mockUseRecentlySelectedZone } from '../../../../testUtils/mockHooks/mockUseRecentlySelectedZone';
66
import { mockUseRecentlySelectedZoneData } from '../../../../testUtils/mockHooks/data';
7+
import { mockUseRecentlyOpenedProjects } from '../../../Nav/SideMenu/testUtils/mockUseRecentlyOpenedProjects';
8+
import { baseMockApi } from '@actiontech/shared/lib/testUtil';
79

810
jest.mock('react-router-dom', () => ({
911
...jest.requireActual('react-router-dom'),
1012
useLocation: jest.fn(),
1113
Outlet: jest.fn(),
12-
useNavigate: jest.fn()
14+
useNavigate: jest.fn(),
15+
useParams: jest.fn()
1316
}));
1417

1518
describe('base/AvailabilityZone/AvailabilityZoneWrapper', () => {
1619
const navigateSpy = jest.fn();
1720

21+
const getRecentlyProjectIdByUserInfoSpy = jest.fn();
22+
23+
let getCurrentUserSpy: jest.SpyInstance;
24+
const useParamsSpy: jest.Mock = useParams as jest.Mock;
25+
1826
const mockAvailabilityZoneOptions = [
1927
{ value: 'zone-123', label: 'Test Zone' },
2028
{ value: 'zone-456', label: 'Another Zone' }
2129
];
2230

2331
beforeEach(() => {
2432
jest.useFakeTimers();
33+
getCurrentUserSpy = baseMockApi.global.getCurrentUser();
2534

2635
(Outlet as jest.Mock).mockImplementation(() => <div>Outlet Content</div>);
2736

@@ -31,6 +40,11 @@ describe('base/AvailabilityZone/AvailabilityZoneWrapper', () => {
3140
pathname: '/test-path',
3241
search: '?test=true'
3342
}));
43+
useParamsSpy.mockReturnValue({ projectID: undefined });
44+
mockUseRecentlyOpenedProjects({
45+
getRecentlyProjectIdByUserInfo: getRecentlyProjectIdByUserInfoSpy
46+
});
47+
3448
mockUseRecentlySelectedZone();
3549
});
3650

@@ -101,12 +115,11 @@ describe('base/AvailabilityZone/AvailabilityZoneWrapper', () => {
101115

102116
fireEvent.click(screen.getByText('确 认'));
103117

118+
await act(async () => jest.advanceTimersByTime(3000));
104119
expect(updateRecentlySelectedZoneSpy).toHaveBeenCalledWith({
105120
uid: 'zone-123',
106121
name: 'Test Zone'
107122
});
108-
109-
expect(navigateSpy).toHaveBeenCalledWith('/test-path?test=true');
110123
});
111124

112125
it('should show modal when memorized zone not in available options', () => {
@@ -134,4 +147,123 @@ describe('base/AvailabilityZone/AvailabilityZoneWrapper', () => {
134147
expect(screen.getByText('Outlet Content')).toBeInTheDocument();
135148
expect(screen.queryByText('选择可用区')).not.toBeInTheDocument();
136149
});
150+
151+
describe('Project path replacement logic', () => {
152+
const updateRecentlySelectedZoneSpy = jest.fn();
153+
154+
beforeEach(() => {
155+
mockUseRecentlySelectedZone({
156+
...mockUseRecentlySelectedZoneData,
157+
updateRecentlySelectedZone: updateRecentlySelectedZoneSpy,
158+
availabilityZoneOptions: mockAvailabilityZoneOptions
159+
});
160+
});
161+
162+
it('should navigate to project path when memorized project exists and no default project in URL', async () => {
163+
getRecentlyProjectIdByUserInfoSpy.mockReturnValue('project-123');
164+
165+
(useLocation as jest.Mock).mockImplementation(() => ({
166+
pathname: '/sqle/project//dashboard',
167+
search: '?test=true'
168+
}));
169+
170+
superRender(<AvailabilityZoneWrapper />);
171+
172+
const selectElement = screen.getByRole('combobox');
173+
fireEvent.mouseDown(selectElement);
174+
175+
await act(async () => jest.advanceTimersByTime(0));
176+
177+
fireEvent.click(screen.getByText('Test Zone'));
178+
fireEvent.click(screen.getByText('确 认'));
179+
180+
await act(async () => jest.advanceTimersByTime(3000));
181+
182+
expect(navigateSpy).toHaveBeenCalledWith(
183+
'/sqle/project/project-123/dashboard?test=true',
184+
{ replace: true }
185+
);
186+
});
187+
188+
it('should navigate to project path when memorized project exists and default project in URL', async () => {
189+
getRecentlyProjectIdByUserInfoSpy.mockReturnValue('project-123');
190+
useParamsSpy.mockReturnValue({ projectID: '700300' });
191+
192+
(useLocation as jest.Mock).mockImplementation(() => ({
193+
pathname: '/sqle/project/700300/dashboard',
194+
search: '?test=true'
195+
}));
196+
197+
superRender(<AvailabilityZoneWrapper />);
198+
199+
const selectElement = screen.getByRole('combobox');
200+
fireEvent.mouseDown(selectElement);
201+
202+
await act(async () => jest.advanceTimersByTime(0));
203+
204+
fireEvent.click(screen.getByText('Test Zone'));
205+
fireEvent.click(screen.getByText('确 认'));
206+
207+
await act(async () => jest.advanceTimersByTime(3000));
208+
209+
expect(navigateSpy).toHaveBeenCalledWith(
210+
'/sqle/project/project-123/dashboard?test=true',
211+
{ replace: true }
212+
);
213+
});
214+
215+
it('should replace project id when project id in url but project id not in bind projects', async () => {
216+
getRecentlyProjectIdByUserInfoSpy.mockReturnValue(undefined);
217+
useParamsSpy.mockReturnValue({ projectID: '123456' });
218+
219+
(useLocation as jest.Mock).mockImplementation(() => ({
220+
pathname: '/sqle/project/123456/dashboard',
221+
search: '?test=true'
222+
}));
223+
224+
superRender(<AvailabilityZoneWrapper />);
225+
226+
const selectElement = screen.getByRole('combobox');
227+
fireEvent.mouseDown(selectElement);
228+
229+
await act(async () => jest.advanceTimersByTime(0));
230+
231+
fireEvent.click(screen.getByText('Test Zone'));
232+
fireEvent.click(screen.getByText('确 认'));
233+
234+
await act(async () => jest.advanceTimersByTime(3000));
235+
expect(getCurrentUserSpy).toHaveBeenCalledTimes(1);
236+
237+
expect(navigateSpy).toHaveBeenCalledWith(
238+
'/sqle/project//dashboard?test=true',
239+
{ replace: true }
240+
);
241+
});
242+
243+
it('should handle path without sqle prefix correctly', async () => {
244+
getRecentlyProjectIdByUserInfoSpy.mockReturnValue('project-123');
245+
246+
(useLocation as jest.Mock).mockImplementation(() => ({
247+
pathname: '/project//dashboard',
248+
search: '?test=true'
249+
}));
250+
251+
superRender(<AvailabilityZoneWrapper />);
252+
253+
const selectElement = screen.getByRole('combobox');
254+
fireEvent.mouseDown(selectElement);
255+
256+
await act(async () => jest.advanceTimersByTime(0));
257+
258+
fireEvent.click(screen.getByText('Test Zone'));
259+
fireEvent.click(screen.getByText('确 认'));
260+
261+
await act(async () => jest.advanceTimersByTime(3000));
262+
263+
expect(navigateSpy).toHaveBeenCalledWith(
264+
'/project/project-123/dashboard?test=true',
265+
{ replace: true }
266+
);
267+
});
268+
});
137269
});

0 commit comments

Comments
 (0)