diff --git a/modules/router-store/jest.config.ts b/modules/router-store/jest.config.ts deleted file mode 100644 index 155c3c4077..0000000000 --- a/modules/router-store/jest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'Router Store', - preset: '../../jest.preset.js', - coverageDirectory: '../../coverage/modules/router-store', - setupFilesAfterEnv: ['/test-setup.ts'], - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], - testRunner: 'jest-jasmine2', -}; diff --git a/modules/router-store/migrations/14_0_0/index.spec.ts b/modules/router-store/migrations/14_0_0/index.spec.ts index d4dd66b030..8f2c0f4137 100644 --- a/modules/router-store/migrations/14_0_0/index.spec.ts +++ b/modules/router-store/migrations/14_0_0/index.spec.ts @@ -9,7 +9,10 @@ import { waitForAsync } from '@angular/core/testing'; describe('Router Store Migration 14_0_0', () => { let appTree: UnitTestTree; - const collectionPath = path.join(__dirname, '../migration.json'); + const collectionPath = path.join( + process.cwd(), + 'dist/modules/router-store/migrations/migration.json' + ); const pkgName = 'router-store'; beforeEach(() => { diff --git a/modules/router-store/migrations/15_2_0/index.spec.ts b/modules/router-store/migrations/15_2_0/index.spec.ts index e4e895f564..b0fc63aa0c 100644 --- a/modules/router-store/migrations/15_2_0/index.spec.ts +++ b/modules/router-store/migrations/15_2_0/index.spec.ts @@ -9,7 +9,10 @@ import { waitForAsync } from '@angular/core/testing'; describe('Router Store Migration 15_2_0', () => { let appTree: UnitTestTree; - const collectionPath = path.join(__dirname, '../migration.json'); + const collectionPath = path.join( + process.cwd(), + 'dist/modules/router-store/migrations/migration.json' + ); const pkgName = 'router-store'; beforeEach(() => { diff --git a/modules/router-store/migrations/6_0_0/index.spec.ts b/modules/router-store/migrations/6_0_0/index.spec.ts index 2492f1839a..c149e69097 100644 --- a/modules/router-store/migrations/6_0_0/index.spec.ts +++ b/modules/router-store/migrations/6_0_0/index.spec.ts @@ -13,7 +13,10 @@ import { versionPrefixes, } from '@ngrx/schematics-core/testing/update'; -const collectionPath = path.join(__dirname, '../migration.json'); +const collectionPath = path.join( + process.cwd(), + 'dist/modules/router-store/migrations/migration.json' +); describe('Router Store Migration 6_0_0', () => { let appTree; diff --git a/modules/router-store/migrations/8_0_0/index.spec.ts b/modules/router-store/migrations/8_0_0/index.spec.ts index 78d1f0e3b4..ba0bce44a7 100644 --- a/modules/router-store/migrations/8_0_0/index.spec.ts +++ b/modules/router-store/migrations/8_0_0/index.spec.ts @@ -8,7 +8,10 @@ import { createPackageJson } from '@ngrx/schematics-core/testing/create-package' describe('Router Store Migration 8_0_0', () => { let appTree: UnitTestTree; - const collectionPath = path.join(__dirname, '../migration.json'); + const collectionPath = path.join( + process.cwd(), + 'dist/modules/router-store/migrations/migration.json' + ); const pkgName = 'router-store'; beforeEach(() => { diff --git a/modules/router-store/migrations/9_0_0/index.spec.ts b/modules/router-store/migrations/9_0_0/index.spec.ts index 0904703716..0da54a7a5b 100644 --- a/modules/router-store/migrations/9_0_0/index.spec.ts +++ b/modules/router-store/migrations/9_0_0/index.spec.ts @@ -8,7 +8,10 @@ import { createPackageJson } from '@ngrx/schematics-core/testing/create-package' describe('Router Store Migration 9_0_0', () => { let appTree: UnitTestTree; - const collectionPath = path.join(__dirname, '../migration.json'); + const collectionPath = path.join( + process.cwd(), + 'dist/modules/router-store/migrations/migration.json' + ); const pkgName = 'router-store'; beforeEach(() => { diff --git a/modules/router-store/project.json b/modules/router-store/project.json index 83a992e9a4..a9cf1952a0 100644 --- a/modules/router-store/project.json +++ b/modules/router-store/project.json @@ -25,6 +25,15 @@ { "command": "pnpm exec tsc -p modules/router-store/tsconfig.schematics.json" }, + { + "command": "pnpm exec rimraf node_modules/@ngrx/router-store" + }, + { + "command": "pnpm exec mkdirp node_modules/@ngrx/router-store" + }, + { + "command": "ncp dist/modules/router-store node_modules/@ngrx/router-store" + }, { "command": "cpy LICENSE dist/modules/router-store" } @@ -43,12 +52,8 @@ "outputs": ["{options.outputFile}"] }, "test": { - "executor": "@nx/jest:jest", - "options": { - "jestConfig": "modules/router-store/jest.config.ts", - "runInBand": true, - "passWithNoTests": false - }, + "executor": "@analogjs/vitest-angular:test", + "dependsOn": ["build"], "outputs": ["{workspaceRoot}/coverage/modules/router-store"] } } diff --git a/modules/router-store/schematics/ng-add/__snapshots__/index.spec.ts.snap b/modules/router-store/schematics/ng-add/__snapshots__/index.spec.ts.snap index aa84193c13..5fccbbfa3e 100644 --- a/modules/router-store/schematics/ng-add/__snapshots__/index.spec.ts.snap +++ b/modules/router-store/schematics/ng-add/__snapshots__/index.spec.ts.snap @@ -1,6 +1,6 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Router Store ng-add Schematic Router Store ng-add Schematic for standalone application provides initial setup 1`] = ` +exports[`Router Store ng-add Schematic > Router Store ng-add Schematic for standalone application > provides initial setup 1`] = ` "import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core'; import { provideRouterStore } from '@ngrx/router-store'; diff --git a/modules/router-store/schematics/ng-add/index.spec.ts b/modules/router-store/schematics/ng-add/index.spec.ts index df5a49dc62..3e3062bb0c 100644 --- a/modules/router-store/schematics/ng-add/index.spec.ts +++ b/modules/router-store/schematics/ng-add/index.spec.ts @@ -12,7 +12,10 @@ import { describe('Router Store ng-add Schematic', () => { const schematicRunner = new SchematicTestRunner( '@ngrx/router-store', - path.join(__dirname, '../collection.json') + path.join( + process.cwd(), + 'dist/modules/router-store/schematics/collection.json' + ) ); const defaultOptions: RouterStoreOptions = { skipPackageJson: false, diff --git a/modules/router-store/spec/integration.spec.ts b/modules/router-store/spec/integration.spec.ts index bddce1d34d..560b40e2d1 100644 --- a/modules/router-store/spec/integration.spec.ts +++ b/modules/router-store/spec/integration.spec.ts @@ -28,147 +28,154 @@ import { import { createTestModule } from './utils'; describe('integration spec', () => { - it('should work', (done: any) => { - const reducer = (state = '', action: RouterAction) => { - if (action.type === ROUTER_NAVIGATION) { - return action.payload.routerState.url.toString(); - } else { - return state; - } - }; - - createTestModule({ reducers: { reducer } }); - - const router = TestBed.inject(Router); - const log = logOfRouterAndActionsAndStore(); - - router - .navigateByUrl('/') - .then(() => { - expect(log).toEqual([ - { type: 'store', state: '' }, // init event. has nothing to do with the router - { type: 'store', state: '' }, // ROUTER_REQUEST event in the store - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/' }, - { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/' }, - /* new Router Lifecycle in Angular 4.3 */ - { type: 'router', event: 'GuardsCheckStart', url: '/' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/' }, - { type: 'router', event: 'ResolveStart', url: '/' }, - { type: 'router', event: 'ResolveEnd', url: '/' }, - { type: 'store', state: '/' }, // ROUTER_NAVIGATED event in the store - { type: 'action', action: ROUTER_NAVIGATED }, - { type: 'router', event: 'NavigationEnd', url: '/' }, - ]); - }) - .then(() => { - log.splice(0); - return router.navigateByUrl('next'); - }) - .then(() => { - expect(log).toEqual([ - { type: 'store', state: '/' }, // ROUTER_REQUEST event in the store - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'store', state: '/next' }, - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - - /* new Router Lifecycle in Angular 4.3 */ - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, - { type: 'router', event: 'ResolveStart', url: '/next' }, - { type: 'router', event: 'ResolveEnd', url: '/next' }, - { type: 'store', state: '/next' }, // ROUTER_NAVIGATED event in the store - { type: 'action', action: ROUTER_NAVIGATED }, - { type: 'router', event: 'NavigationEnd', url: '/next' }, - ]); - - done(); - }); - }); - - it('should have the routerState in the payload', (done: any) => { - const actionLog: RouterAction[] = []; - const reducer = (state = '', action: RouterAction) => { - switch (action.type) { - case ROUTER_CANCEL: - case ROUTER_ERROR: - case ROUTER_NAVIGATED: - case ROUTER_NAVIGATION: - case ROUTER_REQUEST: - actionLog.push(action); - return state; - default: + it('should work', () => + new Promise((done) => { + const reducer = (state = '', action: RouterAction) => { + if (action.type === ROUTER_NAVIGATION) { + return action.payload.routerState.url.toString(); + } else { return state; - } - }; - - createTestModule({ - reducers: { reducer }, - canActivate: ( - route: ActivatedRouteSnapshot, - state: RouterStateSnapshot - ) => state.url !== 'next', - }); - - const router = TestBed.inject(Router); - const log = logOfRouterAndActionsAndStore(); - - const hasRouterState = (action: RouterAction) => - !!action.payload.routerState; + } + }; + + createTestModule({ reducers: { reducer } }); + + const router = TestBed.inject(Router); + const log = logOfRouterAndActionsAndStore(); + + router + .navigateByUrl('/') + .then(() => { + expect(log).toEqual([ + { type: 'store', state: '' }, // init event. has nothing to do with the router + { type: 'store', state: '' }, // ROUTER_REQUEST event in the store + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/' }, + { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/' }, + /* new Router Lifecycle in Angular 4.3 */ + { type: 'router', event: 'GuardsCheckStart', url: '/' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/' }, + { type: 'router', event: 'ResolveStart', url: '/' }, + { type: 'router', event: 'ResolveEnd', url: '/' }, + { type: 'store', state: '/' }, // ROUTER_NAVIGATED event in the store + { type: 'action', action: ROUTER_NAVIGATED }, + { type: 'router', event: 'NavigationEnd', url: '/' }, + ]); + }) + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .then(() => { + expect(log).toEqual([ + { type: 'store', state: '/' }, // ROUTER_REQUEST event in the store + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'store', state: '/next' }, + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + + /* new Router Lifecycle in Angular 4.3 */ + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, + { type: 'router', event: 'ResolveStart', url: '/next' }, + { type: 'router', event: 'ResolveEnd', url: '/next' }, + { type: 'store', state: '/next' }, // ROUTER_NAVIGATED event in the store + { type: 'action', action: ROUTER_NAVIGATED }, + { type: 'router', event: 'NavigationEnd', url: '/next' }, + ]); + + done(); + }); + })); + + it('should have the routerState in the payload', () => + new Promise((done) => { + const actionLog: RouterAction[] = []; + const reducer = (state = '', action: RouterAction) => { + switch (action.type) { + case ROUTER_CANCEL: + case ROUTER_ERROR: + case ROUTER_NAVIGATED: + case ROUTER_NAVIGATION: + case ROUTER_REQUEST: + actionLog.push(action); + return state; + default: + return state; + } + }; - router - .navigateByUrl('/') - .then(() => { - expect(actionLog.filter(hasRouterState).length).toBe(actionLog.length); - }) - .then(() => { - actionLog.splice(0); - return router.navigateByUrl('next'); - }) - .then(() => { - expect(actionLog.filter(hasRouterState).length).toBe(actionLog.length); - done(); + createTestModule({ + reducers: { reducer }, + canActivate: ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ) => state.url !== 'next', }); - }); - - xit('should support preventing navigation', (done: any) => { - const reducer = (state = '', action: RouterAction) => { - if ( - action.type === ROUTER_NAVIGATION && - action.payload.routerState.url.toString() === '/next' - ) { - throw new Error('You shall not pass!'); - } else { - return state; - } - }; - createTestModule({ reducers: { reducer } }); - - const router = TestBed.inject(Router); - const log = logOfRouterAndActionsAndStore(); - - router - .navigateByUrl('/') - .then(() => { - log.splice(0); - return router.navigateByUrl('next'); - }) - .catch((e) => { - expect(e.message).toEqual('You shall not pass!'); - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'router', event: 'NavigationError', url: '/next' }, - ]); - - done(); - }); - }); + const router = TestBed.inject(Router); + const log = logOfRouterAndActionsAndStore(); + + const hasRouterState = (action: RouterAction) => + !!action.payload.routerState; + + router + .navigateByUrl('/') + .then(() => { + expect(actionLog.filter(hasRouterState).length).toBe( + actionLog.length + ); + }) + .then(() => { + actionLog.splice(0); + return router.navigateByUrl('next'); + }) + .then(() => { + expect(actionLog.filter(hasRouterState).length).toBe( + actionLog.length + ); + done(); + }); + })); + + test.skip('should support preventing navigation', () => + new Promise((done) => { + const reducer = (state = '', action: RouterAction) => { + if ( + action.type === ROUTER_NAVIGATION && + action.payload.routerState.url.toString() === '/next' + ) { + throw new Error('You shall not pass!'); + } else { + return state; + } + }; + + createTestModule({ reducers: { reducer } }); + + const router = TestBed.inject(Router); + const log = logOfRouterAndActionsAndStore(); + + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .catch((e) => { + expect(e.message).toEqual('You shall not pass!'); + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'router', event: 'NavigationError', url: '/next' }, + ]); + + done(); + }); + })); it('should ignore routing actions for the URL that is currently open', async () => { createTestModule({ @@ -177,7 +184,7 @@ describe('integration spec', () => { const router = TestBed.inject(Router); const store = TestBed.inject(Store); - const navigateByUrlSpy = jest.spyOn(router, 'navigateByUrl'); + const navigateByUrlSpy = vi.spyOn(router, 'navigateByUrl'); await router.navigateByUrl('/'); @@ -196,458 +203,465 @@ describe('integration spec', () => { expect(navigateByUrlSpy.mock.calls.length).toBe(1); }); - it('should support rolling back if navigation gets canceled (navigation initialized through router)', (done: any) => { - const reducer = (state = '', action: RouterAction): any => { - if (action.type === ROUTER_NAVIGATION) { - return { - url: action.payload.routerState.url.toString(), - lastAction: ROUTER_NAVIGATION, - }; - } else if (action.type === ROUTER_CANCEL) { - return { - url: action.payload.routerState.url.toString(), - storeState: action.payload.storeState.reducer, - lastAction: ROUTER_CANCEL, - }; - } else { - return state; - } - }; - - createTestModule({ - reducers: { reducer, routerReducer }, - canActivate: () => false, - }); - - const router = TestBed.inject(Router); - const log = logOfRouterAndActionsAndStore(); - - router - .navigateByUrl('/') - .then(() => { - log.splice(0); - return router.navigateByUrl('next'); - }) - .then((r) => { - expect(r).toEqual(false); + it('should support rolling back if navigation gets canceled (navigation initialized through router)', () => + new Promise((done) => { + const reducer = (state = '', action: RouterAction): any => { + if (action.type === ROUTER_NAVIGATION) { + return { + url: action.payload.routerState.url.toString(), + lastAction: ROUTER_NAVIGATION, + }; + } else if (action.type === ROUTER_CANCEL) { + return { + url: action.payload.routerState.url.toString(), + storeState: action.payload.storeState.reducer, + lastAction: ROUTER_CANCEL, + }; + } else { + return state; + } + }; - expect(log).toEqual([ - { - type: 'store', - state: { url: '/', lastAction: ROUTER_NAVIGATION }, - }, // ROUTER_REQUEST event in the store - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/next' }, - { - type: 'store', - state: { url: '/next', lastAction: ROUTER_NAVIGATION }, - }, - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, + createTestModule({ + reducers: { reducer, routerReducer }, + canActivate: () => false, + }); - /* new Router Lifecycle in Angular 4.3 - m */ - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, - // { type: 'router', event: 'ResolveStart', url: '/next' }, - // { type: 'router', event: 'ResolveEnd', url: '/next' }, - { - type: 'store', - state: { - url: '/', - lastAction: ROUTER_CANCEL, - storeState: { url: '/', lastAction: ROUTER_NAVIGATION }, + const router = TestBed.inject(Router); + const log = logOfRouterAndActionsAndStore(); + + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .then((r) => { + expect(r).toEqual(false); + + expect(log).toEqual([ + { + type: 'store', + state: { url: '/', lastAction: ROUTER_NAVIGATION }, + }, // ROUTER_REQUEST event in the store + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/next' }, + { + type: 'store', + state: { url: '/next', lastAction: ROUTER_NAVIGATION }, }, - }, - { type: 'action', action: ROUTER_CANCEL }, - { type: 'router', event: 'NavigationCancel', url: '/next' }, - ]); - - done(); - }); - }); + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + + /* new Router Lifecycle in Angular 4.3 - m */ + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, + // { type: 'router', event: 'ResolveStart', url: '/next' }, + // { type: 'router', event: 'ResolveEnd', url: '/next' }, + { + type: 'store', + state: { + url: '/', + lastAction: ROUTER_CANCEL, + storeState: { url: '/', lastAction: ROUTER_NAVIGATION }, + }, + }, + { type: 'action', action: ROUTER_CANCEL }, + { type: 'router', event: 'NavigationCancel', url: '/next' }, + ]); - it('should support rolling back if navigation gets canceled (navigation initialized through store)', (done: any) => { - const CHANGE_ROUTE = 'CHANGE_ROUTE'; - const reducer = ( - state: RouterReducerState, - action: any - ): RouterReducerState => { - if (action.type === CHANGE_ROUTE) { - return { - state: { url: '/next', root: {} }, - navigationId: 123, - }; - } else { - const nextState = routerReducer(state, action); - if (nextState && nextState.state) { + done(); + }); + })); + + it('should support rolling back if navigation gets canceled (navigation initialized through store)', () => + new Promise((done) => { + const CHANGE_ROUTE = 'CHANGE_ROUTE'; + const reducer = ( + state: RouterReducerState, + action: any + ): RouterReducerState => { + if (action.type === CHANGE_ROUTE) { return { - ...nextState, - state: { - ...nextState.state, - root: {} as any, - }, + state: { url: '/next', root: {} }, + navigationId: 123, }; + } else { + const nextState = routerReducer(state, action); + if (nextState && nextState.state) { + return { + ...nextState, + state: { + ...nextState.state, + root: {} as any, + }, + }; + } + return nextState; } - return nextState; - } - }; + }; - createTestModule({ - reducers: { reducer }, - canActivate: () => false, - config: { stateKey: 'reducer' }, - }); - - const router = TestBed.inject(Router); - const store = TestBed.inject(Store); - const log = logOfRouterAndActionsAndStore(); - - router - .navigateByUrl('/') - .then(() => { - log.splice(0); - store.dispatch({ type: CHANGE_ROUTE }); - return waitForNavigation(router, NavigationCancel); - }) - .then(() => { - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/next' }, - { - type: 'store', - state: { state: { url: '/next', root: {} }, navigationId: 123 }, - }, - { type: 'action', action: CHANGE_ROUTE }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, - { - type: 'store', - state: { state: { url: '/', root: {} }, navigationId: 2 }, - }, - { type: 'action', action: ROUTER_CANCEL }, - { type: 'router', event: 'NavigationCancel', url: '/next' }, - ]); - - done(); + createTestModule({ + reducers: { reducer }, + canActivate: () => false, + config: { stateKey: 'reducer' }, }); - }); - - it('should support rolling back if navigation errors (navigation initialized through router)', (done: any) => { - const reducer = (state = '', action: RouterAction): any => { - if (action.type === ROUTER_NAVIGATION) { - return { - url: action.payload.routerState.url.toString(), - lastAction: ROUTER_NAVIGATION, - }; - } else if (action.type === ROUTER_ERROR) { - return { - url: action.payload.routerState.url.toString(), - storeState: action.payload.storeState.reducer, - lastAction: ROUTER_ERROR, - }; - } else { - return state; - } - }; - - createTestModule({ - reducers: { reducer, routerReducer }, - canActivate: () => { - throw new Error('BOOM!'); - }, - }); - - const router = TestBed.inject(Router); - const log = logOfRouterAndActionsAndStore(); - router - .navigateByUrl('/') - .then(() => { - log.splice(0); - return router.navigateByUrl('next'); - }) - .catch((e) => { - expect(e.message).toEqual('BOOM!'); - - expect(log).toEqual([ - { - type: 'store', - state: { url: '/', lastAction: ROUTER_NAVIGATION }, - }, // ROUTER_REQUEST event in the store - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/next' }, - { - type: 'store', - state: { url: '/next', lastAction: ROUTER_NAVIGATION }, - }, - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - - /* new Router Lifecycle in Angular 4.3 */ - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - - { - type: 'store', - state: { - url: '/', - lastAction: ROUTER_ERROR, - storeState: { url: '/', lastAction: ROUTER_NAVIGATION }, + const router = TestBed.inject(Router); + const store = TestBed.inject(Store); + const log = logOfRouterAndActionsAndStore(); + + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + store.dispatch({ type: CHANGE_ROUTE }); + return waitForNavigation(router, NavigationCancel); + }) + .then(() => { + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/next' }, + { + type: 'store', + state: { state: { url: '/next', root: {} }, navigationId: 123 }, }, - }, - { type: 'action', action: ROUTER_ERROR }, - { type: 'router', event: 'NavigationError', url: '/next' }, - ]); + { type: 'action', action: CHANGE_ROUTE }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, + { + type: 'store', + state: { state: { url: '/', root: {} }, navigationId: 2 }, + }, + { type: 'action', action: ROUTER_CANCEL }, + { type: 'router', event: 'NavigationCancel', url: '/next' }, + ]); - done(); - }); - }); + done(); + }); + })); - it('should support rolling back if navigation errors and hand error to error handler (navigation initialized through store)', (done: any) => { - const CHANGE_ROUTE = 'CHANGE_ROUTE'; - const reducer = ( - state: RouterReducerState, - action: any - ): RouterReducerState => { - if (action.type === CHANGE_ROUTE) { - return { - state: { url: '/next', root: {} }, - navigationId: 123, - }; - } else { - const nextState = routerReducer(state, action); - if (nextState && nextState.state) { + it('should support rolling back if navigation errors (navigation initialized through router)', () => + new Promise((done) => { + const reducer = (state = '', action: RouterAction): any => { + if (action.type === ROUTER_NAVIGATION) { return { - ...nextState, - state: { - ...nextState.state, - root: {} as any, - }, + url: action.payload.routerState.url.toString(), + lastAction: ROUTER_NAVIGATION, }; + } else if (action.type === ROUTER_ERROR) { + return { + url: action.payload.routerState.url.toString(), + storeState: action.payload.storeState.reducer, + lastAction: ROUTER_ERROR, + }; + } else { + return state; } - return nextState; - } - }; + }; - const routerError = new Error('BOOM!'); - class SilentErrorHandler implements ErrorHandler { - handleError(error: any) { - expect(error).toBe(routerError); - } - } - - createTestModule({ - reducers: { reducer }, - canActivate: () => { - throw routerError; - }, - providers: [{ provide: ErrorHandler, useClass: SilentErrorHandler }], - config: { stateKey: 'reducer' }, - }); - - const router = TestBed.inject(Router); - const store = TestBed.inject(Store); - const log = logOfRouterAndActionsAndStore(); - - router - .navigateByUrl('/') - .then(() => { - log.splice(0); - store.dispatch({ type: CHANGE_ROUTE }); - return waitForNavigation(router, NavigationError); - }) - .then(() => { - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/next' }, - { - type: 'store', - state: { state: { url: '/next', root: {} }, navigationId: 123 }, - }, - { type: 'action', action: CHANGE_ROUTE }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - { - type: 'store', - state: { state: { url: '/', root: {} }, navigationId: 2 }, - }, - { type: 'action', action: ROUTER_ERROR }, - { type: 'router', event: 'NavigationError', url: '/next' }, - ]); - - done(); + createTestModule({ + reducers: { reducer, routerReducer }, + canActivate: () => { + throw new Error('BOOM!'); + }, }); - }); - - it('should call navigateByUrl when resetting state of the routerReducer', (done: any) => { - const reducer = (state: any, action: RouterAction) => { - const r = routerReducer(state, action); - return r && r.state - ? { url: r.state.url, navigationId: r.navigationId } - : null; - }; - - createTestModule({ reducers: { router: routerReducer, reducer } }); - - const router = TestBed.inject(Router); - const store = TestBed.inject(Store); - const log = logOfRouterAndActionsAndStore(); - - const routerReducerStates: any[] = []; - store.subscribe((state: any) => { - if (state.router) { - routerReducerStates.push(state.router); - } - }); - router - .navigateByUrl('/') - .then(() => { - log.splice(0); - return router.navigateByUrl('next'); - }) - .then(() => { - expect(log).toEqual([ - { type: 'store', state: null }, // ROUTER_REQUEST event in the store - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'store', state: { url: '/next', navigationId: 2 } }, - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - - /* new Router Lifecycle in Angular 4.3 */ - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, - { type: 'router', event: 'ResolveStart', url: '/next' }, - { type: 'router', event: 'ResolveEnd', url: '/next' }, - { type: 'store', state: null }, // ROUTER_NAVIGATED event in the store - { type: 'action', action: ROUTER_NAVIGATED }, - { type: 'router', event: 'NavigationEnd', url: '/next' }, - ]); - log.splice(0); - - store.dispatch({ - type: ROUTER_NAVIGATION, - payload: { - routerState: routerReducerStates[0].state, - event: { id: routerReducerStates[0].navigationId }, - }, - }); - return waitForNavigation(router); - }) - .then(() => { - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/' }, - { type: 'store', state: { url: '/', navigationId: 1 } }, // restored - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/' }, - - /* new Router Lifecycle in Angular 4.3 */ - { type: 'router', event: 'GuardsCheckStart', url: '/' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/' }, - { type: 'router', event: 'ResolveStart', url: '/' }, - { type: 'router', event: 'ResolveEnd', url: '/' }, + const router = TestBed.inject(Router); + const log = logOfRouterAndActionsAndStore(); + + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .catch((e) => { + expect(e.message).toEqual('BOOM!'); + + expect(log).toEqual([ + { + type: 'store', + state: { url: '/', lastAction: ROUTER_NAVIGATION }, + }, // ROUTER_REQUEST event in the store + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/next' }, + { + type: 'store', + state: { url: '/next', lastAction: ROUTER_NAVIGATION }, + }, + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + + /* new Router Lifecycle in Angular 4.3 */ + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + + { + type: 'store', + state: { + url: '/', + lastAction: ROUTER_ERROR, + storeState: { url: '/', lastAction: ROUTER_NAVIGATION }, + }, + }, + { type: 'action', action: ROUTER_ERROR }, + { type: 'router', event: 'NavigationError', url: '/next' }, + ]); - { type: 'router', event: 'NavigationEnd', url: '/' }, - ]); - log.splice(0); - }) - .then(() => { - store.dispatch({ - type: ROUTER_NAVIGATION, - payload: { - routerState: routerReducerStates[3].state, - event: { id: routerReducerStates[3].navigationId }, - }, + done(); }); - return waitForNavigation(router); - }) - .then(() => { - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'store', state: { url: '/next', navigationId: 2 } }, // restored - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, + })); + + it('should support rolling back if navigation errors and hand error to error handler (navigation initialized through store)', () => + new Promise((done) => { + const CHANGE_ROUTE = 'CHANGE_ROUTE'; + const reducer = ( + state: RouterReducerState, + action: any + ): RouterReducerState => { + if (action.type === CHANGE_ROUTE) { + return { + state: { url: '/next', root: {} }, + navigationId: 123, + }; + } else { + const nextState = routerReducer(state, action); + if (nextState && nextState.state) { + return { + ...nextState, + state: { + ...nextState.state, + root: {} as any, + }, + }; + } + return nextState; + } + }; - /* new Router Lifecycle in Angular 4.3 */ - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, - { type: 'router', event: 'ResolveStart', url: '/next' }, - { type: 'router', event: 'ResolveEnd', url: '/next' }, + const routerError = new Error('BOOM!'); + class SilentErrorHandler implements ErrorHandler { + handleError(error: any) { + expect(error).toBe(routerError); + } + } - { type: 'router', event: 'NavigationEnd', url: '/next' }, - ]); - done(); + createTestModule({ + reducers: { reducer }, + canActivate: () => { + throw routerError; + }, + providers: [{ provide: ErrorHandler, useClass: SilentErrorHandler }], + config: { stateKey: 'reducer' }, }); - }); - - it('should support cancellation of initial navigation using canLoad guard', (done: any) => { - const reducer = (state: any, action: RouterAction) => { - const r = routerReducer(state, action); - return r && r.state - ? { url: r.state.url, navigationId: r.navigationId } - : null; - }; - createTestModule({ - reducers: { routerReducer, reducer }, - canLoad: () => false, - }); + const router = TestBed.inject(Router); + const store = TestBed.inject(Store); + const log = logOfRouterAndActionsAndStore(); + + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + store.dispatch({ type: CHANGE_ROUTE }); + return waitForNavigation(router, NavigationError); + }) + .then(() => { + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/next' }, + { + type: 'store', + state: { state: { url: '/next', root: {} }, navigationId: 123 }, + }, + { type: 'action', action: CHANGE_ROUTE }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + { + type: 'store', + state: { state: { url: '/', root: {} }, navigationId: 2 }, + }, + { type: 'action', action: ROUTER_ERROR }, + { type: 'router', event: 'NavigationError', url: '/next' }, + ]); - const router = TestBed.inject(Router); - const log = logOfRouterAndActionsAndStore(); + done(); + }); + })); + + it('should call navigateByUrl when resetting state of the routerReducer', () => + new Promise((done) => { + const reducer = (state: any, action: RouterAction) => { + const r = routerReducer(state, action); + return r && r.state + ? { url: r.state.url, navigationId: r.navigationId } + : null; + }; + + createTestModule({ reducers: { router: routerReducer, reducer } }); + + const router = TestBed.inject(Router); + const store = TestBed.inject(Store); + const log = logOfRouterAndActionsAndStore(); + + const routerReducerStates: any[] = []; + store.subscribe((state: any) => { + if (state.router) { + routerReducerStates.push(state.router); + } + }); - router.navigateByUrl('/load').then((r: boolean) => { - expect(r).toBe(false); - - expect(log).toEqual([ - { type: 'store', state: null }, // initial state - { type: 'store', state: null }, // ROUTER_REQUEST event in the store - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/load' }, - { type: 'store', state: { url: '', navigationId: 1 } }, - { type: 'action', action: ROUTER_CANCEL }, - { type: 'router', event: 'NavigationCancel', url: '/load' }, - ]); - done(); - }); - }); + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .then(() => { + expect(log).toEqual([ + { type: 'store', state: null }, // ROUTER_REQUEST event in the store + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'store', state: { url: '/next', navigationId: 2 } }, + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + + /* new Router Lifecycle in Angular 4.3 */ + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, + { type: 'router', event: 'ResolveStart', url: '/next' }, + { type: 'router', event: 'ResolveEnd', url: '/next' }, + { type: 'store', state: null }, // ROUTER_NAVIGATED event in the store + { type: 'action', action: ROUTER_NAVIGATED }, + { type: 'router', event: 'NavigationEnd', url: '/next' }, + ]); + log.splice(0); + + store.dispatch({ + type: ROUTER_NAVIGATION, + payload: { + routerState: routerReducerStates[0].state, + event: { id: routerReducerStates[0].navigationId }, + }, + }); + return waitForNavigation(router); + }) + .then(() => { + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/' }, + { type: 'store', state: { url: '/', navigationId: 1 } }, // restored + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/' }, + + /* new Router Lifecycle in Angular 4.3 */ + { type: 'router', event: 'GuardsCheckStart', url: '/' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/' }, + { type: 'router', event: 'ResolveStart', url: '/' }, + { type: 'router', event: 'ResolveEnd', url: '/' }, + + { type: 'router', event: 'NavigationEnd', url: '/' }, + ]); + log.splice(0); + }) + .then(() => { + store.dispatch({ + type: ROUTER_NAVIGATION, + payload: { + routerState: routerReducerStates[3].state, + event: { id: routerReducerStates[3].navigationId }, + }, + }); + return waitForNavigation(router); + }) + .then(() => { + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'store', state: { url: '/next', navigationId: 2 } }, // restored + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + + /* new Router Lifecycle in Angular 4.3 */ + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, + { type: 'router', event: 'ResolveStart', url: '/next' }, + { type: 'router', event: 'ResolveEnd', url: '/next' }, + + { type: 'router', event: 'NavigationEnd', url: '/next' }, + ]); + done(); + }); + })); - it('should support cancellation of initial navigation when canLoad guard rejects', (done: any) => { - const reducer = (state: any, action: RouterAction) => { - const r = routerReducer(state, action); - return r && r.state - ? { url: r.state.url, navigationId: r.navigationId } - : null; - }; + it('should support cancellation of initial navigation using canLoad guard', () => + new Promise((done) => { + const reducer = (state: any, action: RouterAction) => { + const r = routerReducer(state, action); + return r && r.state + ? { url: r.state.url, navigationId: r.navigationId } + : null; + }; - createTestModule({ - reducers: { routerReducer, reducer }, - canLoad: () => Promise.reject('boom'), - }); + createTestModule({ + reducers: { routerReducer, reducer }, + canLoad: () => false, + }); - const router = TestBed.inject(Router); - const log = logOfRouterAndActionsAndStore(); + const router = TestBed.inject(Router); + const log = logOfRouterAndActionsAndStore(); - router - .navigateByUrl('/load') - .then(() => { - fail(`Shouldn't be called`); - }) - .catch((err) => { - expect(err).toBe('boom'); + router.navigateByUrl('/load').then((r: boolean) => { + expect(r).toBe(false); expect(log).toEqual([ { type: 'store', state: null }, // initial state - { type: 'store', state: null }, // ROUTER_REQEST event in the store + { type: 'store', state: null }, // ROUTER_REQUEST event in the store { type: 'action', action: ROUTER_REQUEST }, { type: 'router', event: 'NavigationStart', url: '/load' }, { type: 'store', state: { url: '', navigationId: 1 } }, - { type: 'action', action: ROUTER_ERROR }, - { type: 'router', event: 'NavigationError', url: '/load' }, + { type: 'action', action: ROUTER_CANCEL }, + { type: 'router', event: 'NavigationCancel', url: '/load' }, ]); - done(); }); - }); + })); + + it('should support cancellation of initial navigation when canLoad guard rejects', () => + new Promise((done) => { + const reducer = (state: any, action: RouterAction) => { + const r = routerReducer(state, action); + return r && r.state + ? { url: r.state.url, navigationId: r.navigationId } + : null; + }; + + createTestModule({ + reducers: { routerReducer, reducer }, + canLoad: () => Promise.reject('boom'), + }); + + const router = TestBed.inject(Router); + const log = logOfRouterAndActionsAndStore(); + + router + .navigateByUrl('/load') + .then(() => { + fail(`Shouldn't be called`); + }) + .catch((err) => { + expect(err).toBe('boom'); + + expect(log).toEqual([ + { type: 'store', state: null }, // initial state + { type: 'store', state: null }, // ROUTER_REQEST event in the store + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/load' }, + { type: 'store', state: { url: '', navigationId: 1 } }, + { type: 'action', action: ROUTER_ERROR }, + { type: 'router', event: 'NavigationError', url: '/load' }, + ]); + + done(); + }); + })); function shouldSupportCustomSerializer( serializerThroughConfig: boolean, @@ -735,280 +749,290 @@ describe('integration spec', () => { }); } - it('should support a custom RouterStateSnapshot serializer via provider', (done: any) => { - shouldSupportCustomSerializer(false, done); - }); - - it('should support a custom RouterStateSnapshot serializer via config', (done: any) => { - shouldSupportCustomSerializer(true, done); - }); + it('should support a custom RouterStateSnapshot serializer via provider', () => + new Promise((done) => { + shouldSupportCustomSerializer(false, done); + })); - it('should support event during an async canActivate guard', (done: any) => { - createTestModule({ - reducers: { routerReducer }, - canActivate: () => { - store.dispatch({ type: 'USER_EVENT' }); - return store.pipe( - take(1), - map(() => true) - ); - }, - }); + it('should support a custom RouterStateSnapshot serializer via config', () => + new Promise((done) => { + shouldSupportCustomSerializer(true, done); + })); - const router = TestBed.inject(Router); - const store = TestBed.inject(Store); - const log = logOfRouterAndActionsAndStore(); + it('should support event during an async canActivate guard', () => + new Promise((done) => { + createTestModule({ + reducers: { routerReducer }, + canActivate: () => { + store.dispatch({ type: 'USER_EVENT' }); + return store.pipe( + take(1), + map(() => true) + ); + }, + }); - router - .navigateByUrl('/') - .then(() => { - log.splice(0); - return router.navigateByUrl('next'); - }) - .then(() => { - expect(log).toEqual([ - { type: 'store', state: undefined }, // after ROUTER_REQUEST - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'store', state: undefined }, // after ROUTER_NAVIGATION - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - /* new Router Lifecycle in Angular 4.3 */ - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - { type: 'store', state: undefined }, // after USER_EVENT - { type: 'action', action: 'USER_EVENT' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, - { type: 'router', event: 'ResolveStart', url: '/next' }, - { type: 'router', event: 'ResolveEnd', url: '/next' }, - { type: 'store', state: undefined }, // after ROUTER_NAVIGATED - { type: 'action', action: ROUTER_NAVIGATED }, - { type: 'router', event: 'NavigationEnd', url: '/next' }, - ]); + const router = TestBed.inject(Router); + const store = TestBed.inject(Store); + const log = logOfRouterAndActionsAndStore(); + + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .then(() => { + expect(log).toEqual([ + { type: 'store', state: undefined }, // after ROUTER_REQUEST + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'store', state: undefined }, // after ROUTER_NAVIGATION + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + /* new Router Lifecycle in Angular 4.3 */ + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + { type: 'store', state: undefined }, // after USER_EVENT + { type: 'action', action: 'USER_EVENT' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, + { type: 'router', event: 'ResolveStart', url: '/next' }, + { type: 'router', event: 'ResolveEnd', url: '/next' }, + { type: 'store', state: undefined }, // after ROUTER_NAVIGATED + { type: 'action', action: ROUTER_NAVIGATED }, + { type: 'router', event: 'NavigationEnd', url: '/next' }, + ]); + + done(); + }); + })); + + it('should work when defining state key', () => + new Promise((done) => { + const reducer = (state = '', action: RouterAction) => { + if (action.type === ROUTER_NAVIGATION) { + return action.payload.routerState.url.toString(); + } else { + return state; + } + }; - done(); + createTestModule({ + reducers: { 'router-reducer': reducer }, + config: { stateKey: 'router-reducer' }, }); - }); - it('should work when defining state key', (done: any) => { - const reducer = (state = '', action: RouterAction) => { - if (action.type === ROUTER_NAVIGATION) { - return action.payload.routerState.url.toString(); - } else { - return state; - } - }; + const router = TestBed.inject(Router); + const log = logOfRouterAndActionsAndStore({ stateKey: 'router-reducer' }); + + router + .navigateByUrl('/') + .then(() => { + expect(log).toEqual([ + { type: 'store', state: '' }, // init event. has nothing to do with the router + { type: 'store', state: '' }, // ROUTER_REQUEST event in the store + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/' }, + { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/' }, + { type: 'router', event: 'GuardsCheckStart', url: '/' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/' }, + { type: 'router', event: 'ResolveStart', url: '/' }, + { type: 'router', event: 'ResolveEnd', url: '/' }, + { type: 'store', state: '/' }, // ROUTER_NAVIGATED event in the store + { type: 'action', action: ROUTER_NAVIGATED }, + { type: 'router', event: 'NavigationEnd', url: '/' }, + ]); + }) + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .then(() => { + expect(log).toEqual([ + { type: 'store', state: '/' }, + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'store', state: '/next' }, + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, + { type: 'router', event: 'ResolveStart', url: '/next' }, + { type: 'router', event: 'ResolveEnd', url: '/next' }, + { type: 'store', state: '/next' }, + { type: 'action', action: ROUTER_NAVIGATED }, + { type: 'router', event: 'NavigationEnd', url: '/next' }, + ]); + + done(); + }); + })); + + it('should work when defining state selector', () => + new Promise((done) => { + const reducer = (state = '', action: RouterAction) => { + if (action.type === ROUTER_NAVIGATION) { + return action.payload.routerState.url.toString(); + } else { + return state; + } + }; - createTestModule({ - reducers: { 'router-reducer': reducer }, - config: { stateKey: 'router-reducer' }, - }); + createTestModule({ + reducers: { routerReducer: reducer }, + config: { stateKey: (state: any) => state.routerReducer }, + }); - const router = TestBed.inject(Router); - const log = logOfRouterAndActionsAndStore({ stateKey: 'router-reducer' }); + const router = TestBed.inject(Router); + const log = logOfRouterAndActionsAndStore({ + stateKey: (state: any) => state.routerReducer, + }); - router - .navigateByUrl('/') - .then(() => { - expect(log).toEqual([ - { type: 'store', state: '' }, // init event. has nothing to do with the router - { type: 'store', state: '' }, // ROUTER_REQUEST event in the store - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/' }, - { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/' }, - { type: 'router', event: 'GuardsCheckStart', url: '/' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/' }, - { type: 'router', event: 'ResolveStart', url: '/' }, - { type: 'router', event: 'ResolveEnd', url: '/' }, - { type: 'store', state: '/' }, // ROUTER_NAVIGATED event in the store - { type: 'action', action: ROUTER_NAVIGATED }, - { type: 'router', event: 'NavigationEnd', url: '/' }, - ]); - }) - .then(() => { - log.splice(0); - return router.navigateByUrl('next'); - }) - .then(() => { - expect(log).toEqual([ - { type: 'store', state: '/' }, - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'store', state: '/next' }, - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, - { type: 'router', event: 'ResolveStart', url: '/next' }, - { type: 'router', event: 'ResolveEnd', url: '/next' }, - { type: 'store', state: '/next' }, - { type: 'action', action: ROUTER_NAVIGATED }, - { type: 'router', event: 'NavigationEnd', url: '/next' }, - ]); + router + .navigateByUrl('/') + .then(() => { + expect(log).toEqual([ + { type: 'store', state: '' }, // init event. has nothing to do with the router + { type: 'store', state: '' }, // ROUTER_REQUEST event in the store + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/' }, + { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/' }, + { type: 'router', event: 'GuardsCheckStart', url: '/' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/' }, + { type: 'router', event: 'ResolveStart', url: '/' }, + { type: 'router', event: 'ResolveEnd', url: '/' }, + { type: 'store', state: '/' }, // ROUTER_NAVIGATED event in the store + { type: 'action', action: ROUTER_NAVIGATED }, + { type: 'router', event: 'NavigationEnd', url: '/' }, + ]); + }) + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .then(() => { + expect(log).toEqual([ + { type: 'store', state: '/' }, + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'store', state: '/next' }, + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, + { type: 'router', event: 'ResolveStart', url: '/next' }, + { type: 'router', event: 'ResolveEnd', url: '/next' }, + { type: 'store', state: '/next' }, + { type: 'action', action: ROUTER_NAVIGATED }, + { type: 'router', event: 'NavigationEnd', url: '/next' }, + ]); + + done(); + }); + })); + + it('should continue to react to navigation after state initiates router change', () => + new Promise((done) => { + const reducer = (state: any = { state: { url: '/' } }, action: any) => { + if (action.type === ROUTER_NAVIGATION) { + return { state: { url: action.payload.routerState.url.toString() } }; + } else { + return state; + } + }; - done(); + createTestModule({ + reducers: { reducer }, + config: { stateKey: 'reducer' }, }); - }); - it('should work when defining state selector', (done: any) => { - const reducer = (state = '', action: RouterAction) => { - if (action.type === ROUTER_NAVIGATION) { - return action.payload.routerState.url.toString(); - } else { - return state; - } - }; + const router = TestBed.inject(Router); + const store = TestBed.inject(Store); + const log = logOfRouterAndActionsAndStore(); - createTestModule({ - reducers: { routerReducer: reducer }, - config: { stateKey: (state: any) => state.routerReducer }, - }); + store.dispatch({ + type: ROUTER_NAVIGATION, + payload: { routerState: { url: '/next' } }, + }); + waitForNavigation(router) + .then(() => { + router.navigate(['/']); + return waitForNavigation(router); + }) + .then(() => { + expect(log).toEqual([ + { type: 'store', state: { state: { url: '/' } } }, + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'store', state: { state: { url: '/next' } } }, + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'router', event: 'GuardsCheckStart', url: '/next' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, + { type: 'router', event: 'ResolveStart', url: '/next' }, + { type: 'router', event: 'ResolveEnd', url: '/next' }, + { type: 'router', event: 'NavigationEnd', url: '/next' }, + { type: 'store', state: { state: { url: '/next' } } }, + { type: 'action', action: ROUTER_REQUEST }, + { type: 'router', event: 'NavigationStart', url: '/' }, + { type: 'store', state: { state: { url: '/' } } }, + { type: 'action', action: ROUTER_NAVIGATION }, + { type: 'router', event: 'RoutesRecognized', url: '/' }, + { type: 'router', event: 'GuardsCheckStart', url: '/' }, + { type: 'router', event: 'GuardsCheckEnd', url: '/' }, + { type: 'router', event: 'ResolveStart', url: '/' }, + { type: 'router', event: 'ResolveEnd', url: '/' }, + { type: 'store', state: { state: { url: '/' } } }, + { type: 'action', action: ROUTER_NAVIGATED }, + { type: 'router', event: 'NavigationEnd', url: '/' }, + ]); + done(); + }); + })); + + it('should dispatch ROUTER_NAVIGATION later when config options set to true', () => + new Promise((done) => { + const reducer = (state = '', action: RouterAction) => { + if (action.type === ROUTER_NAVIGATION) { + return action.payload.routerState.url.toString(); + } else { + return state; + } + }; - const router = TestBed.inject(Router); - const log = logOfRouterAndActionsAndStore({ - stateKey: (state: any) => state.routerReducer, - }); + createTestModule({ + reducers: { reducer }, + config: { + navigationActionTiming: NavigationActionTiming.PostActivation, + }, + }); - router - .navigateByUrl('/') - .then(() => { + const router = TestBed.inject(Router); + const log = logOfRouterAndActionsAndStore(); + + router.navigateByUrl('/').then(() => { expect(log).toEqual([ { type: 'store', state: '' }, // init event. has nothing to do with the router { type: 'store', state: '' }, // ROUTER_REQUEST event in the store { type: 'action', action: ROUTER_REQUEST }, { type: 'router', event: 'NavigationStart', url: '/' }, - { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store - { type: 'action', action: ROUTER_NAVIGATION }, { type: 'router', event: 'RoutesRecognized', url: '/' }, + /* new Router Lifecycle in Angular 4.3 */ { type: 'router', event: 'GuardsCheckStart', url: '/' }, { type: 'router', event: 'GuardsCheckEnd', url: '/' }, { type: 'router', event: 'ResolveStart', url: '/' }, { type: 'router', event: 'ResolveEnd', url: '/' }, - { type: 'store', state: '/' }, // ROUTER_NAVIGATED event in the store - { type: 'action', action: ROUTER_NAVIGATED }, - { type: 'router', event: 'NavigationEnd', url: '/' }, - ]); - }) - .then(() => { - log.splice(0); - return router.navigateByUrl('next'); - }) - .then(() => { - expect(log).toEqual([ - { type: 'store', state: '/' }, - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'store', state: '/next' }, - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, - { type: 'router', event: 'ResolveStart', url: '/next' }, - { type: 'router', event: 'ResolveEnd', url: '/next' }, - { type: 'store', state: '/next' }, - { type: 'action', action: ROUTER_NAVIGATED }, - { type: 'router', event: 'NavigationEnd', url: '/next' }, - ]); - - done(); - }); - }); - - it('should continue to react to navigation after state initiates router change', (done: Function) => { - const reducer = (state: any = { state: { url: '/' } }, action: any) => { - if (action.type === ROUTER_NAVIGATION) { - return { state: { url: action.payload.routerState.url.toString() } }; - } else { - return state; - } - }; - - createTestModule({ - reducers: { reducer }, - config: { stateKey: 'reducer' }, - }); - - const router = TestBed.inject(Router); - const store = TestBed.inject(Store); - const log = logOfRouterAndActionsAndStore(); - - store.dispatch({ - type: ROUTER_NAVIGATION, - payload: { routerState: { url: '/next' } }, - }); - waitForNavigation(router) - .then(() => { - router.navigate(['/']); - return waitForNavigation(router); - }) - .then(() => { - expect(log).toEqual([ - { type: 'store', state: { state: { url: '/' } } }, - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'store', state: { state: { url: '/next' } } }, - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'router', event: 'GuardsCheckStart', url: '/next' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/next' }, - { type: 'router', event: 'ResolveStart', url: '/next' }, - { type: 'router', event: 'ResolveEnd', url: '/next' }, - { type: 'router', event: 'NavigationEnd', url: '/next' }, - { type: 'store', state: { state: { url: '/next' } } }, - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/' }, - { type: 'store', state: { state: { url: '/' } } }, + { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'router', event: 'RoutesRecognized', url: '/' }, - { type: 'router', event: 'GuardsCheckStart', url: '/' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/' }, - { type: 'router', event: 'ResolveStart', url: '/' }, - { type: 'router', event: 'ResolveEnd', url: '/' }, - { type: 'store', state: { state: { url: '/' } } }, + { type: 'store', state: '/' }, // ROUTER_NAVIGATED event in the store { type: 'action', action: ROUTER_NAVIGATED }, { type: 'router', event: 'NavigationEnd', url: '/' }, ]); done(); }); - }); - - it('should dispatch ROUTER_NAVIGATION later when config options set to true', () => { - const reducer = (state = '', action: RouterAction) => { - if (action.type === ROUTER_NAVIGATION) { - return action.payload.routerState.url.toString(); - } else { - return state; - } - }; - - createTestModule({ - reducers: { reducer }, - config: { navigationActionTiming: NavigationActionTiming.PostActivation }, - }); - - const router = TestBed.inject(Router); - const log = logOfRouterAndActionsAndStore(); - - router.navigateByUrl('/').then(() => { - expect(log).toEqual([ - { type: 'store', state: '' }, // init event. has nothing to do with the router - { type: 'store', state: '' }, // ROUTER_REQUEST event in the store - { type: 'action', action: ROUTER_REQUEST }, - { type: 'router', event: 'NavigationStart', url: '/' }, - { type: 'router', event: 'RoutesRecognized', url: '/' }, - /* new Router Lifecycle in Angular 4.3 */ - { type: 'router', event: 'GuardsCheckStart', url: '/' }, - { type: 'router', event: 'GuardsCheckEnd', url: '/' }, - { type: 'router', event: 'ResolveStart', url: '/' }, - { type: 'router', event: 'ResolveEnd', url: '/' }, - { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store - { type: 'action', action: ROUTER_NAVIGATION }, - { type: 'store', state: '/' }, // ROUTER_NAVIGATED event in the store - { type: 'action', action: ROUTER_NAVIGATED }, - { type: 'router', event: 'NavigationEnd', url: '/' }, - ]); - }); - }); + })); }); function waitForNavigation(router: Router, event: any = NavigationEnd) { diff --git a/modules/router-store/spec/router_store_module.spec.ts b/modules/router-store/spec/router_store_module.spec.ts index 6cbb5d8b75..b473b1feca 100644 --- a/modules/router-store/spec/router_store_module.spec.ts +++ b/modules/router-store/spec/router_store_module.spec.ts @@ -47,32 +47,29 @@ describe('Router Store Module', () => { expect((storeRouterConnectingService).stateKey).toBe(customStateKey); }); - it('should call navigateIfNeeded with args selected by custom state key', (done: any) => { - let logs: any[] = []; - store - .pipe(select(customStateKey), withLatestFrom(store)) - .subscribe(([routerStoreState, storeState]) => { - logs.push([routerStoreState, storeState]); - }); + it('should call navigateIfNeeded with args selected by custom state key', () => + new Promise((done) => { + let logs: any[] = []; + store + .pipe(select(customStateKey), withLatestFrom(store)) + .subscribe(([routerStoreState, storeState]) => { + logs.push([routerStoreState, storeState]); + }); - spyOn( - storeRouterConnectingService, - 'navigateIfNeeded' as never - ).and.callThrough(); - logs = []; - - // this dispatches `@ngrx/router-store/navigation` action - // and store emits its payload. - router.navigateByUrl('/').then(() => { - const actual = (( - storeRouterConnectingService - )).navigateIfNeeded.calls.allArgs(); - - expect(actual.length).toBe(1); - expect(actual[0]).toEqual(logs[0]); - done(); - }); - }); + vi.spyOn(storeRouterConnectingService, 'navigateIfNeeded' as never); + logs = []; + + // this dispatches `@ngrx/router-store/navigation` action + // and store emits its payload. + router.navigateByUrl('/').then(() => { + const actual = (storeRouterConnectingService).navigateIfNeeded + .mock.calls; + + expect(actual.length).toBe(1); + expect(actual[0]).toEqual(logs[0]); + done(); + }); + })); }); describe('with defining state selector', () => { @@ -110,32 +107,29 @@ describe('Router Store Module', () => { ); }); - it('should call navigateIfNeeded with args selected by custom state selector', (done: any) => { - let logs: any[] = []; - store - .pipe(select(customStateSelector), withLatestFrom(store)) - .subscribe(([routerStoreState, storeState]) => { - logs.push([routerStoreState, storeState]); - }); + it('should call navigateIfNeeded with args selected by custom state selector', () => + new Promise((done) => { + let logs: any[] = []; + store + .pipe(select(customStateSelector), withLatestFrom(store)) + .subscribe(([routerStoreState, storeState]) => { + logs.push([routerStoreState, storeState]); + }); - spyOn( - storeRouterConnectingService, - 'navigateIfNeeded' as never - ).and.callThrough(); - logs = []; - - // this dispatches `@ngrx/router-store/navigation` action - // and store emits its payload. - router.navigateByUrl('/').then(() => { - const actual = (( - storeRouterConnectingService - )).navigateIfNeeded.calls.allArgs(); - - expect(actual.length).toBe(1); - expect(actual[0]).toEqual(logs[0]); - done(); - }); - }); + vi.spyOn(storeRouterConnectingService, 'navigateIfNeeded' as never); + logs = []; + + // this dispatches `@ngrx/router-store/navigation` action + // and store emits its payload. + router.navigateByUrl('/').then(() => { + const actual = (storeRouterConnectingService).navigateIfNeeded + .mock.calls; + + expect(actual.length).toBe(1); + expect(actual[0]).toEqual(logs[0]); + done(); + }); + })); }); describe('routerState', () => { @@ -159,15 +153,16 @@ describe('Router Store Module', () => { a.payload && a.payload.event; describe('Full', () => { - it('should dispatch the full event', (done: any) => { - const { actions, router } = setup(RouterState.Full); - actions.pipe(filter(onlyRouterActions)).subscribe(({ payload }) => { - expect(payload.event instanceof RouterEvent).toBe(true); - done(); - }); + it('should dispatch the full event', () => + new Promise((done) => { + const { actions, router } = setup(RouterState.Full); + actions.pipe(filter(onlyRouterActions)).subscribe(({ payload }) => { + expect(payload.event instanceof RouterEvent).toBe(true); + done(); + }); - router.navigateByUrl('/'); - }); + router.navigateByUrl('/'); + })); it('should use the default router serializer by default', () => { const { serializer } = setup(); @@ -194,42 +189,44 @@ describe('Router Store Module', () => { }); describe('Minimal', () => { - it('should dispatch the navigation id with url', (done: any) => { - const { actions, router } = setup(RouterState.Minimal); - actions - .pipe(filter(onlyRouterActions)) - .subscribe(({ payload }: any) => { - expect(payload.event instanceof RouterEvent).toBe(false); - expect(payload.event).toEqual({ id: 1, url: '/' }); - done(); - }); - - router.navigateByUrl('/'); - }); + it('should dispatch the navigation id with url', () => + new Promise((done) => { + const { actions, router } = setup(RouterState.Minimal); + actions + .pipe(filter(onlyRouterActions)) + .subscribe(({ payload }: any) => { + expect(payload.event instanceof RouterEvent).toBe(false); + expect(payload.event).toEqual({ id: 1, url: '/' }); + done(); + }); - it('should dispatch the navigation with urlAfterRedirects', (done: any) => { - const { actions, router } = setup(RouterState.Minimal); - actions - .pipe( - filter(onlyRouterActions), - // wait until NavigationEnd router event - filter( - ({ payload }) => - !!(payload.event as NavigationEnd).urlAfterRedirects + router.navigateByUrl('/'); + })); + + it('should dispatch the navigation with urlAfterRedirects', () => + new Promise((done) => { + const { actions, router } = setup(RouterState.Minimal); + actions + .pipe( + filter(onlyRouterActions), + // wait until NavigationEnd router event + filter( + ({ payload }) => + !!(payload.event as NavigationEnd).urlAfterRedirects + ) ) - ) - .subscribe(({ payload }: any) => { - expect(payload.event instanceof RouterEvent).toBe(false); - expect(payload.event).toEqual({ - id: 1, - url: '/redirect', - urlAfterRedirects: '/next', + .subscribe(({ payload }: any) => { + expect(payload.event instanceof RouterEvent).toBe(false); + expect(payload.event).toEqual({ + id: 1, + url: '/redirect', + urlAfterRedirects: '/next', + }); + done(); }); - done(); - }); - router.navigateByUrl('/redirect'); - }); + router.navigateByUrl('/redirect'); + })); it('should use the minimal router serializer', () => { const { serializer } = setup(RouterState.Minimal); diff --git a/modules/router-store/spec/utils.ts b/modules/router-store/spec/utils.ts index fb5eea20aa..3470214255 100644 --- a/modules/router-store/spec/utils.ts +++ b/modules/router-store/spec/utils.ts @@ -5,6 +5,7 @@ import { StoreModule } from '@ngrx/store'; import { StoreRouterConfig, StoreRouterConnectingModule } from '../src'; import { RouterOutlet } from '@angular/router'; +import { vi } from 'vitest'; export function createTestModule( opts: { @@ -63,8 +64,8 @@ export function createTestModule( { provide: Console, useValue: { - log: jasmine.createSpy('Console.log'), - warn: jasmine.createSpy('Console.warn'), + log: vi.fn(), + warn: vi.fn(), }, }, opts.providers || [], diff --git a/modules/router-store/test-setup.ts b/modules/router-store/test-setup.ts index 04187448f9..3512059d4b 100644 --- a/modules/router-store/test-setup.ts +++ b/modules/router-store/test-setup.ts @@ -1,4 +1,33 @@ -import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; +import { + TextEncoder as NodeTextEncoder, + TextDecoder as NodeTextDecoder, +} from 'util'; -setupZoneTestEnv(); -Object.assign(global, { TextDecoder, TextEncoder }); +// Only assign if not already defined, using type assertion to satisfy TypeScript +if (typeof globalThis.TextEncoder === 'undefined') { + globalThis.TextEncoder = NodeTextEncoder as unknown as { + new (): TextEncoder; + prototype: TextEncoder; + }; +} + +if (typeof globalThis.TextDecoder === 'undefined') { + globalThis.TextDecoder = NodeTextDecoder as unknown as { + new (): TextDecoder; + prototype: TextDecoder; + }; +} + +import '@angular/compiler'; +import '@analogjs/vitest-angular/setup-zone'; + +import { + BrowserTestingModule, + platformBrowserTesting, +} from '@angular/platform-browser/testing'; +import { getTestBed } from '@angular/core/testing'; + +getTestBed().initTestEnvironment( + BrowserTestingModule, + platformBrowserTesting() +); diff --git a/modules/router-store/tsconfig.schematics.json b/modules/router-store/tsconfig.schematics.json index c7a9329378..bfa644995e 100644 --- a/modules/router-store/tsconfig.schematics.json +++ b/modules/router-store/tsconfig.schematics.json @@ -4,8 +4,9 @@ "rootDir": ".", "stripInternal": true, "experimentalDecorators": true, - "module": "preserve", - "moduleResolution": "bundler", + "module": "nodenext", + "target": "es2022", + "moduleResolution": "nodenext", "downlevelIteration": true, "outDir": "../../dist/modules/router-store", "paths": { diff --git a/modules/router-store/tsconfig.spec.json b/modules/router-store/tsconfig.spec.json index dcb4681eef..ba963ae942 100644 --- a/modules/router-store/tsconfig.spec.json +++ b/modules/router-store/tsconfig.spec.json @@ -2,10 +2,10 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"], + "module": "es2022", + "types": ["node", "vitest", "vitest/globals"], "target": "es2016" }, "files": ["test-setup.ts"], - "include": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts", "**/*.d.ts"] + "include": ["**/*.spec.ts", "**/*.test.ts", "**/*.d.ts"] } diff --git a/modules/router-store/vite.config.mts b/modules/router-store/vite.config.mts new file mode 100644 index 0000000000..fa49854dbf --- /dev/null +++ b/modules/router-store/vite.config.mts @@ -0,0 +1,29 @@ +/// + +import angular from '@analogjs/vite-plugin-angular'; + +import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; + +import { defineConfig } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig(({ mode }) => { + return { + root: __dirname, + plugins: [ + angular(), + nxViteTsPaths(), + ], + test: { + globals: true, + pool: 'forks', + environment: 'jsdom', + setupFiles: ['test-setup.ts'], + include: ['**/*.spec.ts'], + reporters: ['default'] + }, + define: { + 'import.meta.vitest': mode !== 'production', + }, + }; +});