@nocobase/client-v2 2.2.0-beta.8 → 2.2.0-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/BaseApplication.d.ts +2 -0
- package/es/RouteRepository.d.ts +8 -0
- package/es/RouterManager.d.ts +15 -0
- package/es/authRedirect.d.ts +1 -0
- package/es/entry-actions/EntryActionManager.d.ts +24 -0
- package/es/entry-actions/index.d.ts +9 -0
- package/es/flow/admin-shell/BaseLayoutModel.d.ts +6 -0
- package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +7 -0
- package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +2 -1
- package/es/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.d.ts +24 -0
- package/es/flow/admin-shell/admin-layout/index.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/useApplications.d.ts +7 -2
- package/es/flow/models/base/ActionModelCore.d.ts +2 -0
- package/es/flow/routeTransientInputArgs.d.ts +14 -0
- package/es/index.d.ts +2 -0
- package/es/index.mjs +212 -126
- package/es/utils/markdownSanitize.d.ts +11 -0
- package/lib/index.js +198 -112
- package/package.json +7 -7
- package/src/BaseApplication.tsx +2 -0
- package/src/RouteRepository.ts +25 -0
- package/src/RouterManager.tsx +142 -1
- package/src/__tests__/RouteRepository.test.ts +23 -0
- package/src/__tests__/RouterManager.test.ts +125 -0
- package/src/__tests__/authRedirect.test.ts +17 -0
- package/src/authRedirect.ts +38 -0
- package/src/entry-actions/EntryActionManager.ts +76 -0
- package/src/entry-actions/index.ts +10 -0
- package/src/flow/FlowPage.tsx +29 -2
- package/src/flow/__tests__/FlowPage.test.tsx +152 -25
- package/src/flow/__tests__/FlowRoute.test.tsx +547 -2
- package/src/flow/actions/__tests__/dataScopeFilter.test.ts +62 -0
- package/src/flow/actions/__tests__/openView.defineProps.route.test.tsx +80 -20
- package/src/flow/actions/dataScopeFilter.ts +10 -1
- package/src/flow/actions/dateTimeFormat.tsx +2 -2
- package/src/flow/actions/openView.tsx +21 -1
- package/src/flow/admin-shell/BaseLayoutModel.tsx +124 -0
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +184 -42
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +1016 -119
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +41 -4
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +177 -1
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +20 -0
- package/src/flow/admin-shell/admin-layout/AppListRender.tsx +13 -2
- package/src/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.tsx +289 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +436 -2
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +48 -0
- package/src/flow/admin-shell/admin-layout/index.ts +1 -0
- package/src/flow/admin-shell/admin-layout/useApplications.tsx +81 -12
- package/src/flow/common/Markdown/Display.tsx +14 -3
- package/src/flow/common/Markdown/Edit.tsx +19 -7
- package/src/flow/components/FlowRoute.tsx +128 -16
- package/src/flow/internal/components/Markdown/util.ts +2 -1
- package/src/flow/models/base/ActionModel.tsx +10 -8
- package/src/flow/models/base/ActionModelCore.tsx +5 -0
- package/src/flow/models/blocks/table/TableColumnModel.tsx +6 -2
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +51 -0
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +45 -13
- package/src/flow/models/fields/TextareaFieldModel.tsx +42 -19
- package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +32 -1
- package/src/flow/models/topbar/TopbarActionModel.tsx +78 -3
- package/src/flow/routeTransientInputArgs.ts +27 -0
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +42 -0
- package/src/index.ts +2 -0
- package/src/nocobase-buildin-plugin/index.tsx +7 -1
- package/src/utils/markdownSanitize.ts +88 -0
|
@@ -7,14 +7,16 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { FlowContext, FlowEngine } from '@nocobase/flow-engine';
|
|
10
|
+
import { FlowContext, FlowEngine, type FlowModel } from '@nocobase/flow-engine';
|
|
11
|
+
import type React from 'react';
|
|
11
12
|
import { describe, expect, it, vi, beforeEach } from 'vitest';
|
|
12
13
|
import { getViewDiffAndUpdateHidden } from '../../getViewDiffAndUpdateHidden';
|
|
13
14
|
import { getOpenViewStepParams } from '../../flows/openViewFlow';
|
|
14
|
-
import { resolveViewParamsToViewList, updateViewListHidden } from '../../resolveViewParamsToViewList';
|
|
15
|
+
import { resolveViewParamsToViewList, updateViewListHidden, type ViewItem } from '../../resolveViewParamsToViewList';
|
|
15
16
|
import { AdminLayoutRouteCoordinator } from '../AdminLayoutRouteCoordinator';
|
|
16
17
|
import { BaseLayoutRouteCoordinator, toViewStack } from '../BaseLayoutRouteCoordinator';
|
|
17
18
|
import { RouteModel } from '../../models/base/RouteModel';
|
|
19
|
+
import { ROUTE_TRANSIENT_INPUT_ARGS_KEY } from '../../routeTransientInputArgs';
|
|
18
20
|
|
|
19
21
|
vi.mock('../../resolveViewParamsToViewList', () => ({
|
|
20
22
|
resolveViewParamsToViewList: vi.fn(),
|
|
@@ -27,9 +29,9 @@ vi.mock('../../getViewDiffAndUpdateHidden', () => ({
|
|
|
27
29
|
}));
|
|
28
30
|
|
|
29
31
|
vi.mock('../../flows/openViewFlow', async (importOriginal) => {
|
|
30
|
-
const actual = await importOriginal();
|
|
32
|
+
const actual = await importOriginal<typeof import('../../flows/openViewFlow')>();
|
|
31
33
|
return {
|
|
32
|
-
...
|
|
34
|
+
...actual,
|
|
33
35
|
getOpenViewStepParams: vi.fn(),
|
|
34
36
|
};
|
|
35
37
|
});
|
|
@@ -39,7 +41,48 @@ const mockGetViewDiffAndUpdateHidden = vi.mocked(getViewDiffAndUpdateHidden);
|
|
|
39
41
|
const mockGetOpenViewStepParams = vi.mocked(getOpenViewStepParams);
|
|
40
42
|
const mockUpdateViewListHidden = vi.mocked(updateViewListHidden);
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
type RouteOpenPayload = {
|
|
45
|
+
target?: HTMLElement | null;
|
|
46
|
+
destroyRef: React.RefObject<(result?: unknown, force?: boolean) => void>;
|
|
47
|
+
updateRef: React.RefObject<(value: unknown) => void>;
|
|
48
|
+
activateRef: React.RefObject<(forceRefresh?: boolean) => void>;
|
|
49
|
+
deactivateRef: React.RefObject<() => void>;
|
|
50
|
+
onOpen: () => void;
|
|
51
|
+
pageActive: boolean;
|
|
52
|
+
activationControlledByLayout: boolean;
|
|
53
|
+
hidden: { value: boolean };
|
|
54
|
+
triggerByRouter: boolean;
|
|
55
|
+
[key: string]: unknown;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
type DispatchEventMock = ReturnType<typeof createDispatchEventMock>;
|
|
59
|
+
|
|
60
|
+
const createDispatchEventMock = (
|
|
61
|
+
implementation?: (eventName: string, payload: RouteOpenPayload) => Promise<unknown[] | void>,
|
|
62
|
+
) => vi.fn((eventName: string, payload: RouteOpenPayload) => implementation?.(eventName, payload) ?? Promise.resolve());
|
|
63
|
+
|
|
64
|
+
const createViewModel = (uid: string, dispatchEvent: DispatchEventMock) =>
|
|
65
|
+
({
|
|
66
|
+
uid,
|
|
67
|
+
dispatchEvent,
|
|
68
|
+
}) as unknown as FlowModel;
|
|
69
|
+
|
|
70
|
+
const createViewItem = (
|
|
71
|
+
uid: string,
|
|
72
|
+
dispatchEvent: DispatchEventMock,
|
|
73
|
+
index = 0,
|
|
74
|
+
params: ViewItem['params'] = { viewUid: uid },
|
|
75
|
+
): ViewItem => ({
|
|
76
|
+
params,
|
|
77
|
+
modelUid: uid,
|
|
78
|
+
model: createViewModel(uid, dispatchEvent),
|
|
79
|
+
hidden: { value: false },
|
|
80
|
+
index,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const nextTick = () => new Promise((resolve) => setTimeout(resolve, 0));
|
|
84
|
+
|
|
85
|
+
function setupRouteReplay(viewParams: Record<string, unknown>) {
|
|
43
86
|
const engine = new FlowEngine();
|
|
44
87
|
engine.registerModels({ RouteModel });
|
|
45
88
|
engine.context.defineProperty('route', {
|
|
@@ -54,87 +97,832 @@ function setupRouteReplay(viewParams: Record<string, any>) {
|
|
|
54
97
|
},
|
|
55
98
|
});
|
|
56
99
|
|
|
57
|
-
const dispatchEvent =
|
|
58
|
-
const viewItem = {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
};
|
|
100
|
+
const dispatchEvent = createDispatchEventMock();
|
|
101
|
+
const viewItem = createViewItem('popup', dispatchEvent, 0, {
|
|
102
|
+
viewUid: 'popup',
|
|
103
|
+
filterByTk: 'member',
|
|
104
|
+
...viewParams,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
mockResolveViewParamsToViewList.mockReturnValue([viewItem]);
|
|
108
|
+
mockGetViewDiffAndUpdateHidden.mockReturnValue({
|
|
109
|
+
viewsToClose: [],
|
|
110
|
+
viewsToOpen: [viewItem],
|
|
111
|
+
});
|
|
112
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
113
|
+
collectionName: 'roles',
|
|
114
|
+
associationName: 'users.roles',
|
|
115
|
+
dataSourceKey: 'main',
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const coordinator = new AdminLayoutRouteCoordinator(engine);
|
|
119
|
+
coordinator.registerPage('test-route', {
|
|
120
|
+
active: true,
|
|
121
|
+
layoutContentElement: document.createElement('div'),
|
|
122
|
+
});
|
|
123
|
+
coordinator.syncRoute({
|
|
124
|
+
params: { name: 'test-route' },
|
|
125
|
+
pathname: '/admin/popup/filterbytk/member',
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return { dispatchEvent };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
describe('AdminLayoutRouteCoordinator', () => {
|
|
132
|
+
beforeEach(() => {
|
|
133
|
+
vi.clearAllMocks();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('drops configured associationName during route replay when sourceId is absent', () => {
|
|
137
|
+
const { dispatchEvent } = setupRouteReplay({});
|
|
138
|
+
|
|
139
|
+
expect(dispatchEvent.mock.calls[0][1]).toMatchObject({
|
|
140
|
+
collectionName: 'roles',
|
|
141
|
+
associationName: null,
|
|
142
|
+
dataSourceKey: 'main',
|
|
143
|
+
filterByTk: 'member',
|
|
144
|
+
triggerByRouter: true,
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('keeps configured associationName during route replay when sourceId is present', () => {
|
|
149
|
+
const { dispatchEvent } = setupRouteReplay({ sourceId: '1' });
|
|
150
|
+
|
|
151
|
+
expect(dispatchEvent.mock.calls[0][1]).toMatchObject({
|
|
152
|
+
collectionName: 'roles',
|
|
153
|
+
associationName: 'users.roles',
|
|
154
|
+
dataSourceKey: 'main',
|
|
155
|
+
filterByTk: 'member',
|
|
156
|
+
sourceId: '1',
|
|
157
|
+
triggerByRouter: true,
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('passes RunJS openView route state as runtime mode and size during route replay', () => {
|
|
162
|
+
const { dispatchEvent } = setupRouteReplay({
|
|
163
|
+
openViewRouteState: { mode: 'dialog', size: 'large' },
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
expect(dispatchEvent.mock.calls[0][1]).toMatchObject({
|
|
167
|
+
mode: 'dialog',
|
|
168
|
+
size: 'large',
|
|
169
|
+
openViewRouteState: { mode: 'dialog', size: 'large' },
|
|
170
|
+
triggerByRouter: true,
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('uses layout content element before route page placeholder as view target', () => {
|
|
175
|
+
const engine = new FlowEngine();
|
|
176
|
+
engine.registerModels({ RouteModel });
|
|
177
|
+
engine.context.defineProperty('route', {
|
|
178
|
+
value: {},
|
|
179
|
+
});
|
|
180
|
+
engine.context.defineProperty('routeRepository', {
|
|
181
|
+
value: {
|
|
182
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const layoutContentElement = document.createElement('div');
|
|
187
|
+
const routePageElement = document.createElement('div');
|
|
188
|
+
const dispatchEvent = createDispatchEventMock();
|
|
189
|
+
const viewItem = createViewItem('test-route', dispatchEvent);
|
|
190
|
+
mockResolveViewParamsToViewList.mockReturnValue([viewItem]);
|
|
191
|
+
mockGetViewDiffAndUpdateHidden.mockReturnValue({
|
|
192
|
+
viewsToClose: [],
|
|
193
|
+
viewsToOpen: [viewItem],
|
|
194
|
+
});
|
|
195
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
196
|
+
collectionName: '',
|
|
197
|
+
dataSourceKey: '',
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
201
|
+
coordinator.setLayoutContentElement(layoutContentElement);
|
|
202
|
+
coordinator.registerPage('test-route', {
|
|
203
|
+
active: true,
|
|
204
|
+
layoutContentElement: routePageElement,
|
|
205
|
+
});
|
|
206
|
+
coordinator.syncRoute({
|
|
207
|
+
pageUid: 'test-route',
|
|
208
|
+
pathname: '/admin/test-route',
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
expect(dispatchEvent.mock.calls[0][1].target).toBe(layoutContentElement);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('passes transient route state input args to the opened view', () => {
|
|
215
|
+
const engine = new FlowEngine();
|
|
216
|
+
engine.registerModels({ RouteModel });
|
|
217
|
+
engine.context.defineProperty('routeRepository', {
|
|
218
|
+
value: {
|
|
219
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const dispatchEvent = createDispatchEventMock();
|
|
224
|
+
const viewItem = createViewItem('test-route', dispatchEvent);
|
|
225
|
+
mockResolveViewParamsToViewList.mockReturnValue([viewItem]);
|
|
226
|
+
mockGetViewDiffAndUpdateHidden.mockReturnValue({
|
|
227
|
+
viewsToClose: [],
|
|
228
|
+
viewsToOpen: [viewItem],
|
|
229
|
+
});
|
|
230
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
231
|
+
collectionName: '',
|
|
232
|
+
dataSourceKey: '',
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
236
|
+
coordinator.registerPage('test-route', {
|
|
237
|
+
active: true,
|
|
238
|
+
layoutContentElement: document.createElement('div'),
|
|
239
|
+
});
|
|
240
|
+
coordinator.syncRoute({
|
|
241
|
+
pageUid: 'test-route',
|
|
242
|
+
pathname: '/admin/test-route',
|
|
243
|
+
state: {
|
|
244
|
+
usr: {
|
|
245
|
+
[ROUTE_TRANSIENT_INPUT_ARGS_KEY]: {
|
|
246
|
+
'test-route': {
|
|
247
|
+
formData: {
|
|
248
|
+
start: '2026-06-24 08:00:00',
|
|
249
|
+
end: '2026-06-24 09:00:00',
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
expect(dispatchEvent.mock.calls[0][1]).toMatchObject({
|
|
258
|
+
formData: {
|
|
259
|
+
start: '2026-06-24 08:00:00',
|
|
260
|
+
end: '2026-06-24 09:00:00',
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('keeps transient route state input args during initial deep-link replay', async () => {
|
|
266
|
+
const engine = new FlowEngine();
|
|
267
|
+
engine.registerModels({ RouteModel });
|
|
268
|
+
const navigate = vi.fn();
|
|
269
|
+
engine.context.defineProperty('router', {
|
|
270
|
+
value: {
|
|
271
|
+
navigate,
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
engine.context.defineProperty('routeRepository', {
|
|
275
|
+
value: {
|
|
276
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
const rootDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
281
|
+
payload.onOpen?.();
|
|
282
|
+
return Promise.resolve();
|
|
283
|
+
});
|
|
284
|
+
const popupDispatchEvent = createDispatchEventMock();
|
|
285
|
+
const rootViewItem = createViewItem('test-route', rootDispatchEvent);
|
|
286
|
+
const popupViewItem = createViewItem('popup', popupDispatchEvent, 1);
|
|
287
|
+
|
|
288
|
+
mockResolveViewParamsToViewList.mockReturnValue([rootViewItem, popupViewItem]);
|
|
289
|
+
mockGetViewDiffAndUpdateHidden.mockReturnValue({
|
|
290
|
+
viewsToClose: [],
|
|
291
|
+
viewsToOpen: [rootViewItem, popupViewItem],
|
|
292
|
+
});
|
|
293
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
294
|
+
collectionName: '',
|
|
295
|
+
dataSourceKey: '',
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const routeState = {
|
|
299
|
+
[ROUTE_TRANSIENT_INPUT_ARGS_KEY]: {
|
|
300
|
+
popup: {
|
|
301
|
+
formData: {
|
|
302
|
+
start: '2026-06-24',
|
|
303
|
+
end: '2026-06-25',
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
309
|
+
coordinator.registerPage('test-route', {
|
|
310
|
+
active: true,
|
|
311
|
+
layoutContentElement: document.createElement('div'),
|
|
312
|
+
});
|
|
313
|
+
coordinator.syncRoute({
|
|
314
|
+
pageUid: 'test-route',
|
|
315
|
+
pathname: '/admin/test-route/view/popup',
|
|
316
|
+
state: routeState,
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
expect(navigate).toHaveBeenCalledWith('/admin/test-route', { replace: true, state: routeState });
|
|
320
|
+
expect(navigate).toHaveBeenCalledWith('/admin/test-route/view/popup', { state: routeState });
|
|
321
|
+
expect(popupDispatchEvent).not.toHaveBeenCalled();
|
|
322
|
+
|
|
323
|
+
await Promise.resolve();
|
|
324
|
+
|
|
325
|
+
expect(popupDispatchEvent.mock.calls[0][1]).toMatchObject({
|
|
326
|
+
formData: {
|
|
327
|
+
start: '2026-06-24',
|
|
328
|
+
end: '2026-06-25',
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('replays the active route view when the layout content element changes', () => {
|
|
334
|
+
const engine = new FlowEngine();
|
|
335
|
+
engine.registerModels({ RouteModel });
|
|
336
|
+
engine.context.defineProperty('route', {
|
|
337
|
+
value: {},
|
|
338
|
+
});
|
|
339
|
+
engine.context.defineProperty('routeRepository', {
|
|
340
|
+
value: {
|
|
341
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
const firstDestroy = vi.fn();
|
|
346
|
+
const dispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
347
|
+
if (dispatchEvent.mock.calls.length === 1) {
|
|
348
|
+
payload.destroyRef.current = firstDestroy;
|
|
349
|
+
}
|
|
350
|
+
return Promise.resolve();
|
|
351
|
+
});
|
|
352
|
+
const viewItem = createViewItem('test-route', dispatchEvent);
|
|
353
|
+
mockResolveViewParamsToViewList.mockReturnValue([viewItem]);
|
|
354
|
+
mockGetViewDiffAndUpdateHidden.mockReturnValue({
|
|
355
|
+
viewsToClose: [],
|
|
356
|
+
viewsToOpen: [viewItem],
|
|
357
|
+
});
|
|
358
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
359
|
+
collectionName: '',
|
|
360
|
+
dataSourceKey: '',
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
const firstLayoutContentElement = document.createElement('div');
|
|
364
|
+
const secondLayoutContentElement = document.createElement('div');
|
|
365
|
+
const routePageElement = document.createElement('div');
|
|
366
|
+
|
|
367
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
368
|
+
coordinator.setLayoutContentElement(firstLayoutContentElement);
|
|
369
|
+
const routeModel = coordinator.registerPage('test-route', {
|
|
370
|
+
active: true,
|
|
371
|
+
layoutContentElement: routePageElement,
|
|
372
|
+
});
|
|
373
|
+
coordinator.syncRoute({
|
|
374
|
+
pageUid: 'test-route',
|
|
375
|
+
pathname: '/admin/test-route',
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
expect(dispatchEvent).toHaveBeenCalledTimes(1);
|
|
379
|
+
expect(dispatchEvent.mock.calls[0][1].target).toBe(firstLayoutContentElement);
|
|
380
|
+
|
|
381
|
+
coordinator.setLayoutContentElement(null);
|
|
382
|
+
expect(dispatchEvent).toHaveBeenCalledTimes(1);
|
|
383
|
+
|
|
384
|
+
coordinator.setLayoutContentElement(secondLayoutContentElement);
|
|
385
|
+
|
|
386
|
+
expect(firstDestroy).toHaveBeenCalledTimes(1);
|
|
387
|
+
expect(dispatchEvent).toHaveBeenCalledTimes(2);
|
|
388
|
+
expect(dispatchEvent.mock.calls[1][1].target).toBe(secondLayoutContentElement);
|
|
389
|
+
expect(engine.getModel('test-route')).toBe(routeModel);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it('reopens an inactive cached route view on the new layout content element when it becomes active again', () => {
|
|
393
|
+
const engine = new FlowEngine();
|
|
394
|
+
engine.registerModels({ RouteModel });
|
|
395
|
+
engine.context.defineProperty('route', {
|
|
396
|
+
value: {},
|
|
397
|
+
});
|
|
398
|
+
engine.context.defineProperty('routeRepository', {
|
|
399
|
+
value: {
|
|
400
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const dispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
405
|
+
payload.destroyRef.current = vi.fn();
|
|
406
|
+
payload.activateRef.current = vi.fn();
|
|
407
|
+
payload.deactivateRef.current = vi.fn();
|
|
408
|
+
return Promise.resolve();
|
|
409
|
+
});
|
|
410
|
+
const viewItem = createViewItem('test-route', dispatchEvent);
|
|
411
|
+
mockResolveViewParamsToViewList.mockReturnValue([viewItem]);
|
|
412
|
+
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
413
|
+
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
414
|
+
viewsToOpen: currentViewList.filter((currentViewItem) => !prevViewList.includes(currentViewItem)),
|
|
415
|
+
}));
|
|
416
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
417
|
+
collectionName: '',
|
|
418
|
+
dataSourceKey: '',
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
const firstLayoutContentElement = document.createElement('div');
|
|
422
|
+
const secondLayoutContentElement = document.createElement('div');
|
|
423
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
424
|
+
coordinator.setLayoutContentElement(firstLayoutContentElement);
|
|
425
|
+
coordinator.registerPage('test-route', {
|
|
426
|
+
active: true,
|
|
427
|
+
layoutContentElement: document.createElement('div'),
|
|
428
|
+
});
|
|
429
|
+
coordinator.syncRoute({
|
|
430
|
+
pageUid: 'test-route',
|
|
431
|
+
pathname: '/admin/test-route',
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
coordinator.syncRoute({
|
|
435
|
+
pageUid: 'other-route',
|
|
436
|
+
pathname: '/admin/other-route',
|
|
437
|
+
});
|
|
438
|
+
coordinator.setLayoutContentElement(secondLayoutContentElement);
|
|
439
|
+
coordinator.syncRoute({
|
|
440
|
+
pageUid: 'test-route',
|
|
441
|
+
pathname: '/admin/test-route',
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
expect(dispatchEvent).toHaveBeenCalledTimes(2);
|
|
445
|
+
expect(dispatchEvent.mock.calls[1][1].target).toBe(secondLayoutContentElement);
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it('ignores stale view onOpen callbacks after the layout content element changes', () => {
|
|
449
|
+
const engine = new FlowEngine();
|
|
450
|
+
engine.registerModels({ RouteModel });
|
|
451
|
+
engine.context.defineProperty('route', {
|
|
452
|
+
value: {},
|
|
453
|
+
});
|
|
454
|
+
engine.context.defineProperty('routeRepository', {
|
|
455
|
+
value: {
|
|
456
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
457
|
+
},
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
const rootDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
461
|
+
payload.destroyRef.current = vi.fn();
|
|
462
|
+
return Promise.resolve();
|
|
463
|
+
});
|
|
464
|
+
let stalePopupOnOpen: (() => void) | undefined;
|
|
465
|
+
const popupDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
466
|
+
stalePopupOnOpen = payload.onOpen;
|
|
467
|
+
payload.destroyRef.current = vi.fn();
|
|
468
|
+
return Promise.resolve();
|
|
469
|
+
});
|
|
470
|
+
const detailDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
471
|
+
payload.destroyRef.current = vi.fn();
|
|
472
|
+
return Promise.resolve();
|
|
473
|
+
});
|
|
474
|
+
const rootViewItem = createViewItem('test-route', rootDispatchEvent);
|
|
475
|
+
const popupViewItem = createViewItem('popup', popupDispatchEvent, 1);
|
|
476
|
+
const detailViewItem = createViewItem('detail', detailDispatchEvent, 2);
|
|
477
|
+
let resolvedViewList: ViewItem[] = [rootViewItem];
|
|
478
|
+
mockResolveViewParamsToViewList.mockImplementation(() => resolvedViewList);
|
|
479
|
+
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
480
|
+
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
481
|
+
viewsToOpen: currentViewList.filter((currentViewItem) => !prevViewList.includes(currentViewItem)),
|
|
482
|
+
}));
|
|
483
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
484
|
+
collectionName: '',
|
|
485
|
+
dataSourceKey: '',
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
489
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
490
|
+
coordinator.registerPage('test-route', {
|
|
491
|
+
active: true,
|
|
492
|
+
layoutContentElement: document.createElement('div'),
|
|
493
|
+
});
|
|
494
|
+
coordinator.syncRoute({
|
|
495
|
+
pageUid: 'test-route',
|
|
496
|
+
pathname: '/admin/test-route',
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
resolvedViewList = [rootViewItem, popupViewItem, detailViewItem];
|
|
500
|
+
coordinator.syncRoute({
|
|
501
|
+
pageUid: 'test-route',
|
|
502
|
+
pathname: '/admin/test-route',
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
expect(popupDispatchEvent).toHaveBeenCalledTimes(1);
|
|
506
|
+
expect(detailDispatchEvent).not.toHaveBeenCalled();
|
|
507
|
+
expect(stalePopupOnOpen).toBeDefined();
|
|
508
|
+
|
|
509
|
+
resolvedViewList = [rootViewItem];
|
|
510
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
511
|
+
stalePopupOnOpen?.();
|
|
512
|
+
|
|
513
|
+
expect(detailDispatchEvent).not.toHaveBeenCalled();
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
it('ignores stale async model loads after the layout content element changes', async () => {
|
|
517
|
+
const engine = new FlowEngine();
|
|
518
|
+
engine.registerModels({ RouteModel });
|
|
519
|
+
engine.context.defineProperty('route', {
|
|
520
|
+
value: {},
|
|
521
|
+
});
|
|
522
|
+
engine.context.defineProperty('routeRepository', {
|
|
523
|
+
value: {
|
|
524
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
525
|
+
},
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
const rootDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
529
|
+
payload.destroyRef.current = vi.fn();
|
|
530
|
+
return Promise.resolve();
|
|
531
|
+
});
|
|
532
|
+
const popupDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
533
|
+
payload.destroyRef.current = vi.fn();
|
|
534
|
+
return Promise.resolve();
|
|
535
|
+
});
|
|
536
|
+
const rootViewItem = createViewItem('test-route', rootDispatchEvent);
|
|
537
|
+
const popupViewItem: ViewItem = {
|
|
538
|
+
params: { viewUid: 'popup' },
|
|
539
|
+
modelUid: 'popup',
|
|
540
|
+
model: undefined,
|
|
541
|
+
hidden: { value: false },
|
|
542
|
+
index: 1,
|
|
543
|
+
};
|
|
544
|
+
let resolvePopupModel: (model: FlowModel) => void = () => {};
|
|
545
|
+
vi.spyOn(engine, 'loadModel').mockImplementation(
|
|
546
|
+
() =>
|
|
547
|
+
new Promise((resolve) => {
|
|
548
|
+
resolvePopupModel = resolve;
|
|
549
|
+
}),
|
|
550
|
+
);
|
|
551
|
+
let resolvedViewList: ViewItem[] = [rootViewItem];
|
|
552
|
+
mockResolveViewParamsToViewList.mockImplementation(() => resolvedViewList);
|
|
553
|
+
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
554
|
+
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
555
|
+
viewsToOpen: currentViewList.filter((currentViewItem) => !prevViewList.includes(currentViewItem)),
|
|
556
|
+
}));
|
|
557
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
558
|
+
collectionName: '',
|
|
559
|
+
dataSourceKey: '',
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
563
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
564
|
+
coordinator.registerPage('test-route', {
|
|
565
|
+
active: true,
|
|
566
|
+
layoutContentElement: document.createElement('div'),
|
|
567
|
+
});
|
|
568
|
+
coordinator.syncRoute({
|
|
569
|
+
pageUid: 'test-route',
|
|
570
|
+
pathname: '/admin/test-route',
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
resolvedViewList = [rootViewItem, popupViewItem];
|
|
574
|
+
coordinator.syncRoute({
|
|
575
|
+
pageUid: 'test-route',
|
|
576
|
+
pathname: '/admin/test-route',
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
resolvedViewList = [rootViewItem];
|
|
580
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
581
|
+
resolvePopupModel(createViewModel('popup', popupDispatchEvent));
|
|
582
|
+
await nextTick();
|
|
583
|
+
|
|
584
|
+
expect(popupDispatchEvent.mock.calls.length).toBe(0);
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it('ignores stale async view opens after the pathname changes', async () => {
|
|
588
|
+
const engine = new FlowEngine();
|
|
589
|
+
engine.registerModels({ RouteModel });
|
|
590
|
+
engine.context.defineProperty('route', {
|
|
591
|
+
value: {},
|
|
592
|
+
});
|
|
593
|
+
engine.context.defineProperty('routeRepository', {
|
|
594
|
+
value: {
|
|
595
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
596
|
+
},
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
const rootDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
600
|
+
payload.destroyRef.current = vi.fn();
|
|
601
|
+
return Promise.resolve();
|
|
602
|
+
});
|
|
603
|
+
const popupDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
604
|
+
payload.destroyRef.current = vi.fn();
|
|
605
|
+
return Promise.resolve();
|
|
606
|
+
});
|
|
607
|
+
const rootViewItem = createViewItem('test-route', rootDispatchEvent);
|
|
608
|
+
const popupViewItem: ViewItem = {
|
|
609
|
+
params: { viewUid: 'popup' },
|
|
610
|
+
modelUid: 'popup',
|
|
611
|
+
model: undefined,
|
|
612
|
+
hidden: { value: false },
|
|
613
|
+
index: 1,
|
|
614
|
+
};
|
|
615
|
+
const resolvePopupModels: Array<(model: FlowModel) => void> = [];
|
|
616
|
+
vi.spyOn(engine, 'loadModel').mockImplementation(
|
|
617
|
+
() =>
|
|
618
|
+
new Promise((resolve) => {
|
|
619
|
+
resolvePopupModels.push(resolve);
|
|
620
|
+
}),
|
|
621
|
+
);
|
|
622
|
+
let resolvedViewList: ViewItem[] = [rootViewItem];
|
|
623
|
+
mockResolveViewParamsToViewList.mockImplementation(() => resolvedViewList);
|
|
624
|
+
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
625
|
+
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
626
|
+
viewsToOpen: currentViewList.filter((currentViewItem) => !prevViewList.includes(currentViewItem)),
|
|
627
|
+
}));
|
|
628
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
629
|
+
collectionName: '',
|
|
630
|
+
dataSourceKey: '',
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
634
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
635
|
+
coordinator.registerPage('test-route', {
|
|
636
|
+
active: true,
|
|
637
|
+
layoutContentElement: document.createElement('div'),
|
|
638
|
+
});
|
|
639
|
+
coordinator.syncRoute({
|
|
640
|
+
pageUid: 'test-route',
|
|
641
|
+
pathname: '/admin/test-route',
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
resolvedViewList = [rootViewItem, popupViewItem];
|
|
645
|
+
coordinator.syncRoute({
|
|
646
|
+
pageUid: 'test-route',
|
|
647
|
+
pathname: '/admin/test-route/view/popup',
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
resolvedViewList = [rootViewItem];
|
|
651
|
+
coordinator.syncRoute({
|
|
652
|
+
pageUid: 'test-route',
|
|
653
|
+
pathname: '/admin/test-route',
|
|
654
|
+
});
|
|
655
|
+
resolvePopupModels.forEach((resolvePopupModel) => {
|
|
656
|
+
resolvePopupModel(createViewModel('popup', popupDispatchEvent));
|
|
657
|
+
});
|
|
658
|
+
await nextTick();
|
|
659
|
+
|
|
660
|
+
expect(popupDispatchEvent.mock.calls.length).toBe(0);
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
it('does not duplicate pending async view opens when the same pathname syncs again', async () => {
|
|
664
|
+
const engine = new FlowEngine();
|
|
665
|
+
engine.registerModels({ RouteModel });
|
|
666
|
+
engine.context.defineProperty('route', {
|
|
667
|
+
value: {},
|
|
668
|
+
});
|
|
669
|
+
engine.context.defineProperty('routeRepository', {
|
|
670
|
+
value: {
|
|
671
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
672
|
+
},
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
const rootDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
676
|
+
payload.destroyRef.current = vi.fn();
|
|
677
|
+
return Promise.resolve();
|
|
678
|
+
});
|
|
679
|
+
const popupDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
680
|
+
payload.destroyRef.current = vi.fn();
|
|
681
|
+
return Promise.resolve();
|
|
682
|
+
});
|
|
683
|
+
const rootViewItem = createViewItem('test-route', rootDispatchEvent);
|
|
684
|
+
const popupViewItem: ViewItem = {
|
|
685
|
+
params: { viewUid: 'popup' },
|
|
686
|
+
modelUid: 'popup',
|
|
687
|
+
model: undefined,
|
|
688
|
+
hidden: { value: false },
|
|
689
|
+
index: 1,
|
|
690
|
+
};
|
|
691
|
+
const resolvePopupModels: Array<(model: FlowModel) => void> = [];
|
|
692
|
+
vi.spyOn(engine, 'loadModel').mockImplementation(
|
|
693
|
+
() =>
|
|
694
|
+
new Promise((resolve) => {
|
|
695
|
+
resolvePopupModels.push(resolve);
|
|
696
|
+
}),
|
|
697
|
+
);
|
|
698
|
+
let resolvedViewList: ViewItem[] = [rootViewItem];
|
|
699
|
+
mockResolveViewParamsToViewList.mockImplementation(() => resolvedViewList);
|
|
700
|
+
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
701
|
+
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
702
|
+
viewsToOpen: currentViewList.filter((currentViewItem) => !prevViewList.includes(currentViewItem)),
|
|
703
|
+
}));
|
|
704
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
705
|
+
collectionName: '',
|
|
706
|
+
dataSourceKey: '',
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
710
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
711
|
+
coordinator.registerPage('test-route', {
|
|
712
|
+
active: true,
|
|
713
|
+
layoutContentElement: document.createElement('div'),
|
|
714
|
+
});
|
|
715
|
+
coordinator.syncRoute({
|
|
716
|
+
pageUid: 'test-route',
|
|
717
|
+
pathname: '/admin/test-route',
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
resolvedViewList = [rootViewItem, popupViewItem];
|
|
721
|
+
coordinator.syncRoute({
|
|
722
|
+
pageUid: 'test-route',
|
|
723
|
+
pathname: '/admin/test-route/view/popup',
|
|
724
|
+
});
|
|
725
|
+
coordinator.syncRoute({
|
|
726
|
+
pageUid: 'test-route',
|
|
727
|
+
pathname: '/admin/test-route/view/popup',
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
resolvePopupModels.forEach((resolvePopupModel) => {
|
|
731
|
+
resolvePopupModel(createViewModel('popup', popupDispatchEvent));
|
|
732
|
+
});
|
|
733
|
+
await nextTick();
|
|
734
|
+
|
|
735
|
+
expect(popupDispatchEvent).toHaveBeenCalledTimes(1);
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
it('clears pending route view opens when dispatchEvent throws synchronously', async () => {
|
|
739
|
+
const engine = new FlowEngine();
|
|
740
|
+
engine.registerModels({ RouteModel });
|
|
741
|
+
engine.context.defineProperty('route', {
|
|
742
|
+
value: {},
|
|
743
|
+
});
|
|
744
|
+
engine.context.defineProperty('routeRepository', {
|
|
745
|
+
value: {
|
|
746
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
747
|
+
},
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
const dispatchError = new Error('open failed');
|
|
751
|
+
const dispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
752
|
+
if (dispatchEvent.mock.calls.length === 1) {
|
|
753
|
+
throw dispatchError;
|
|
754
|
+
}
|
|
69
755
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
756
|
+
payload.destroyRef.current = vi.fn();
|
|
757
|
+
return Promise.resolve();
|
|
758
|
+
});
|
|
759
|
+
const viewItem = createViewItem('test-route', dispatchEvent);
|
|
760
|
+
mockResolveViewParamsToViewList.mockReturnValue([viewItem]);
|
|
761
|
+
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
762
|
+
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
763
|
+
viewsToOpen: currentViewList.filter((currentViewItem) => !prevViewList.includes(currentViewItem)),
|
|
764
|
+
}));
|
|
765
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
766
|
+
collectionName: '',
|
|
767
|
+
dataSourceKey: '',
|
|
768
|
+
});
|
|
769
|
+
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
80
770
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
771
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
772
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
773
|
+
coordinator.registerPage('test-route', {
|
|
774
|
+
active: true,
|
|
775
|
+
layoutContentElement: document.createElement('div'),
|
|
776
|
+
});
|
|
777
|
+
coordinator.syncRoute({
|
|
778
|
+
pageUid: 'test-route',
|
|
779
|
+
pathname: '/admin/test-route',
|
|
780
|
+
});
|
|
781
|
+
await nextTick();
|
|
90
782
|
|
|
91
|
-
|
|
92
|
-
|
|
783
|
+
coordinator.syncRoute({
|
|
784
|
+
pageUid: 'test-route',
|
|
785
|
+
pathname: '/admin/test-route',
|
|
786
|
+
});
|
|
93
787
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
vi.clearAllMocks();
|
|
788
|
+
expect(dispatchEvent).toHaveBeenCalledTimes(2);
|
|
789
|
+
consoleErrorSpy.mockRestore();
|
|
97
790
|
});
|
|
98
791
|
|
|
99
|
-
it('
|
|
100
|
-
const
|
|
792
|
+
it('ignores stale initial deep-link replay after the pathname changes before a view opens', async () => {
|
|
793
|
+
const engine = new FlowEngine();
|
|
794
|
+
engine.registerModels({ RouteModel });
|
|
795
|
+
engine.context.defineProperty('router', {
|
|
796
|
+
value: {
|
|
797
|
+
navigate: vi.fn(),
|
|
798
|
+
},
|
|
799
|
+
});
|
|
800
|
+
engine.context.defineProperty('route', {
|
|
801
|
+
value: {},
|
|
802
|
+
});
|
|
803
|
+
engine.context.defineProperty('routeRepository', {
|
|
804
|
+
value: {
|
|
805
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
806
|
+
},
|
|
807
|
+
});
|
|
101
808
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
809
|
+
const rootDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
810
|
+
payload.destroyRef.current = vi.fn();
|
|
811
|
+
payload.onOpen();
|
|
812
|
+
return Promise.resolve();
|
|
813
|
+
});
|
|
814
|
+
const popupDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
815
|
+
payload.destroyRef.current = vi.fn();
|
|
816
|
+
return Promise.resolve();
|
|
817
|
+
});
|
|
818
|
+
const rootViewItem = createViewItem('test-route', rootDispatchEvent);
|
|
819
|
+
const popupViewItem = createViewItem('popup', popupDispatchEvent, 1);
|
|
820
|
+
mockResolveViewParamsToViewList.mockImplementation((_engine, viewParams) => {
|
|
821
|
+
if (viewParams[1]?.viewUid === 'popup') {
|
|
822
|
+
return [rootViewItem, popupViewItem];
|
|
823
|
+
}
|
|
824
|
+
return [];
|
|
825
|
+
});
|
|
826
|
+
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
827
|
+
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
828
|
+
viewsToOpen: currentViewList.filter((currentViewItem) => !prevViewList.includes(currentViewItem)),
|
|
829
|
+
}));
|
|
830
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
831
|
+
collectionName: '',
|
|
832
|
+
dataSourceKey: '',
|
|
108
833
|
});
|
|
109
|
-
});
|
|
110
834
|
|
|
111
|
-
|
|
112
|
-
|
|
835
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
836
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
837
|
+
coordinator.registerPage('test-route', {
|
|
838
|
+
active: true,
|
|
839
|
+
layoutContentElement: document.createElement('div'),
|
|
840
|
+
});
|
|
841
|
+
coordinator.syncRoute({
|
|
842
|
+
pageUid: 'test-route',
|
|
843
|
+
pathname: '/admin/test-route/view/popup',
|
|
844
|
+
});
|
|
113
845
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
dataSourceKey: 'main',
|
|
118
|
-
filterByTk: 'member',
|
|
119
|
-
sourceId: '1',
|
|
120
|
-
triggerByRouter: true,
|
|
846
|
+
coordinator.syncRoute({
|
|
847
|
+
pageUid: 'test-route',
|
|
848
|
+
pathname: '/admin/test-route',
|
|
121
849
|
});
|
|
850
|
+
await nextTick();
|
|
851
|
+
|
|
852
|
+
expect(popupDispatchEvent.mock.calls.length).toBe(0);
|
|
122
853
|
});
|
|
123
854
|
|
|
124
|
-
it('
|
|
125
|
-
const
|
|
126
|
-
|
|
855
|
+
it('ignores stale async view opens after the route is cleared', async () => {
|
|
856
|
+
const engine = new FlowEngine();
|
|
857
|
+
engine.registerModels({ RouteModel });
|
|
858
|
+
engine.context.defineProperty('route', {
|
|
859
|
+
value: {},
|
|
860
|
+
});
|
|
861
|
+
engine.context.defineProperty('routeRepository', {
|
|
862
|
+
value: {
|
|
863
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
864
|
+
},
|
|
127
865
|
});
|
|
128
866
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
867
|
+
const rootDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
868
|
+
payload.destroyRef.current = vi.fn();
|
|
869
|
+
return Promise.resolve();
|
|
870
|
+
});
|
|
871
|
+
const popupDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
872
|
+
payload.destroyRef.current = vi.fn();
|
|
873
|
+
return Promise.resolve();
|
|
874
|
+
});
|
|
875
|
+
const rootViewItem = createViewItem('test-route', rootDispatchEvent);
|
|
876
|
+
const popupViewItem: ViewItem = {
|
|
877
|
+
params: { viewUid: 'popup' },
|
|
878
|
+
modelUid: 'popup',
|
|
879
|
+
model: undefined,
|
|
880
|
+
hidden: { value: false },
|
|
881
|
+
index: 1,
|
|
882
|
+
};
|
|
883
|
+
let resolvePopupModel: (model: FlowModel) => void = () => {};
|
|
884
|
+
vi.spyOn(engine, 'loadModel').mockImplementation(
|
|
885
|
+
() =>
|
|
886
|
+
new Promise((resolve) => {
|
|
887
|
+
resolvePopupModel = resolve;
|
|
888
|
+
}),
|
|
889
|
+
);
|
|
890
|
+
let resolvedViewList: ViewItem[] = [rootViewItem];
|
|
891
|
+
mockResolveViewParamsToViewList.mockImplementation(() => resolvedViewList);
|
|
892
|
+
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
893
|
+
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
894
|
+
viewsToOpen: currentViewList.filter((currentViewItem) => !prevViewList.includes(currentViewItem)),
|
|
895
|
+
}));
|
|
896
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
897
|
+
collectionName: '',
|
|
898
|
+
dataSourceKey: '',
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
902
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
903
|
+
coordinator.registerPage('test-route', {
|
|
904
|
+
active: true,
|
|
905
|
+
layoutContentElement: document.createElement('div'),
|
|
906
|
+
});
|
|
907
|
+
coordinator.syncRoute({
|
|
908
|
+
pageUid: 'test-route',
|
|
909
|
+
pathname: '/admin/test-route',
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
resolvedViewList = [rootViewItem, popupViewItem];
|
|
913
|
+
coordinator.syncRoute({
|
|
914
|
+
pageUid: 'test-route',
|
|
915
|
+
pathname: '/admin/test-route/view/popup',
|
|
134
916
|
});
|
|
917
|
+
|
|
918
|
+
coordinator.syncRoute({});
|
|
919
|
+
resolvePopupModel(createViewModel('popup', popupDispatchEvent));
|
|
920
|
+
await nextTick();
|
|
921
|
+
|
|
922
|
+
expect(popupDispatchEvent).not.toHaveBeenCalled();
|
|
135
923
|
});
|
|
136
924
|
|
|
137
|
-
it('
|
|
925
|
+
it('ignores stale async view opens after switching away and back to the same pathname', async () => {
|
|
138
926
|
const engine = new FlowEngine();
|
|
139
927
|
engine.registerModels({ RouteModel });
|
|
140
928
|
engine.context.defineProperty('route', {
|
|
@@ -146,35 +934,161 @@ describe('AdminLayoutRouteCoordinator', () => {
|
|
|
146
934
|
},
|
|
147
935
|
});
|
|
148
936
|
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
937
|
+
const pageRootDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
938
|
+
payload.destroyRef.current = vi.fn();
|
|
939
|
+
return Promise.resolve();
|
|
940
|
+
});
|
|
941
|
+
const otherRootDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
942
|
+
payload.destroyRef.current = vi.fn();
|
|
943
|
+
return Promise.resolve();
|
|
944
|
+
});
|
|
945
|
+
const stalePopupDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
946
|
+
payload.destroyRef.current = vi.fn();
|
|
947
|
+
return Promise.resolve();
|
|
948
|
+
});
|
|
949
|
+
const currentPopupDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
950
|
+
payload.destroyRef.current = vi.fn();
|
|
951
|
+
return Promise.resolve();
|
|
952
|
+
});
|
|
953
|
+
const pageRootViewItem = createViewItem('test-route', pageRootDispatchEvent);
|
|
954
|
+
const otherRootViewItem = createViewItem('other-route', otherRootDispatchEvent);
|
|
955
|
+
const firstPopupViewItem: ViewItem = {
|
|
956
|
+
params: { viewUid: 'popup' },
|
|
957
|
+
modelUid: 'popup',
|
|
958
|
+
model: undefined,
|
|
156
959
|
hidden: { value: false },
|
|
157
|
-
index:
|
|
960
|
+
index: 1,
|
|
158
961
|
};
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
962
|
+
const secondPopupViewItem: ViewItem = {
|
|
963
|
+
params: { viewUid: 'popup' },
|
|
964
|
+
modelUid: 'popup',
|
|
965
|
+
model: undefined,
|
|
966
|
+
hidden: { value: false },
|
|
967
|
+
index: 1,
|
|
968
|
+
};
|
|
969
|
+
const resolvePopupModels: Array<(model: FlowModel) => void> = [];
|
|
970
|
+
vi.spyOn(engine, 'loadModel').mockImplementation(
|
|
971
|
+
() =>
|
|
972
|
+
new Promise((resolve) => {
|
|
973
|
+
resolvePopupModels.push(resolve);
|
|
974
|
+
}),
|
|
975
|
+
);
|
|
976
|
+
let resolvedViewList: ViewItem[] = [pageRootViewItem];
|
|
977
|
+
mockResolveViewParamsToViewList.mockImplementation(() => resolvedViewList);
|
|
978
|
+
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
979
|
+
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
980
|
+
viewsToOpen: currentViewList.filter((currentViewItem) => !prevViewList.includes(currentViewItem)),
|
|
981
|
+
}));
|
|
982
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
983
|
+
collectionName: '',
|
|
984
|
+
dataSourceKey: '',
|
|
163
985
|
});
|
|
164
|
-
mockGetOpenViewStepParams.mockReturnValue({} as any);
|
|
165
986
|
|
|
166
987
|
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
167
|
-
coordinator.setLayoutContentElement(
|
|
988
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
168
989
|
coordinator.registerPage('test-route', {
|
|
169
990
|
active: true,
|
|
170
|
-
layoutContentElement:
|
|
991
|
+
layoutContentElement: document.createElement('div'),
|
|
992
|
+
});
|
|
993
|
+
coordinator.registerPage('other-route', {
|
|
994
|
+
active: false,
|
|
995
|
+
layoutContentElement: document.createElement('div'),
|
|
171
996
|
});
|
|
172
997
|
coordinator.syncRoute({
|
|
173
998
|
pageUid: 'test-route',
|
|
174
999
|
pathname: '/admin/test-route',
|
|
175
1000
|
});
|
|
176
1001
|
|
|
177
|
-
|
|
1002
|
+
resolvedViewList = [pageRootViewItem, firstPopupViewItem];
|
|
1003
|
+
coordinator.syncRoute({
|
|
1004
|
+
pageUid: 'test-route',
|
|
1005
|
+
pathname: '/admin/test-route/view/popup',
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
resolvedViewList = [otherRootViewItem];
|
|
1009
|
+
coordinator.syncRoute({
|
|
1010
|
+
pageUid: 'other-route',
|
|
1011
|
+
pathname: '/admin/other-route',
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
resolvedViewList = [pageRootViewItem, secondPopupViewItem];
|
|
1015
|
+
coordinator.syncRoute({
|
|
1016
|
+
pageUid: 'test-route',
|
|
1017
|
+
pathname: '/admin/test-route/view/popup',
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
resolvePopupModels[0]?.(createViewModel('popup', stalePopupDispatchEvent));
|
|
1021
|
+
resolvePopupModels[1]?.(createViewModel('popup', currentPopupDispatchEvent));
|
|
1022
|
+
await nextTick();
|
|
1023
|
+
|
|
1024
|
+
expect(stalePopupDispatchEvent).not.toHaveBeenCalled();
|
|
1025
|
+
expect(currentPopupDispatchEvent).toHaveBeenCalledTimes(1);
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
it('does not run initial deep-link step navigation while replaying after layout content element changes', () => {
|
|
1029
|
+
const engine = new FlowEngine();
|
|
1030
|
+
engine.registerModels({ RouteModel });
|
|
1031
|
+
const navigate = vi.fn();
|
|
1032
|
+
engine.context.defineProperty('router', {
|
|
1033
|
+
value: {
|
|
1034
|
+
navigate,
|
|
1035
|
+
},
|
|
1036
|
+
});
|
|
1037
|
+
engine.context.defineProperty('route', {
|
|
1038
|
+
value: {},
|
|
1039
|
+
});
|
|
1040
|
+
engine.context.defineProperty('routeRepository', {
|
|
1041
|
+
value: {
|
|
1042
|
+
getRouteBySchemaUid: vi.fn(() => ({})),
|
|
1043
|
+
},
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
const rootDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
1047
|
+
payload.destroyRef.current = vi.fn();
|
|
1048
|
+
payload.onOpen();
|
|
1049
|
+
return Promise.resolve();
|
|
1050
|
+
});
|
|
1051
|
+
const popupDispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
1052
|
+
payload.destroyRef.current = vi.fn();
|
|
1053
|
+
return Promise.resolve();
|
|
1054
|
+
});
|
|
1055
|
+
const rootViewItem = createViewItem('test-route', rootDispatchEvent);
|
|
1056
|
+
const popupViewItem = createViewItem('popup', popupDispatchEvent, 1);
|
|
1057
|
+
let resolvedViewList: ViewItem[] = [rootViewItem];
|
|
1058
|
+
mockResolveViewParamsToViewList.mockImplementation(() => resolvedViewList);
|
|
1059
|
+
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
1060
|
+
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
1061
|
+
viewsToOpen: currentViewList.filter((currentViewItem) => !prevViewList.includes(currentViewItem)),
|
|
1062
|
+
}));
|
|
1063
|
+
mockGetOpenViewStepParams.mockReturnValue({
|
|
1064
|
+
collectionName: '',
|
|
1065
|
+
dataSourceKey: '',
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
const coordinator = new BaseLayoutRouteCoordinator(engine, { basePathname: '/admin' });
|
|
1069
|
+
coordinator.setLayoutContentElement(document.createElement('div'));
|
|
1070
|
+
coordinator.registerPage('test-route', {
|
|
1071
|
+
active: true,
|
|
1072
|
+
layoutContentElement: document.createElement('div'),
|
|
1073
|
+
});
|
|
1074
|
+
coordinator.syncRoute({
|
|
1075
|
+
pageUid: 'test-route',
|
|
1076
|
+
pathname: '/admin/test-route',
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
resolvedViewList = [rootViewItem, popupViewItem];
|
|
1080
|
+
coordinator.syncRoute({
|
|
1081
|
+
pageUid: 'test-route',
|
|
1082
|
+
pathname: '/admin/test-route/view/popup',
|
|
1083
|
+
});
|
|
1084
|
+
navigate.mockClear();
|
|
1085
|
+
|
|
1086
|
+
const nextLayoutContentElement = document.createElement('div');
|
|
1087
|
+
coordinator.setLayoutContentElement(nextLayoutContentElement);
|
|
1088
|
+
|
|
1089
|
+
expect(navigate).not.toHaveBeenCalled();
|
|
1090
|
+
expect(popupDispatchEvent).toHaveBeenCalledTimes(2);
|
|
1091
|
+
expect(popupDispatchEvent.mock.calls[1][1].target).toBe(nextLayoutContentElement);
|
|
178
1092
|
});
|
|
179
1093
|
|
|
180
1094
|
it('replaces stale non-route model before registering route page', () => {
|
|
@@ -281,18 +1195,12 @@ describe('AdminLayoutRouteCoordinator', () => {
|
|
|
281
1195
|
},
|
|
282
1196
|
});
|
|
283
1197
|
|
|
284
|
-
const dispatchEvent =
|
|
1198
|
+
const dispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
285
1199
|
payload.activateRef.current = vi.fn();
|
|
286
1200
|
payload.deactivateRef.current = vi.fn();
|
|
287
1201
|
return Promise.resolve();
|
|
288
1202
|
});
|
|
289
|
-
const viewItem =
|
|
290
|
-
params: { viewUid: 'test-route' },
|
|
291
|
-
modelUid: 'test-route',
|
|
292
|
-
model: { uid: 'test-route', dispatchEvent } as any,
|
|
293
|
-
hidden: { value: false },
|
|
294
|
-
index: 0,
|
|
295
|
-
};
|
|
1203
|
+
const viewItem = createViewItem('test-route', dispatchEvent);
|
|
296
1204
|
mockResolveViewParamsToViewList.mockReturnValue([viewItem]);
|
|
297
1205
|
mockGetViewDiffAndUpdateHidden.mockReturnValueOnce({
|
|
298
1206
|
viewsToClose: [],
|
|
@@ -342,28 +1250,26 @@ describe('AdminLayoutRouteCoordinator', () => {
|
|
|
342
1250
|
},
|
|
343
1251
|
});
|
|
344
1252
|
|
|
345
|
-
const viewItemsByPageUid = new Map<string,
|
|
346
|
-
const
|
|
347
|
-
const dispatchEvent =
|
|
1253
|
+
const viewItemsByPageUid = new Map<string, ViewItem>();
|
|
1254
|
+
const createCachedViewItem = (pageUid: string) => {
|
|
1255
|
+
const dispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
348
1256
|
payload.activateRef.current = vi.fn();
|
|
349
1257
|
payload.deactivateRef.current = vi.fn();
|
|
350
1258
|
return Promise.resolve();
|
|
351
1259
|
});
|
|
352
|
-
return
|
|
353
|
-
params: { viewUid: pageUid },
|
|
354
|
-
modelUid: pageUid,
|
|
355
|
-
model: { uid: pageUid, dispatchEvent } as any,
|
|
356
|
-
hidden: { value: false },
|
|
357
|
-
index: 0,
|
|
358
|
-
};
|
|
1260
|
+
return createViewItem(pageUid, dispatchEvent);
|
|
359
1261
|
};
|
|
360
1262
|
|
|
361
1263
|
mockResolveViewParamsToViewList.mockImplementation((_engine, viewParams) => {
|
|
362
1264
|
const pageUid = viewParams[0].viewUid;
|
|
363
1265
|
if (!viewItemsByPageUid.has(pageUid)) {
|
|
364
|
-
viewItemsByPageUid.set(pageUid,
|
|
1266
|
+
viewItemsByPageUid.set(pageUid, createCachedViewItem(pageUid));
|
|
1267
|
+
}
|
|
1268
|
+
const viewItem = viewItemsByPageUid.get(pageUid);
|
|
1269
|
+
if (!viewItem) {
|
|
1270
|
+
throw new Error(`Expected cached view item for ${pageUid}.`);
|
|
365
1271
|
}
|
|
366
|
-
return [
|
|
1272
|
+
return [viewItem];
|
|
367
1273
|
});
|
|
368
1274
|
mockGetViewDiffAndUpdateHidden.mockImplementation((prevViewList, currentViewList) => ({
|
|
369
1275
|
viewsToClose: prevViewList.filter((prevViewItem) => !currentViewList.includes(prevViewItem)),
|
|
@@ -420,18 +1326,12 @@ describe('AdminLayoutRouteCoordinator', () => {
|
|
|
420
1326
|
},
|
|
421
1327
|
});
|
|
422
1328
|
|
|
423
|
-
const dispatchEvent =
|
|
1329
|
+
const dispatchEvent = createDispatchEventMock((_eventName, payload) => {
|
|
424
1330
|
payload.activateRef.current = vi.fn();
|
|
425
1331
|
payload.deactivateRef.current = vi.fn();
|
|
426
1332
|
return Promise.resolve();
|
|
427
1333
|
});
|
|
428
|
-
const viewItem =
|
|
429
|
-
params: { viewUid: 'test-route' },
|
|
430
|
-
modelUid: 'test-route',
|
|
431
|
-
model: { uid: 'test-route', dispatchEvent } as any,
|
|
432
|
-
hidden: { value: false },
|
|
433
|
-
index: 0,
|
|
434
|
-
};
|
|
1334
|
+
const viewItem = createViewItem('test-route', dispatchEvent);
|
|
435
1335
|
mockResolveViewParamsToViewList.mockReturnValue([viewItem]);
|
|
436
1336
|
mockGetViewDiffAndUpdateHidden.mockReturnValueOnce({
|
|
437
1337
|
viewsToClose: [],
|
|
@@ -479,13 +1379,10 @@ describe('AdminLayoutRouteCoordinator', () => {
|
|
|
479
1379
|
},
|
|
480
1380
|
});
|
|
481
1381
|
|
|
482
|
-
const popupViewItem = {
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
hidden: { value: false },
|
|
487
|
-
index: 1,
|
|
488
|
-
};
|
|
1382
|
+
const popupViewItem = createViewItem('popup', createDispatchEventMock(), 1, {
|
|
1383
|
+
viewUid: 'popup',
|
|
1384
|
+
filterByTk: '1',
|
|
1385
|
+
});
|
|
489
1386
|
mockResolveViewParamsToViewList.mockImplementation((_engine, viewParams, routeModel) => [
|
|
490
1387
|
{
|
|
491
1388
|
params: viewParams[0],
|