UNPKG

@nocobase/flow-engine

Version:

A standalone flow engine for NocoBase, managing workflows, models, and actions.

192 lines (154 loc) 7.1 kB
/** * This file is part of the NocoBase (R) project. * Copyright (c) 2020-2024 NocoBase Co., Ltd. * Authors: NocoBase Team. * * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. * For more information, please refer to: https://www.nocobase.com/agreement. */ import { ViewNavigation, generatePathnameFromViewParams } from '../ViewNavigation'; describe('ViewNavigation', () => { let mockCtx: any; let viewNavigation: ViewNavigation; beforeEach(() => { mockCtx = { router: { navigate: vi.fn(), }, route: { pathname: '/admin/test', }, }; }); describe('changeTo', () => { it('should replace current view when viewStack is empty', () => { viewNavigation = new ViewNavigation(mockCtx, []); viewNavigation.changeTo({ viewUid: 'new-view' }); expect(viewNavigation.viewStack).toEqual([{ viewUid: 'new-view' }]); expect(mockCtx.router.navigate).toHaveBeenCalledWith('/admin/new-view', { replace: true }); }); it('should replace last view in viewStack', () => { viewNavigation = new ViewNavigation(mockCtx, [{ viewUid: 'old-view' }]); viewNavigation.changeTo({ viewUid: 'new-view', tabUid: 'tab1' }); expect(viewNavigation.viewStack).toEqual([{ viewUid: 'new-view', tabUid: 'tab1' }]); expect(mockCtx.router.navigate).toHaveBeenCalledWith('/admin/new-view/tab/tab1', { replace: true }); }); it('should replace last view with complex parameters', () => { viewNavigation = new ViewNavigation(mockCtx, [{ viewUid: 'view1' }, { viewUid: 'view2', tabUid: 'tab1' }]); viewNavigation.changeTo({ viewUid: 'new-view', tabUid: 'new-tab', filterByTk: '123', sourceId: 'source1', }); expect(viewNavigation.viewStack).toEqual([ { viewUid: 'view1' }, { viewUid: 'new-view', tabUid: 'new-tab', filterByTk: '123', sourceId: 'source1' }, ]); expect(mockCtx.router.navigate).toHaveBeenCalledWith( '/admin/view1/view/new-view/tab/new-tab/filterbytk/123/sourceid/source1', { replace: true }, ); }); it('should allow omitting viewUid', () => { viewNavigation = new ViewNavigation(mockCtx, [{ viewUid: 'view1' }]); viewNavigation.changeTo({ tabUid: 'new-tab' }); expect(viewNavigation.viewStack).toEqual([{ viewUid: 'view1', tabUid: 'new-tab' }]); }); }); describe('navigateTo', () => { it('should navigate to new view', () => { viewNavigation = new ViewNavigation(mockCtx, [{ viewUid: 'current-view' }]); viewNavigation.navigateTo({ viewUid: 'new-view' }); // viewStack 保持不变 expect(viewNavigation.viewStack).toEqual([{ viewUid: 'current-view' }]); const call = (mockCtx.router.navigate as any).mock.calls[0]; expect(call[0]).toBe('/admin/current-view/view/new-view'); expect(call[1]).toBeUndefined(); }); it('should navigate back when pathname is the same', () => { viewNavigation = new ViewNavigation(mockCtx, [{ viewUid: 'view1' }]); // set browser location to match the generated pathname window.history.pushState({}, '', '/admin/view1/view/view2'); viewNavigation.navigateTo({ viewUid: 'view2' }); // when same pathname, navigate(-1) to avoid "no reaction" UX expect(mockCtx.router.navigate).toHaveBeenCalledWith(-1); expect(viewNavigation.viewStack).toEqual([{ viewUid: 'view1' }]); }); it('should navigate with complex parameters', () => { viewNavigation = new ViewNavigation(mockCtx, [{ viewUid: 'view1', tabUid: 'tab1' }]); viewNavigation.navigateTo({ viewUid: 'view2', tabUid: 'tab2', filterByTk: '456', sourceId: 'source2', }); // viewStack 保持不变 expect(viewNavigation.viewStack).toEqual([{ viewUid: 'view1', tabUid: 'tab1' }]); const call = (mockCtx.router.navigate as any).mock.calls[0]; expect(call[0]).toBe('/admin/view1/tab/tab1/view/view2/tab/tab2/filterbytk/456/sourceid/source2'); expect(call[1]).toBeUndefined(); }); it('should navigate from empty viewStack', () => { viewNavigation = new ViewNavigation(mockCtx, []); viewNavigation.navigateTo({ viewUid: 'first-view' }); expect(viewNavigation.viewStack).toEqual([{ viewUid: 'first-view' }]); const call = (mockCtx.router.navigate as any).mock.calls[0]; expect(call[0]).toBe('/admin/first-view'); expect(call[1]).toBeUndefined(); }); }); describe('back', () => { it('should call router navigate with -1', () => { viewNavigation = new ViewNavigation(mockCtx, [{ viewUid: 'view1' }]); // set browser location to current stack pathname so back() triggers window.history.pushState({}, '', '/admin/view1'); viewNavigation.back(); expect(mockCtx.router.navigate).toHaveBeenCalledWith(-1); }); }); }); describe('generatePathnameFromViewParams', () => { it('should handle empty array', () => { expect(generatePathnameFromViewParams([])).toBe('/admin'); expect(generatePathnameFromViewParams(null as any)).toBe('/admin'); expect(generatePathnameFromViewParams(undefined as any)).toBe('/admin'); }); it('should generate single view path', () => { expect(generatePathnameFromViewParams([{ viewUid: 'xxx' }])).toBe('/admin/xxx'); }); it('should generate view with tab', () => { expect(generatePathnameFromViewParams([{ viewUid: 'xxx', tabUid: 'yyy' }])).toBe('/admin/xxx/tab/yyy'); }); it('should generate multiple views', () => { expect(generatePathnameFromViewParams([{ viewUid: 'xxx' }, { viewUid: 'yyy' }])).toBe('/admin/xxx/view/yyy'); }); it('should generate complex path with all parameters', () => { expect( generatePathnameFromViewParams([ { viewUid: 'xxx', tabUid: 'tab1' }, { viewUid: 'yyy', tabUid: 'tab2', filterByTk: '123', sourceId: 'source1' }, ]), ).toBe('/admin/xxx/tab/tab1/view/yyy/tab/tab2/filterbytk/123/sourceid/source1'); }); it('should handle filterByTk and sourceId without tab', () => { expect(generatePathnameFromViewParams([{ viewUid: 'xxx', filterByTk: '1', sourceId: '2' }])).toBe( '/admin/xxx/filterbytk/1/sourceid/2', ); }); it('should match parsePathnameToViewParams test cases', () => { // Test cases from parsePathnameToViewParams.test.ts expect(generatePathnameFromViewParams([{ viewUid: 'xxx' }])).toBe('/admin/xxx'); expect(generatePathnameFromViewParams([{ viewUid: 'xxx', tabUid: 'yyy' }])).toBe('/admin/xxx/tab/yyy'); expect(generatePathnameFromViewParams([{ viewUid: 'xxx' }, { viewUid: 'yyy' }])).toBe('/admin/xxx/view/yyy'); expect(generatePathnameFromViewParams([{ viewUid: 'xxx' }, { viewUid: 'yyy', tabUid: 'zzz' }])).toBe( '/admin/xxx/view/yyy/tab/zzz', ); expect( generatePathnameFromViewParams([ { viewUid: 'xxx', tabUid: 'yyy' }, { viewUid: 'zzz', tabUid: 'aaa' }, ]), ).toBe('/admin/xxx/tab/yyy/view/zzz/tab/aaa'); }); });