diff --git a/modules/store/eslint.config.mjs b/modules/store/eslint.config.mjs index 0f56636e0b..410c851e5b 100644 --- a/modules/store/eslint.config.mjs +++ b/modules/store/eslint.config.mjs @@ -13,7 +13,6 @@ export default [ { ignores: [ '**/dist', - '**/jest.config.ts', '**/schematics-core/**/*.ts', ], }, diff --git a/modules/store/jest.config.ts b/modules/store/jest.config.ts deleted file mode 100644 index 7426c4a3e3..0000000000 --- a/modules/store/jest.config.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'Store', - preset: '../../jest.preset.js', - coverageDirectory: '../../coverage/modules/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', - moduleNameMapper: { - '^rxjs(/operators$)?$': - '../../node_modules/rxjs/dist/bundles/rxjs.umd.js', - '^rxjs/testing$': - '../../node_modules/rxjs/dist/cjs/testing/index.js', - }, - maxWorkers: 8, -}; diff --git a/modules/store/migrations/13_0_0-beta/index.spec.ts b/modules/store/migrations/13_0_0-beta/index.spec.ts index a20d2abe21..9f531ad740 100644 --- a/modules/store/migrations/13_0_0-beta/index.spec.ts +++ b/modules/store/migrations/13_0_0-beta/index.spec.ts @@ -6,7 +6,10 @@ import { import * as path from 'path'; describe('Store Migration 13_0_0 beta', () => { - const collectionPath = path.join(__dirname, '../migration.json'); + const collectionPath = path.join( + process.cwd(), + 'dist/modules/store/migrations/migration.json' + ); const pkgName = 'store'; it(`should replace createFeatureSelector usages with 2 generics`, async () => { diff --git a/modules/store/migrations/13_0_0-rc/index.spec.ts b/modules/store/migrations/13_0_0-rc/index.spec.ts index 09d7187bfe..764f77aee4 100644 --- a/modules/store/migrations/13_0_0-rc/index.spec.ts +++ b/modules/store/migrations/13_0_0-rc/index.spec.ts @@ -6,7 +6,10 @@ import { import * as path from 'path'; describe('Store Migration 13_0_1', () => { - const collectionPath = path.join(__dirname, '../migration.json'); + const collectionPath = path.join( + process.cwd(), + 'dist/modules/store/migrations/migration.json' + ); const pkgName = 'store'; it(`should replace createSelector with explicit generics usages with explicit generics using Slices tuple`, async () => { diff --git a/modules/store/migrations/15_2_0/index.spec.ts b/modules/store/migrations/15_2_0/index.spec.ts index 861129addf..bcb77f08eb 100644 --- a/modules/store/migrations/15_2_0/index.spec.ts +++ b/modules/store/migrations/15_2_0/index.spec.ts @@ -6,7 +6,10 @@ import { import * as path from 'path'; describe('Store Migration 15_2_0', () => { - const collectionPath = path.join(__dirname, '../migration.json'); + const collectionPath = path.join( + process.cwd(), + 'dist/modules/store/migrations/migration.json' + ); const pkgName = 'store'; it(`should replace remove the State type argument`, async () => { diff --git a/modules/store/migrations/16_0_0-beta/index.spec.ts b/modules/store/migrations/16_0_0-beta/index.spec.ts index ae91191119..703b8455d5 100644 --- a/modules/store/migrations/16_0_0-beta/index.spec.ts +++ b/modules/store/migrations/16_0_0-beta/index.spec.ts @@ -6,7 +6,10 @@ import { import * as path from 'path'; describe('Store Migration 16_0_0-beta', () => { - const collectionPath = path.join(__dirname, '../migration.json'); + const collectionPath = path.join( + process.cwd(), + 'dist/modules/store/migrations/migration.json' + ); it(`should replace getMockStore with createMockStore`, async () => { const input = ` @@ -14,7 +17,7 @@ describe('Store Migration 16_0_0-beta', () => { import { SomethingElse } from '@ngrx/store'; import {getMockStore} from '@ngrx/store'; import {foo, getMockStore, bar} from '@ngrx/store'; - + const mockStore = getMockStore(); it('just a test', () => { @@ -27,7 +30,7 @@ describe('Store Migration 16_0_0-beta', () => { import { SomethingElse } from '@ngrx/store'; import {createMockStore} from '@ngrx/store'; import {foo,createMockStore, bar} from '@ngrx/store'; - + const mockStore =createMockStore(); it('just a test', () => { diff --git a/modules/store/migrations/18_0_0-beta/index.spec.ts b/modules/store/migrations/18_0_0-beta/index.spec.ts index bdc48e48c0..5c011edf28 100644 --- a/modules/store/migrations/18_0_0-beta/index.spec.ts +++ b/modules/store/migrations/18_0_0-beta/index.spec.ts @@ -7,7 +7,10 @@ import * as path from 'path'; import { tags } from '@angular-devkit/core'; describe('Store Migration to 18.0.0-beta', () => { - const collectionPath = path.join(__dirname, '../migration.json'); + const collectionPath = path.join( + process.cwd(), + 'dist/modules/store/migrations/migration.json' + ); const schematicRunner = new SchematicTestRunner('schematics', collectionPath); let appTree: UnitTestTree; diff --git a/modules/store/migrations/6_0_0/index.spec.ts b/modules/store/migrations/6_0_0/index.spec.ts index ff7437f31c..e88bda791e 100644 --- a/modules/store/migrations/6_0_0/index.spec.ts +++ b/modules/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/store/migrations/migration.json' +); describe('Store Migration 6_0_0', () => { let appTree; diff --git a/modules/store/migrations/8_0_0-beta/index.spec.ts b/modules/store/migrations/8_0_0-beta/index.spec.ts index 3f8db26fd5..40dd60725d 100644 --- a/modules/store/migrations/8_0_0-beta/index.spec.ts +++ b/modules/store/migrations/8_0_0-beta/index.spec.ts @@ -8,7 +8,10 @@ import { createPackageJson } from '@ngrx/schematics-core/testing/create-package' describe('Store Migration 8_0_0 beta', () => { let appTree: UnitTestTree; - const collectionPath = path.join(__dirname, '../migration.json'); + const collectionPath = path.join( + process.cwd(), + 'dist/modules/store/migrations/migration.json' + ); const pkgName = 'store'; beforeEach(() => { appTree = new UnitTestTree(Tree.empty()); diff --git a/modules/store/migrations/8_0_0-rc/index.spec.ts b/modules/store/migrations/8_0_0-rc/index.spec.ts index 9542b3c8b8..3623e8c7de 100644 --- a/modules/store/migrations/8_0_0-rc/index.spec.ts +++ b/modules/store/migrations/8_0_0-rc/index.spec.ts @@ -1,3 +1,4 @@ +import * as path from 'node:path'; import { normalize } from '@angular-devkit/core'; import { EmptyTree } from '@angular-devkit/schematics'; import { @@ -262,7 +263,7 @@ describe('Migration to version 8.0.0 rc', () => { function createSchematicsRunner() { const schematicRunner = new SchematicTestRunner( 'migrations', - require.resolve('../migration.json') + path.join(process.cwd(), 'dist/modules/store/migrations/migration.json') ); return schematicRunner; diff --git a/modules/store/project.json b/modules/store/project.json index 6d52c9abf6..055c78f8d2 100644 --- a/modules/store/project.json +++ b/modules/store/project.json @@ -55,12 +55,8 @@ "outputs": ["{options.outputFile}"] }, "test": { - "executor": "@nx/jest:jest", - "options": { - "jestConfig": "modules/store/jest.config.ts", - "runInBand": true, - "passWithNoTests": false - }, + "executor": "@analogjs/vitest-angular:test", + "dependsOn": ["build"], "outputs": ["{workspaceRoot}/coverage/modules/store"] } } diff --git a/modules/store/schematics/ng-add/index.spec.ts b/modules/store/schematics/ng-add/index.spec.ts index e92f723841..fa68bbb379 100644 --- a/modules/store/schematics/ng-add/index.spec.ts +++ b/modules/store/schematics/ng-add/index.spec.ts @@ -12,7 +12,7 @@ import { describe('Store ng-add Schematic', () => { const schematicRunner = new SchematicTestRunner( '@ngrx/store', - path.join(__dirname, '../collection.json') + path.join(process.cwd(), 'dist/modules/store/schematics/collection.json') ); const defaultOptions: RootStoreOptions = { skipPackageJson: false, diff --git a/modules/store/spec/action_creator.spec.ts b/modules/store/spec/action_creator.spec.ts index 0c83780c4f..03e721f222 100644 --- a/modules/store/spec/action_creator.spec.ts +++ b/modules/store/spec/action_creator.spec.ts @@ -1,17 +1,6 @@ import { createAction, props, union } from '..'; describe('Action Creators', () => { - let originalTimeout: number; - - beforeEach(() => { - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000; - }); - - afterEach(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; - }); - describe('createAction', () => { it('should create an action', () => { const foo = createAction('FOO', (foo: number) => ({ foo })); diff --git a/modules/store/spec/edge.spec.ts b/modules/store/spec/edge.spec.ts index 8247eabf77..1dd987f15f 100644 --- a/modules/store/spec/edge.spec.ts +++ b/modules/store/spec/edge.spec.ts @@ -29,28 +29,29 @@ describe('ngRx Store', () => { expect(store).toBeDefined(); }); - it('should handle re-entrancy', (done: any) => { - let todosNextCount = 0; - let todosCountNextCount = 0; + it('should handle re-entrancy', () => + new Promise((done) => { + let todosNextCount = 0; + let todosCountNextCount = 0; - store.pipe(select('todos')).subscribe((todos) => { - todosNextCount++; - store.dispatch({ type: 'SET_COUNT', payload: todos.length }); - }); - - store.pipe(select('todoCount')).subscribe((count) => { - todosCountNextCount++; - }); + store.pipe(select('todos')).subscribe((todos) => { + todosNextCount++; + store.dispatch({ type: 'SET_COUNT', payload: todos.length }); + }); - store.dispatch({ type: 'ADD_TODO', payload: { name: 'test' } }); - expect(todosNextCount).toBe(2); - expect(todosCountNextCount).toBe(2); + store.pipe(select('todoCount')).subscribe((count) => { + todosCountNextCount++; + }); - setTimeout(() => { + store.dispatch({ type: 'ADD_TODO', payload: { name: 'test' } }); expect(todosNextCount).toBe(2); expect(todosCountNextCount).toBe(2); - done(); - }, 10); - }); + + setTimeout(() => { + expect(todosNextCount).toBe(2); + expect(todosCountNextCount).toBe(2); + done(); + }, 10); + })); }); }); diff --git a/modules/store/spec/feature_creator.spec.ts b/modules/store/spec/feature_creator.spec.ts index 35bd313a85..2d837a660f 100644 --- a/modules/store/spec/feature_creator.spec.ts +++ b/modules/store/spec/feature_creator.spec.ts @@ -212,23 +212,24 @@ describe('createFeature()', () => { }); }); - it('should set up a feature state', (done) => { - const initialFooState = { x: 1, y: 2, z: 3 }; - const fooFeature = createFeature({ - name: 'foo', - reducer: createReducer(initialFooState), - }); - - TestBed.configureTestingModule({ - imports: [StoreModule.forRoot({}), StoreModule.forFeature(fooFeature)], - }); + it('should set up a feature state', () => + new Promise((done) => { + const initialFooState = { x: 1, y: 2, z: 3 }; + const fooFeature = createFeature({ + name: 'foo', + reducer: createReducer(initialFooState), + }); - TestBed.inject(Store) - .select(fooFeature.name) - .pipe(take(1)) - .subscribe((fooState) => { - expect(fooState).toEqual(initialFooState); - done(); + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({}), StoreModule.forFeature(fooFeature)], }); - }); + + TestBed.inject(Store) + .select(fooFeature.name) + .pipe(take(1)) + .subscribe((fooState) => { + expect(fooState).toEqual(initialFooState); + done(); + }); + })); }); diff --git a/modules/store/spec/integration.spec.ts b/modules/store/spec/integration.spec.ts index 1c8c92dd9d..80d168114c 100644 --- a/modules/store/spec/integration.spec.ts +++ b/modules/store/spec/integration.spec.ts @@ -53,7 +53,7 @@ describe('ngRx Integration spec', () => { beforeEach(() => { resetId(); - spyOn(reducers, 'todos').and.callThrough(); + vi.spyOn(reducers, 'todos'); TestBed.configureTestingModule({ imports: [StoreModule.forRoot(reducers, { initialState })], @@ -67,20 +67,21 @@ describe('ngRx Integration spec', () => { expect(store).toBeDefined(); }); - it('should combine reducers automatically if a key/value map is provided', (done) => { - const action = { type: 'Test Action' }; - const reducer$ = TestBed.inject(ReducerManager); + it('should combine reducers automatically if a key/value map is provided', () => + new Promise((done) => { + const action = { type: 'Test Action' }; + const reducer$ = TestBed.inject(ReducerManager); - reducer$.pipe(first()).subscribe((reducer: ActionReducer) => { - expect(reducer).toBeDefined(); - expect(typeof reducer === 'function').toBe(true); + reducer$.pipe(first()).subscribe((reducer: ActionReducer) => { + expect(reducer).toBeDefined(); + expect(typeof reducer === 'function').toBe(true); - reducer({ todos: [] }, action); + reducer({ todos: [] }, action); - expect(reducers.todos).toHaveBeenCalledWith([], action); - done(); - }); - }); + expect(reducers.todos).toHaveBeenCalledWith([], action); + done(); + }); + })); it('should use a provided initial state', () => { const resolvedInitialState = TestBed.inject(INITIAL_STATE); @@ -184,68 +185,70 @@ describe('ngRx Integration spec', () => { expect(currentlyVisibleTodos.length).toBe(0); }); - it('should use props to get a todo', (done: any) => { - const getTodosById = createSelector( - (state: TodoAppSchema) => state.todos, - (todos: Todo[], id: number) => { - return todos.find((p) => p.id === id); - } - ); - - const todo$ = store.select(getTodosById, 2); - todo$.pipe(take(3), toArray()).subscribe((res) => { - expect(res).toEqual([ - undefined, - { - id: 2, - text: 'second todo', - completed: false, - }, - { - id: 2, - text: 'second todo', - completed: true, - }, - ]); - done(); - }); - - store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); - store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } }); - store.dispatch({ - type: COMPLETE_TODO, - payload: { id: 2 }, - }); - }); + it('should use props to get a todo', () => + new Promise((done) => { + const getTodosById = createSelector( + (state: TodoAppSchema) => state.todos, + (todos: Todo[], id: number) => { + return todos.find((p) => p.id === id); + } + ); + + const todo$ = store.select(getTodosById, 2); + todo$.pipe(take(3), toArray()).subscribe((res) => { + expect(res).toEqual([ + undefined, + { + id: 2, + text: 'second todo', + completed: false, + }, + { + id: 2, + text: 'second todo', + completed: true, + }, + ]); + done(); + }); - it('should use the selector and props to get a todo', (done: any) => { - const getTodosState = createFeatureSelector( - 'todos' - ); - const getTodos = createSelector(getTodosState, (todos) => todos); - const getTodosById = createSelector( - getTodos, - (state: TodoAppSchema, id: number) => id, - (todos, id) => todos.find((todo) => todo.id === id) - ); - - const todo$ = store.select(getTodosById, 2); - todo$.pipe(take(3), toArray()).subscribe((res) => { - expect(res).toEqual([ - undefined, - { id: 2, text: 'second todo', completed: false }, - { id: 2, text: 'second todo', completed: true }, - ]); - done(); - }); + store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); + store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } }); + store.dispatch({ + type: COMPLETE_TODO, + payload: { id: 2 }, + }); + })); + + it('should use the selector and props to get a todo', () => + new Promise((done) => { + const getTodosState = createFeatureSelector( + 'todos' + ); + const getTodos = createSelector(getTodosState, (todos) => todos); + const getTodosById = createSelector( + getTodos, + (state: TodoAppSchema, id: number) => id, + (todos, id) => todos.find((todo) => todo.id === id) + ); + + const todo$ = store.select(getTodosById, 2); + todo$.pipe(take(3), toArray()).subscribe((res) => { + expect(res).toEqual([ + undefined, + { id: 2, text: 'second todo', completed: false }, + { id: 2, text: 'second todo', completed: true }, + ]); + done(); + }); - store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); - store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } }); - store.dispatch({ - type: COMPLETE_TODO, - payload: { id: 2 }, - }); - }); + store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); + store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } }); + store.dispatch({ + type: COMPLETE_TODO, + payload: { id: 2 }, + }); + })); }); describe('using the select operator', () => { @@ -315,71 +318,73 @@ describe('ngRx Integration spec', () => { expect(currentlyVisibleTodos.length).toBe(0); }); - it('should use the selector and props to get a todo', (done: any) => { - const getTodosState = createFeatureSelector( - 'todos' - ); - const getTodos = createSelector(getTodosState, (todos) => todos); - const getTodosById = createSelector( - getTodos, - (state: TodoAppSchema, id: number) => id, - (todos, id) => todos.find((todo) => todo.id === id) - ); - - const todo$ = store.pipe(select(getTodosById, 2)); - todo$.pipe(take(3), toArray()).subscribe((res) => { - expect(res).toEqual([ - undefined, - { id: 2, text: 'second todo', completed: false }, - { id: 2, text: 'second todo', completed: true }, - ]); - done(); - }); - - store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); - store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } }); - store.dispatch({ - type: COMPLETE_TODO, - payload: { id: 2 }, - }); - }); + it('should use the selector and props to get a todo', () => + new Promise((done) => { + const getTodosState = createFeatureSelector( + 'todos' + ); + const getTodos = createSelector(getTodosState, (todos) => todos); + const getTodosById = createSelector( + getTodos, + (state: TodoAppSchema, id: number) => id, + (todos, id) => todos.find((todo) => todo.id === id) + ); + + const todo$ = store.pipe(select(getTodosById, 2)); + todo$.pipe(take(3), toArray()).subscribe((res) => { + expect(res).toEqual([ + undefined, + { id: 2, text: 'second todo', completed: false }, + { id: 2, text: 'second todo', completed: true }, + ]); + done(); + }); - it('should use the props in the projector to get a todo', (done: any) => { - const getTodosState = createFeatureSelector( - 'todos' - ); - - const getTodosById = createSelector( - getTodosState, - (todos: Todo[], { id }: { id: number }) => - todos.find((todo) => todo.id === id) - ); - - const todo$ = store.pipe(select(getTodosById, { id: 2 })); - todo$.pipe(take(3), toArray()).subscribe((res) => { - expect(res).toEqual([ - undefined, - { - id: 2, - text: 'second todo', - completed: false, - }, - { - id: 2, - text: 'second todo', - completed: true, - }, - ]); - done(); - }); + store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); + store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } }); + store.dispatch({ + type: COMPLETE_TODO, + payload: { id: 2 }, + }); + })); + + it('should use the props in the projector to get a todo', () => + new Promise((done) => { + const getTodosState = createFeatureSelector( + 'todos' + ); + + const getTodosById = createSelector( + getTodosState, + (todos: Todo[], { id }: { id: number }) => + todos.find((todo) => todo.id === id) + ); + + const todo$ = store.pipe(select(getTodosById, { id: 2 })); + todo$.pipe(take(3), toArray()).subscribe((res) => { + expect(res).toEqual([ + undefined, + { + id: 2, + text: 'second todo', + completed: false, + }, + { + id: 2, + text: 'second todo', + completed: true, + }, + ]); + done(); + }); - store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); - store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } }); - store.dispatch({ - type: COMPLETE_TODO, - payload: { id: 2 }, - }); - }); + store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); + store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } }); + store.dispatch({ + type: COMPLETE_TODO, + payload: { id: 2 }, + }); + })); }); }); @@ -462,31 +467,35 @@ describe('ngRx Integration spec', () => { }); }); - it('throws if forRoot() is used more than once', (done: any) => { - @NgModule({ - imports: [StoreModule.forRoot({})], - }) - class FeatureModule {} - - TestBed.configureTestingModule({ - imports: [StoreModule.forRoot({}), RouterTestingModule.withRoutes([])], - }); + it('throws if forRoot() is used more than once', () => + new Promise((done) => { + @NgModule({ + imports: [StoreModule.forRoot({})], + }) + class FeatureModule {} + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({}), + RouterTestingModule.withRoutes([]), + ], + }); - const router = TestBed.inject(Router); + const router = TestBed.inject(Router); - router.resetConfig([ - { - path: 'feature-path', - loadChildren: () => Promise.resolve(FeatureModule), - }, - ]); + router.resetConfig([ + { + path: 'feature-path', + loadChildren: () => Promise.resolve(FeatureModule), + }, + ]); - router.navigateByUrl('/feature-path').catch((err: TypeError) => { - expect(err.message).toBe( - 'The root Store has been provided more than once. Feature modules should provide feature states instead.' - ); - done(); - }); - }); + router.navigateByUrl('/feature-path').catch((err: TypeError) => { + expect(err.message).toBe( + 'The root Store has been provided more than once. Feature modules should provide feature states instead.' + ); + done(); + }); + })); }); }); diff --git a/modules/store/spec/integration_signals.spec.ts b/modules/store/spec/integration_signals.spec.ts index 2d53b1021d..105324f3ec 100644 --- a/modules/store/spec/integration_signals.spec.ts +++ b/modules/store/spec/integration_signals.spec.ts @@ -40,7 +40,7 @@ describe('NgRx and Signals Integration spec', () => { beforeEach(() => { resetId(); - spyOn(reducers, 'todos').and.callThrough(); + vi.spyOn(reducers, 'todos'); TestBed.configureTestingModule({ providers: [provideStore(reducers, { initialState })], diff --git a/modules/store/spec/meta-reducers/inNgZoneAssert_reducer.spec.ts b/modules/store/spec/meta-reducers/inNgZoneAssert_reducer.spec.ts index 8cf2fb5766..2105972990 100644 --- a/modules/store/spec/meta-reducers/inNgZoneAssert_reducer.spec.ts +++ b/modules/store/spec/meta-reducers/inNgZoneAssert_reducer.spec.ts @@ -3,17 +3,13 @@ import { inNgZoneAssertMetaReducer } from '../../src/meta-reducers'; describe('inNgZoneAssertMetaReducer:', () => { it('should not throw if in NgZone', () => { - ngCore.NgZone.isInAngularZone = jasmine - .createSpy('isInAngularZone') - .and.returnValue(true); + ngCore.NgZone.isInAngularZone = vi.fn(() => true); expect(() => invokeActionReducer((state: any) => state)).not.toThrow(); expect(ngCore.NgZone.isInAngularZone).toHaveBeenCalled(); }); it('should throw when not in NgZone', () => { - ngCore.NgZone.isInAngularZone = jasmine - .createSpy('isInAngularZone') - .and.returnValue(false); + ngCore.NgZone.isInAngularZone = vi.fn(() => false); expect(() => invokeActionReducer((state: any) => state)).toThrowError( `Action 'invoke' running outside NgZone. https://ngrx.io/guide/store/configuration/runtime-checks#strictactionwithinngzone` ); @@ -21,7 +17,7 @@ describe('inNgZoneAssertMetaReducer:', () => { }); it('should not call isInAngularZone when check is off', () => { - ngCore.NgZone.isInAngularZone = jasmine.createSpy('isInAngularZone'); + ngCore.NgZone.isInAngularZone = vi.fn(); expect(() => invokeActionReducer((state: any) => state, false) ).not.toThrow(); diff --git a/modules/store/spec/modules.spec.ts b/modules/store/spec/modules.spec.ts index 4ccc21fe9e..c830537a16 100644 --- a/modules/store/spec/modules.spec.ts +++ b/modules/store/spec/modules.spec.ts @@ -47,14 +47,10 @@ describe(`Store Modules`, () => { const rootInitial = { fruit: 'orange' }; beforeEach(() => { - featureAReducerFactory = jasmine - .createSpy('featureAReducerFactory') - .and.callFake((rm: any, initialState?: any) => { - return (state: any, action: any) => 4; - }); - rootReducerFactory = jasmine - .createSpy('rootReducerFactory') - .and.callFake(combineReducers); + featureAReducerFactory = vi.fn((rm: any, initialState?: any) => { + return (state: any, action: any) => 4; + }); + rootReducerFactory = vi.fn(combineReducers); @NgModule({ imports: [ @@ -104,18 +100,19 @@ describe(`Store Modules`, () => { }); }); - it(`should use config.reducerFactory`, (done) => { - store.dispatch({ type: 'fruit', payload: 'banana' }); - store.dispatch({ type: 'a', payload: 42 }); + it(`should use config.reducerFactory`, () => + new Promise((done) => { + store.dispatch({ type: 'fruit', payload: 'banana' }); + store.dispatch({ type: 'a', payload: 42 }); - store.pipe(take(1)).subscribe((s: any) => { - expect(s).toEqual({ - fruit: 'banana', - a: 4, + store.pipe(take(1)).subscribe((s: any) => { + expect(s).toEqual({ + fruit: 'banana', + a: 4, + }); + done(); }); - done(); - }); - }); + })); }); describe(`: With initial state`, () => { @@ -136,12 +133,13 @@ describe(`Store Modules`, () => { store = TestBed.inject(Store); }); - it('should have initial state', (done) => { - store.pipe(take(1)).subscribe((s: any) => { - expect(s).toEqual(initialState); - done(); - }); - }); + it('should have initial state', () => + new Promise((done) => { + store.pipe(take(1)).subscribe((s: any) => { + expect(s).toEqual(initialState); + done(); + }); + })); }; describe( @@ -201,23 +199,24 @@ describe(`Store Modules`, () => { store = TestBed.inject(Store); }); - it('should nest the child module in the root store object', (done) => { - store.pipe(take(1)).subscribe((state: State) => { - expect(state).toEqual({ - fruit: 'apple', - a: 5, - b: { - list: [1, 2, 3], - index: 2, - }, - c: { - list: [1, 2, 3], - index: 2, - }, - } as State); - done(); - }); - }); + it('should nest the child module in the root store object', () => + new Promise((done) => { + store.pipe(take(1)).subscribe((state: State) => { + expect(state).toEqual({ + fruit: 'apple', + a: 5, + b: { + list: [1, 2, 3], + index: 2, + }, + c: { + list: [1, 2, 3], + index: 2, + }, + } as State); + done(); + }); + })); }); describe(`: With slice object`, () => { @@ -241,13 +240,14 @@ describe(`Store Modules`, () => { store = TestBed.inject(Store); }); - it('should set up a feature state', (done) => { - store.pipe(take(1)).subscribe((state: State) => { - expect(state).toEqual({ - a: 5, - } as State); - done(); - }); - }); + it('should set up a feature state', () => + new Promise((done) => { + store.pipe(take(1)).subscribe((state: State) => { + expect(state).toEqual({ + a: 5, + } as State); + done(); + }); + })); }); }); diff --git a/modules/store/spec/runtime_checks.spec.ts b/modules/store/spec/runtime_checks.spec.ts index 6fc0b0ec1f..0aef7c4e84 100644 --- a/modules/store/spec/runtime_checks.spec.ts +++ b/modules/store/spec/runtime_checks.spec.ts @@ -5,6 +5,8 @@ import { createActiveRuntimeChecks } from '../src/runtime_checks'; import { RuntimeChecks, Action } from '../src/models'; import { resetRegisteredActionTypes } from '../src/globals'; +vi.mock('@angular/core', { spy: true }); + describe('Runtime checks:', () => { describe('createActiveRuntimeChecks:', () => { it('should enable immutability checks by default', () => { @@ -39,7 +41,7 @@ describe('Runtime checks:', () => { }); it('should disable runtime checks in production by default', () => { - const spy = jest.spyOn(ngCore, 'isDevMode').mockReturnValue(false); + const spy = vi.mocked(ngCore.isDevMode).mockReturnValue(false); expect(createActiveRuntimeChecks()).toEqual({ strictStateSerializability: false, @@ -55,7 +57,7 @@ describe('Runtime checks:', () => { }); it('should disable runtime checks in production even if opted in to enable', () => { - const spy = jest.spyOn(ngCore, 'isDevMode').mockReturnValue(false); + const spy = vi.mocked(ngCore.isDevMode).mockReturnValue(false); expect( createActiveRuntimeChecks({ @@ -242,9 +244,7 @@ describe('Runtime checks:', () => { const invalidAction = () => ({ type: ErrorTypes.OutOfNgZoneAction }); it('should throw when running outside ngZone', fakeAsync(() => { - ngCore.NgZone.isInAngularZone = jasmine - .createSpy('isInAngularZone') - .and.returnValue(false); + ngCore.NgZone.isInAngularZone = vi.fn().mockReturnValue(false); const store = setupStore({ strictActionWithinNgZone: true }); expect(() => { store.dispatch(invalidAction()); @@ -255,9 +255,7 @@ describe('Runtime checks:', () => { })); it('should not throw when running in ngZone', fakeAsync(() => { - ngCore.NgZone.isInAngularZone = jasmine - .createSpy('isInAngularZone') - .and.returnValue(true); + ngCore.NgZone.isInAngularZone = vi.fn().mockReturnValue(true); const store = setupStore({ strictActionWithinNgZone: true }); expect(() => { store.dispatch(invalidAction()); @@ -269,7 +267,7 @@ describe('Runtime checks:', () => { it('should not be called when disabled', fakeAsync(() => { const store = setupStore({ strictActionWithinNgZone: false }); - ngCore.NgZone.isInAngularZone = jasmine.createSpy('isInAngularZone'); + ngCore.NgZone.isInAngularZone = vi.fn(); expect(() => { store.dispatch(invalidAction()); flush(); diff --git a/modules/store/spec/runtime_checks_meta_reducers.spec.ts b/modules/store/spec/runtime_checks_meta_reducers.spec.ts index 462974b427..613717c548 100644 --- a/modules/store/spec/runtime_checks_meta_reducers.spec.ts +++ b/modules/store/spec/runtime_checks_meta_reducers.spec.ts @@ -2,15 +2,12 @@ import { TestBed } from '@angular/core/testing'; import { Store, StoreModule, USER_RUNTIME_CHECKS } from '..'; import * as metaReducers from '../src/meta-reducers'; -// mock to be able to spy on meta reducer methods -jest.mock('../src/meta-reducers'); - describe('USER_RUNTIME_CHECKS Token', () => { it('should be possible to toggle runtime reducers via the Injection Token', () => { - const serializationCheckMetaReducerSpy = spyOn( + const serializationCheckMetaReducerSpy = vi.spyOn( metaReducers, 'serializationCheckMetaReducer' - ).and.callThrough(); + ); TestBed.configureTestingModule({ imports: [StoreModule.forRoot({})], @@ -26,17 +23,20 @@ describe('USER_RUNTIME_CHECKS Token', () => { const _store = TestBed.inject(Store); expect(serializationCheckMetaReducerSpy).toHaveBeenCalled(); + + // Needs to reset or else the test fails + serializationCheckMetaReducerSpy.mockReset(); }); it('should not create a meta reducer if not desired', () => { - const serializationCheckMetaReducerSpy = spyOn( + const serializationCheckMetaReducerSpy = vi.spyOn( metaReducers, 'serializationCheckMetaReducer' - ).and.callThrough(); - const inNgZoneAssertMetaReducerSpy = spyOn( + ); + const inNgZoneAssertMetaReducerSpy = vi.spyOn( metaReducers, 'inNgZoneAssertMetaReducer' - ).and.callThrough(); + ); TestBed.configureTestingModule({ imports: [StoreModule.forRoot({})], @@ -54,17 +54,21 @@ describe('USER_RUNTIME_CHECKS Token', () => { const _store = TestBed.inject(Store); expect(serializationCheckMetaReducerSpy).not.toHaveBeenCalled(); expect(inNgZoneAssertMetaReducerSpy).not.toHaveBeenCalled(); + + // Needs to reset or else the test fails + serializationCheckMetaReducerSpy.mockReset(); + inNgZoneAssertMetaReducerSpy.mockReset(); }); it('should create immutability meta reducer without config', () => { - const serializationCheckMetaReducerSpy = spyOn( + const serializationCheckMetaReducerSpy = vi.spyOn( metaReducers, 'serializationCheckMetaReducer' - ).and.callThrough(); - const immutabilityCheckMetaReducerSpy = spyOn( + ); + const immutabilityCheckMetaReducerSpy = vi.spyOn( metaReducers, 'immutabilityCheckMetaReducer' - ).and.callThrough(); + ); TestBed.configureTestingModule({ imports: [StoreModule.forRoot({})], @@ -79,5 +83,9 @@ describe('USER_RUNTIME_CHECKS Token', () => { const _store = TestBed.inject(Store); expect(serializationCheckMetaReducerSpy).not.toHaveBeenCalled(); expect(immutabilityCheckMetaReducerSpy).toHaveBeenCalled(); + + // Needs to reset or else the test fails + serializationCheckMetaReducerSpy.mockReset(); + immutabilityCheckMetaReducerSpy.mockReset(); }); }); diff --git a/modules/store/spec/selector.spec.ts b/modules/store/spec/selector.spec.ts index 7d45d0d131..b13c5027b1 100644 --- a/modules/store/spec/selector.spec.ts +++ b/modules/store/spec/selector.spec.ts @@ -11,36 +11,40 @@ import { import { map, distinctUntilChanged } from 'rxjs/operators'; import { setNgrxMockEnvironment } from '../src'; +import { type Mock, vi } from 'vitest'; + +vi.mock('@angular/core', { spy: true }); + describe('Selectors', () => { let countOne: number; let countTwo: number; let countThree: number; - let incrementOne: jasmine.Spy; - let incrementTwo: jasmine.Spy; - let incrementThree: jasmine.Spy; + let incrementOne: Mock; + let incrementTwo: Mock; + let incrementThree: Mock; beforeEach(() => { countOne = 0; countTwo = 0; countThree = 0; - incrementOne = jasmine.createSpy('incrementOne').and.callFake(() => { + incrementOne = vi.fn(() => { return ++countOne; }); - incrementTwo = jasmine.createSpy('incrementTwo').and.callFake(() => { + incrementTwo = vi.fn(() => { return ++countTwo; }); - incrementThree = jasmine.createSpy('incrementThree').and.callFake(() => { + incrementThree = vi.fn(() => { return ++countThree; }); }); describe('createSelector', () => { it('should deliver the value of selectors to the projection function', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( incrementOne, @@ -52,7 +56,7 @@ describe('Selectors', () => { }); it('should allow an override of the selector return', () => { - const projectFn = jasmine.createSpy('projectionFn').and.returnValue(2); + const projectFn = vi.fn().mockReturnValue(2); const selector = createSelector(incrementOne, incrementTwo, projectFn); @@ -66,7 +70,7 @@ describe('Selectors', () => { }); it('should be possible to test a projector fn independent from the selectors it is composed of', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector(incrementOne, incrementTwo, projectFn); selector.projector('', ''); @@ -79,12 +83,10 @@ describe('Selectors', () => { it('should call the projector function only when the value of a dependent selector change', () => { const firstState = { first: 'state', unchanged: 'state' }; const secondState = { second: 'state', unchanged: 'state' }; - const neverChangingSelector = jasmine - .createSpy('unchangedSelector') - .and.callFake((state: any) => { - return state.unchanged; - }); - const projectFn = jasmine.createSpy('projectionFn'); + const neverChangingSelector = vi.fn((state: any) => { + return state.unchanged; + }); + const projectFn = vi.fn(); const selector = createSelector(neverChangingSelector, projectFn); selector(firstState); @@ -96,7 +98,7 @@ describe('Selectors', () => { it('should memoize the function', () => { const firstState = { first: 'state' }; const secondState = { second: 'state' }; - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( incrementOne, incrementTwo, @@ -122,15 +124,10 @@ describe('Selectors', () => { const fail = () => { throw new Error(); }; - const projectorFn = jasmine - .createSpy('projectorFn', (s: any) => (s.ok ? s.ok : fail())) - .and.callThrough(); - const selectorFn = jasmine - .createSpy( - 'selectorFn', - createSelector((state: any) => state, projectorFn) - ) - .and.callThrough(); + const projectorFn = vi.fn((s: any) => (s.ok ? s.ok : fail())); + const selectorFn = vi.fn( + createSelector((state: any) => state, projectorFn) + ); selectorFn(firstState); @@ -144,7 +141,7 @@ describe('Selectors', () => { it('should allow you to release memoized arguments', () => { const state = { first: 'state' }; - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector(incrementOne, projectFn); selector(state); @@ -160,8 +157,9 @@ describe('Selectors', () => { const grandparent = createSelector(incrementOne, (a) => a); const parent = createSelector(grandparent, (a) => a); const child = createSelector(parent, (a) => a); - spyOn(grandparent, 'release').and.callThrough(); - spyOn(parent, 'release').and.callThrough(); + + vi.spyOn(grandparent, 'release'); + vi.spyOn(parent, 'release'); child.release(); @@ -203,7 +201,7 @@ describe('Selectors', () => { describe('createSelector with props', () => { it('should deliver the value of selectors to the projection function', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( incrementOne, @@ -219,7 +217,7 @@ describe('Selectors', () => { }); it('should be possible to test a projector fn independent from the selectors it is composed of', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( incrementOne, incrementTwo, @@ -237,7 +235,7 @@ describe('Selectors', () => { }); it('should call the projector function when the state changes', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( incrementOne, (state: any, props: any) => props.value, @@ -262,7 +260,7 @@ describe('Selectors', () => { const secondState = { second: 'state' }; const props = { foo: 'props' }; - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( incrementOne, incrementTwo, @@ -286,7 +284,7 @@ describe('Selectors', () => { it('should allow you to release memoized arguments', () => { const state = { first: 'state' }; const props = { foo: 'props' }; - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( incrementOne, (state: any, props: any) => props, @@ -305,7 +303,7 @@ describe('Selectors', () => { describe('createSelector with arrays', () => { it('should deliver the value of selectors to the projection function', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( [incrementOne, incrementTwo], projectFn @@ -315,7 +313,7 @@ describe('Selectors', () => { }); it('should be possible to test a projector fn independent from the selectors it is composed of', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector([incrementOne, incrementTwo], projectFn); selector.projector('', ''); @@ -328,12 +326,10 @@ describe('Selectors', () => { it('should call the projector function only when the value of a dependent selector change', () => { const firstState = { first: 'state', unchanged: 'state' }; const secondState = { second: 'state', unchanged: 'state' }; - const neverChangingSelector = jasmine - .createSpy('unchangedSelector') - .and.callFake((state: any) => { - return state.unchanged; - }); - const projectFn = jasmine.createSpy('projectionFn'); + const neverChangingSelector = vi.fn((state: any) => { + return state.unchanged; + }); + const projectFn = vi.fn(); const selector = createSelector([neverChangingSelector], projectFn); selector(firstState); @@ -345,7 +341,7 @@ describe('Selectors', () => { it('should memoize the function', () => { const firstState = { first: 'state' }; const secondState = { second: 'state' }; - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( [incrementOne, incrementTwo, incrementThree], projectFn @@ -365,7 +361,7 @@ describe('Selectors', () => { it('should allow you to release memoized arguments', () => { const state = { first: 'state' }; - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector([incrementOne], projectFn); selector(state); @@ -381,8 +377,9 @@ describe('Selectors', () => { const grandparent = createSelector([incrementOne], (a) => a); const parent = createSelector([grandparent], (a) => a); const child = createSelector([parent], (a) => a); - spyOn(grandparent, 'release').and.callThrough(); - spyOn(parent, 'release').and.callThrough(); + + vi.spyOn(grandparent, 'release'); + vi.spyOn(parent, 'release'); child.release(); @@ -393,7 +390,7 @@ describe('Selectors', () => { describe('createSelector with arrays and props', () => { it('should deliver the value of selectors to the projection function', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( [incrementOne, incrementTwo, (state: any, props: any) => props.value], projectFn @@ -405,7 +402,7 @@ describe('Selectors', () => { }); it('should be possible to test a projector fn independent from the selectors it is composed of', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( [ incrementOne, @@ -426,7 +423,7 @@ describe('Selectors', () => { }); it('should call the projector function when the state changes', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( [incrementOne, (state: any, props: any) => props.value], projectFn @@ -450,7 +447,7 @@ describe('Selectors', () => { const secondState = { second: 'state' }; const props = { foo: 'props' }; - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( [ incrementOne, @@ -476,7 +473,7 @@ describe('Selectors', () => { it('should allow you to release memoized arguments', () => { const state = { first: 'state' }; const props = { foo: 'props' }; - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selector = createSelector( [incrementOne, (state: any, props: any) => props], projectFn @@ -495,13 +492,15 @@ describe('Selectors', () => { describe('createFeatureSelector', () => { const featureName = 'featureA'; let featureSelector: (state: any) => number; - let warnSpy: jasmine.Spy; + let warnSpy: Mock; beforeEach(() => { featureSelector = createFeatureSelector(featureName); - warnSpy = spyOn(console, 'warn'); + warnSpy = vi.spyOn(console, 'warn'); }); + afterEach(() => warnSpy.mockReset()); + it('should memoize the result', () => { const firstValue = { first: 'value' }; const firstState = { [featureName]: firstValue }; @@ -524,7 +523,7 @@ describe('Selectors', () => { describe('Warning', () => { describe('should not log when: ', () => { it('the feature does exist', () => { - const ngSpy = jest.spyOn(ngCore, 'isDevMode').mockReturnValue(true); + const ngSpy = vi.mocked(ngCore.isDevMode).mockReturnValue(true); const selector = createFeatureSelector('featureA'); selector({ featureA: {} }); @@ -536,7 +535,7 @@ describe('Selectors', () => { }); it('the feature key exist but is falsy', () => { - const ngSpy = jest.spyOn(ngCore, 'isDevMode').mockReturnValue(true); + const ngSpy = vi.mocked(ngCore.isDevMode).mockReturnValue(true); const selector = createFeatureSelector('featureB'); selector({ featureA: {}, featureB: undefined }); @@ -548,7 +547,7 @@ describe('Selectors', () => { }); it('not in development mode', () => { - const ngSpy = jest.spyOn(ngCore, 'isDevMode').mockReturnValue(false); + const ngSpy = vi.mocked(ngCore.isDevMode).mockReturnValue(false); const selector = createFeatureSelector('featureB'); selector({ featureA: {} }); @@ -562,13 +561,13 @@ describe('Selectors', () => { describe('warning will ', () => { it('be logged when not in mock environment', () => { - const ngSpy = jest.spyOn(ngCore, 'isDevMode').mockReturnValue(true); + const ngSpy = vi.mocked(ngCore.isDevMode).mockReturnValue(true); const selector = createFeatureSelector('featureB'); selector({ featureA: {} }); expect(warnSpy).toHaveBeenCalled(); - expect(warnSpy.calls.mostRecent().args[0]).toMatch( + expect(warnSpy.mock.lastCall?.[0]).toMatch( /The feature name "featureB" does not exist/ ); @@ -590,7 +589,7 @@ describe('Selectors', () => { describe('createSelectorFactory', () => { it('should return a selector creator function', () => { - const projectFn = jasmine.createSpy('projectionFn'); + const projectFn = vi.fn(); const selectorFunc = createSelectorFactory(defaultMemoize); const selector = selectorFunc(incrementOne, incrementTwo, projectFn)({}); @@ -599,9 +598,9 @@ describe('Selectors', () => { }); it('should allow a custom memoization function', () => { - const projectFn = jasmine.createSpy('projectionFn'); - const anyFn = jasmine.createSpy('t').and.callFake(() => true); - const equalFn = jasmine.createSpy('isEqual').and.callFake(() => true); + const projectFn = vi.fn(); + const anyFn = vi.fn(() => true); + const equalFn = vi.fn(() => true); const customMemoizer = (aFn: any = anyFn, eFn: any = equalFn) => defaultMemoize(anyFn, equalFn); const customSelector = createSelectorFactory(customMemoizer); @@ -610,12 +609,12 @@ describe('Selectors', () => { selector(1); selector(2); - expect(anyFn.calls.count()).toEqual(1); + expect(anyFn.mock.calls.length).toEqual(1); }); it('should allow a custom state memoization function', () => { - const projectFn = jasmine.createSpy('projectionFn'); - const stateFn = jasmine.createSpy('stateFn'); + const projectFn = vi.fn(); + const stateFn = vi.fn(); const selectorFunc = createSelectorFactory(defaultMemoize, { stateFn }); const selector = selectorFunc(incrementOne, incrementTwo, projectFn)({}); @@ -626,19 +625,19 @@ describe('Selectors', () => { describe('defaultMemoize', () => { it('should allow a custom equality function', () => { - const anyFn = jasmine.createSpy('t').and.callFake(() => true); - const equalFn = jasmine.createSpy('isEqual').and.callFake(() => true); + const anyFn = vi.fn(() => true); + const equalFn = vi.fn(() => true); const memoizer = defaultMemoize(anyFn, equalFn); memoizer.memoized(1, 2, 3); memoizer.memoized(1, 2); - expect(anyFn.calls.count()).toEqual(1); + expect(anyFn.mock.calls.length).toEqual(1); }); }); describe('resultMemoize', () => { - let projectionFnSpy: jasmine.Spy; + let projectionFnSpy: Mock; const ARRAY = ['a', 'ab', 'b']; const ARRAY_CHANGED = [...ARRAY, 'bc']; const A_FILTER: { by: string } = { by: 'a' }; @@ -657,11 +656,9 @@ describe('Selectors', () => { } beforeEach(() => { - projectionFnSpy = jasmine - .createSpy('projectionFn') - .and.callFake((arr: string[], filter: { by: string }) => - arr.filter((item) => item.startsWith(filter.by)) - ); + projectionFnSpy = vi.fn((arr: string[], filter: { by: string }) => + arr.filter((item) => item.startsWith(filter.by)) + ); arrayMemoizer = resultMemoize(projectionFnSpy, isResultEqual); }); @@ -670,14 +667,14 @@ describe('Selectors', () => { arrayMemoizer.memoized(ARRAY, A_FILTER); arrayMemoizer.memoized(ARRAY, A_FILTER); - expect(projectionFnSpy.calls.count()).toBe(1); + expect(projectionFnSpy.mock.calls.length).toBe(1); }); it('should rerun projector function when arguments changed', () => { arrayMemoizer.memoized(ARRAY, A_FILTER); arrayMemoizer.memoized(ARRAY_CHANGED, A_FILTER); - expect(projectionFnSpy.calls.count()).toBe(2); + expect(projectionFnSpy.mock.calls.length).toBe(2); }); it('should return the same instance of results when projector function produces the same results array', () => { diff --git a/modules/store/spec/state.spec.ts b/modules/store/spec/state.spec.ts index 8778098461..d41518dafe 100644 --- a/modules/store/spec/state.spec.ts +++ b/modules/store/spec/state.spec.ts @@ -4,7 +4,7 @@ import { INIT, Store, StoreModule, Action } from '..'; describe('ngRx State', () => { it('should call the reducer to scan over the dispatcher', () => { const initialState = 123; - const reducer = jasmine.createSpy('reducer').and.returnValue(initialState); + const reducer = vi.fn(() => initialState); TestBed.configureTestingModule({ imports: [ diff --git a/modules/store/spec/store.spec.ts b/modules/store/spec/store.spec.ts index 013b9b5eda..4adab5e082 100644 --- a/modules/store/spec/store.spec.ts +++ b/modules/store/spec/store.spec.ts @@ -29,8 +29,8 @@ import { RESET, counterReducer2, } from './fixtures/counter'; -import Spy = jasmine.Spy; import { take } from 'rxjs/operators'; +import type { Mock } from 'vitest'; interface TestAppSchema { counter1: number; @@ -62,44 +62,47 @@ describe('ngRx Store', () => { } describe('initial state', () => { - it('should handle an initial state object', (done: any) => { - setup(); - testStoreValue({ counter1: 0, counter2: 1, counter3: 0 }, done); - }); - - it('should handle an initial state function', (done: any) => { - setup(() => ({ counter1: 0, counter2: 5 })); - testStoreValue({ counter1: 0, counter2: 5, counter3: 0 }, done); - }); - - it('should keep initial state values when state is partially initialized', (done: any) => { - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({} as any, { - initialState: { - feature1: { - counter1: 1, + it('should handle an initial state object', () => + new Promise((done) => { + setup(); + testStoreValue({ counter1: 0, counter2: 1, counter3: 0 }, done); + })); + + it('should handle an initial state function', () => + new Promise((done) => { + setup(() => ({ counter1: 0, counter2: 5 })); + testStoreValue({ counter1: 0, counter2: 5, counter3: 0 }, done); + })); + + it('should keep initial state values when state is partially initialized', () => + new Promise((done) => { + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({} as any, { + initialState: { + feature1: { + counter1: 1, + }, + feature3: { + counter3: 3, + }, }, - feature3: { - counter3: 3, - }, - }, - }), - StoreModule.forFeature('feature1', { counter1: counterReducer }), - StoreModule.forFeature('feature2', { counter2: counterReducer }), - StoreModule.forFeature('feature3', { counter3: counterReducer }), - ], - }); - - testStoreValue( - { - feature1: { counter1: 1 }, - feature2: { counter2: 0 }, - feature3: { counter3: 3 }, - }, - done - ); - }); + }), + StoreModule.forFeature('feature1', { counter1: counterReducer }), + StoreModule.forFeature('feature2', { counter2: counterReducer }), + StoreModule.forFeature('feature3', { counter3: counterReducer }), + ], + }); + + testStoreValue( + { + feature1: { counter1: 1 }, + feature2: { counter2: 0 }, + feature3: { counter3: 3 }, + }, + done + ); + })); it('should reset to initial state when undefined (root ActionReducerMap)', () => { TestBed.configureTestingModule({ @@ -277,8 +280,8 @@ describe('ngRx Store', () => { }); it('should implement the observer interface forwarding actions and errors to the dispatcher', () => { - spyOn(dispatcher, 'next'); - spyOn(dispatcher, 'error'); + vi.spyOn(dispatcher, 'next').mockImplementationOnce(() => void 0); + vi.spyOn(dispatcher, 'error').mockImplementationOnce(() => void 0); store.next(1); store.error(2); @@ -309,21 +312,18 @@ describe('ngRx Store', () => { }); describe(`add/remove reducers`, () => { - let addReducerSpy: Spy; - let removeReducerSpy: Spy; - let reducerManagerDispatcherSpy: Spy; + let addReducerSpy: Mock; + let removeReducerSpy: Mock; + let reducerManagerDispatcherSpy: Mock; const key = 'counter4'; beforeEach(() => { setup(); const reducerManager = TestBed.inject(ReducerManager); const dispatcher = TestBed.inject(ReducerManagerDispatcher); - addReducerSpy = spyOn(reducerManager, 'addReducer').and.callThrough(); - removeReducerSpy = spyOn( - reducerManager, - 'removeReducer' - ).and.callThrough(); - reducerManagerDispatcherSpy = spyOn(dispatcher, 'next').and.callThrough(); + addReducerSpy = vi.spyOn(reducerManager, 'addReducer'); + removeReducerSpy = vi.spyOn(reducerManager, 'removeReducer'); + reducerManagerDispatcherSpy = vi.spyOn(dispatcher, 'next'); }); it(`should delegate add/remove to ReducerManager`, () => { @@ -334,19 +334,20 @@ describe('ngRx Store', () => { expect(removeReducerSpy).toHaveBeenCalledWith(key); }); - it(`should work with added / removed reducers`, (done) => { - store.addReducer(key, counterReducer); - store.pipe(take(1)).subscribe((val) => { - expect(val.counter4).toBe(0); - }); + it(`should work with added / removed reducers`, () => + new Promise((done) => { + store.addReducer(key, counterReducer); + store.pipe(take(1)).subscribe((val) => { + expect(val.counter4).toBe(0); + }); - store.removeReducer(key); - store.dispatch({ type: INCREMENT }); - store.pipe(take(1)).subscribe((val) => { - expect(val.counter4).toBeUndefined(); - done(); - }); - }); + store.removeReducer(key); + store.dispatch({ type: INCREMENT }); + store.pipe(take(1)).subscribe((val) => { + expect(val.counter4).toBeUndefined(); + done(); + }); + })); it('should dispatch an update reducers action when a reducer is added', () => { store.addReducer(key, counterReducer); @@ -367,7 +368,7 @@ describe('ngRx Store', () => { describe('add/remove features', () => { let reducerManager: ReducerManager; - let reducerManagerDispatcherSpy: Spy; + let reducerManagerDispatcherSpy: Mock; beforeEach(() => { TestBed.configureTestingModule({ @@ -376,7 +377,7 @@ describe('ngRx Store', () => { reducerManager = TestBed.inject(ReducerManager); const dispatcher = TestBed.inject(ReducerManagerDispatcher); - reducerManagerDispatcherSpy = spyOn(dispatcher, 'next').and.callThrough(); + reducerManagerDispatcherSpy = vi.spyOn(dispatcher, 'next'); }); it('should dispatch an update reducers action when a feature is added', () => { @@ -447,15 +448,15 @@ describe('ngRx Store', () => { return { key, reducers: {}, - reducerFactory: jasmine.createSpy(`reducerFactory_${key}`), + reducerFactory: vi.fn(), }; } }); describe('Meta Reducers', () => { let metaReducerContainer: any; - let metaReducerSpy1: Spy; - let metaReducerSpy2: Spy; + let metaReducerSpy1: Mock; + let metaReducerSpy2: Mock; beforeEach(() => { metaReducerContainer = (function () { @@ -477,15 +478,9 @@ describe('ngRx Store', () => { }; })(); - metaReducerSpy1 = spyOn( - metaReducerContainer, - 'metaReducer1' - ).and.callThrough(); + metaReducerSpy1 = vi.spyOn(metaReducerContainer, 'metaReducer1'); - metaReducerSpy2 = spyOn( - metaReducerContainer, - 'metaReducer2' - ).and.callThrough(); + metaReducerSpy2 = vi.spyOn(metaReducerContainer, 'metaReducer2'); }); it('should create a meta reducer for root and call it through', () => { @@ -529,32 +524,33 @@ describe('ngRx Store', () => { expect(metaReducerSpy2).toHaveBeenCalledWith(counterReducer2); }); - it('should initial state with value', (done: any) => { - const counterInitialState = 2; - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({}), - StoreModule.forFeature( - 'counterState', - { counter: counterReducer }, - { - initialState: { counter: counterInitialState }, - metaReducers: [metaReducerContainer.metaReducer1], - } - ), - ], - }); - - const mockStore = TestBed.inject(Store); - - mockStore.pipe(take(1)).subscribe({ - next(val: any) { - expect(val['counterState'].counter).toEqual(counterInitialState); - }, - error: done, - complete: done, - }); - }); + it('should initial state with value', () => + new Promise((done) => { + const counterInitialState = 2; + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({}), + StoreModule.forFeature( + 'counterState', + { counter: counterReducer }, + { + initialState: { counter: counterInitialState }, + metaReducers: [metaReducerContainer.metaReducer1], + } + ), + ], + }); + + const mockStore = TestBed.inject(Store); + + mockStore.pipe(take(1)).subscribe({ + next(val: any) { + expect(val['counterState'].counter).toEqual(counterInitialState); + }, + error: done, + complete: done, + }); + })); }); describe('Feature config token', () => { @@ -566,87 +562,89 @@ describe('ngRx Store', () => { FEATURE_CONFIG2_TOKEN = new InjectionToken('Feature Config2'); }); - it('should initial state with value', (done: any) => { - const initialState = { counter1: 1 }; - const featureKey = 'counter'; - - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({}), - StoreModule.forFeature( - featureKey, - counterReducer, - FEATURE_CONFIG_TOKEN - ), - ], - providers: [ - { - provide: FEATURE_CONFIG_TOKEN, - useValue: { initialState: initialState }, - }, - ], - }); - - const mockStore = TestBed.inject(Store); - - mockStore.pipe(take(1)).subscribe({ - next(val: any) { - expect(val[featureKey]).toEqual(initialState); - }, - error: done, - complete: done, - }); - }); + it('should initial state with value', () => + new Promise((done) => { + const initialState = { counter1: 1 }; + const featureKey = 'counter'; + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({}), + StoreModule.forFeature( + featureKey, + counterReducer, + FEATURE_CONFIG_TOKEN + ), + ], + providers: [ + { + provide: FEATURE_CONFIG_TOKEN, + useValue: { initialState: initialState }, + }, + ], + }); - it('should initial state with value for multi features', (done: any) => { - const initialState = 1; - const initialState2 = 2; - const initialState3 = 3; - const featureKey = 'counter'; - const featureKey2 = 'counter2'; - const featureKey3 = 'counter3'; + const mockStore = TestBed.inject(Store); - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({}), - StoreModule.forFeature( - featureKey, - counterReducer, - FEATURE_CONFIG_TOKEN - ), - StoreModule.forFeature( - featureKey2, - counterReducer, - FEATURE_CONFIG2_TOKEN - ), - StoreModule.forFeature(featureKey3, counterReducer, { - initialState: initialState3, - }), - ], - providers: [ - { - provide: FEATURE_CONFIG_TOKEN, - useValue: { initialState: initialState }, - }, - { - provide: FEATURE_CONFIG2_TOKEN, - useValue: { initialState: initialState2 }, + mockStore.pipe(take(1)).subscribe({ + next(val: any) { + expect(val[featureKey]).toEqual(initialState); }, - ], - }); + error: done, + complete: done, + }); + })); + + it('should initial state with value for multi features', () => + new Promise((done) => { + const initialState = 1; + const initialState2 = 2; + const initialState3 = 3; + const featureKey = 'counter'; + const featureKey2 = 'counter2'; + const featureKey3 = 'counter3'; + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({}), + StoreModule.forFeature( + featureKey, + counterReducer, + FEATURE_CONFIG_TOKEN + ), + StoreModule.forFeature( + featureKey2, + counterReducer, + FEATURE_CONFIG2_TOKEN + ), + StoreModule.forFeature(featureKey3, counterReducer, { + initialState: initialState3, + }), + ], + providers: [ + { + provide: FEATURE_CONFIG_TOKEN, + useValue: { initialState: initialState }, + }, + { + provide: FEATURE_CONFIG2_TOKEN, + useValue: { initialState: initialState2 }, + }, + ], + }); - const mockStore = TestBed.inject(Store); + const mockStore = TestBed.inject(Store); - mockStore.pipe(take(1)).subscribe({ - next(val: any) { - expect(val[featureKey]).toEqual(initialState); - expect(val[featureKey2]).toEqual(initialState2); - expect(val[featureKey3]).toEqual(initialState3); - }, - error: done, - complete: done, - }); - }); + mockStore.pipe(take(1)).subscribe({ + next(val: any) { + expect(val[featureKey]).toEqual(initialState); + expect(val[featureKey2]).toEqual(initialState2); + expect(val[featureKey3]).toEqual(initialState3); + }, + error: done, + complete: done, + }); + })); it('should create a meta reducer with config injection token and call it with the expected reducer', () => { const metaReducerContainer = (function () { @@ -668,15 +666,9 @@ describe('ngRx Store', () => { }; })(); - const metaReducerSpy1 = spyOn( - metaReducerContainer, - 'metaReducer1' - ).and.callThrough(); + const metaReducerSpy1 = vi.spyOn(metaReducerContainer, 'metaReducer1'); - const metaReducerSpy2 = spyOn( - metaReducerContainer, - 'metaReducer2' - ).and.callThrough(); + const metaReducerSpy2 = vi.spyOn(metaReducerContainer, 'metaReducer2'); TestBed.configureTestingModule({ imports: [ diff --git a/modules/store/spec/types/action_creator.spec.ts b/modules/store/spec/types/action_creator.spec.ts index ad6378fdbb..9b5211ab57 100644 --- a/modules/store/spec/types/action_creator.spec.ts +++ b/modules/store/spec/types/action_creator.spec.ts @@ -162,4 +162,4 @@ describe('createAction()', () => { ); }); }); -}); +}, 8_000); diff --git a/modules/store/spec/types/action_group_creator.spec.ts b/modules/store/spec/types/action_group_creator.spec.ts index a5a36c2afc..df7b07aee6 100644 --- a/modules/store/spec/types/action_group_creator.spec.ts +++ b/modules/store/spec/types/action_group_creator.spec.ts @@ -297,4 +297,4 @@ describe('createActionGroup', () => { testWith(expectSnippet); }); -}); +}, 8_000); diff --git a/modules/store/spec/types/feature_creator.spec.ts b/modules/store/spec/types/feature_creator.spec.ts index 3346b03a33..e96bee080b 100644 --- a/modules/store/spec/types/feature_creator.spec.ts +++ b/modules/store/spec/types/feature_creator.spec.ts @@ -581,4 +581,4 @@ describe('createFeature()', () => { `).toFail(); }); }); -}); +}, 8_000); diff --git a/modules/store/spec/types/reducer_creator.spec.ts b/modules/store/spec/types/reducer_creator.spec.ts index 889667cb59..65916355c5 100644 --- a/modules/store/spec/types/reducer_creator.spec.ts +++ b/modules/store/spec/types/reducer_creator.spec.ts @@ -125,4 +125,4 @@ describe('createReducer()', () => { ); }); }); -}); +}, 8_000); diff --git a/modules/store/spec/types/select.spec.ts b/modules/store/spec/types/select.spec.ts index 8e0f661b21..ab7e9013c9 100644 --- a/modules/store/spec/types/select.spec.ts +++ b/modules/store/spec/types/select.spec.ts @@ -158,4 +158,4 @@ describe('select()', () => { }); }); }); -}); +}, 8_000); diff --git a/modules/store/spec/types/select_signal.spec.ts b/modules/store/spec/types/select_signal.spec.ts index f7e0551584..f8489ad656 100644 --- a/modules/store/spec/types/select_signal.spec.ts +++ b/modules/store/spec/types/select_signal.spec.ts @@ -71,4 +71,4 @@ describe('Store.selectSignal()', () => { }); }); }); -}); +}, 8_000); diff --git a/modules/store/spec/types/selector.spec.ts b/modules/store/spec/types/selector.spec.ts index 160520b440..8ae3e24e81 100644 --- a/modules/store/spec/types/selector.spec.ts +++ b/modules/store/spec/types/selector.spec.ts @@ -37,7 +37,7 @@ describe('createSelector()', () => { selectTest.projector(); `).toSucceed(); }); - }); + }, 8_000); it('should create a selector from selectors dictionary', () => { expectSnippet(` @@ -96,4 +96,4 @@ describe('createSelector() with props', () => { `).toSucceed(); }); }); -}); +}, 8_000); diff --git a/modules/store/spec/types/store.spec.ts b/modules/store/spec/types/store.spec.ts index bc35d5af1f..0d454e5c58 100644 --- a/modules/store/spec/types/store.spec.ts +++ b/modules/store/spec/types/store.spec.ts @@ -57,4 +57,4 @@ describe('Store', () => { ); }); }); -}); +}, 8_000); diff --git a/modules/store/spec/types/store_module.spec.ts b/modules/store/spec/types/store_module.spec.ts index 3f2d7ffbf2..ad0736845a 100644 --- a/modules/store/spec/types/store_module.spec.ts +++ b/modules/store/spec/types/store_module.spec.ts @@ -79,4 +79,4 @@ describe('StoreModule', () => { `).toFail(/No overload matches this call/); }); }); -}); +}, 8_000); diff --git a/modules/store/spec/utils.spec.ts b/modules/store/spec/utils.spec.ts index 6df661cd7f..c22336b270 100644 --- a/modules/store/spec/utils.spec.ts +++ b/modules/store/spec/utils.spec.ts @@ -76,9 +76,7 @@ describe(`Store utils`, () => { describe('createFeatureReducerFactory()', () => { it('should compose a reducer factory from the provided meta reducers', () => { - const metaReducer = jasmine - .createSpy('metaReducer') - .and.callFake((red) => (s: any, a: any) => red(s, a)); + const metaReducer = vi.fn((red) => (s: any, a: any) => red(s, a)); const reducer = (state: any, action: any) => state; const featureReducerFactory = createFeatureReducerFactory([metaReducer]); diff --git a/modules/store/test-setup.ts b/modules/store/test-setup.ts index 3394400c3e..3512059d4b 100644 --- a/modules/store/test-setup.ts +++ b/modules/store/test-setup.ts @@ -1,5 +1,33 @@ -import 'zone.js/plugins/zone-legacy'; -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/store/testing/spec/mock_store.spec.ts b/modules/store/testing/spec/mock_store.spec.ts index a41f93b183..802de00606 100644 --- a/modules/store/testing/spec/mock_store.spec.ts +++ b/modules/store/testing/spec/mock_store.spec.ts @@ -85,21 +85,22 @@ describe('Mock Store with TestBed', () => { expect(fromStore).toBe(fromMockStore); }); - it('should set the initial state to a mocked one', (done: any) => { - const fixedState = { - counter1: 17, - counter2: 11, - counter3: 25, - }; - mockStore.setState(fixedState); - mockStore.pipe(take(1)).subscribe({ - next(val) { - expect(val).toEqual(fixedState); - }, - error: done.fail, - complete: done, - }); - }); + it('should set the initial state to a mocked one', () => + new Promise((done, fail) => { + const fixedState = { + counter1: 17, + counter2: 11, + counter3: 25, + }; + mockStore.setState(fixedState); + mockStore.pipe(take(1)).subscribe({ + next(val) { + expect(val).toEqual(fixedState); + }, + error: fail, + complete: done, + }); + })); it('should allow tracing dispatched actions', () => { const action = { type: INCREMENT }; @@ -311,23 +312,26 @@ describe('Mock Store with Injector', () => { expect(isNgrxMockEnvironment()).toBe(true); }); - it('should provide Store', (done: any) => { - const store: Store = injector.get(Store); + it('should provide Store', () => + new Promise((done) => { + const store: Store = injector.get(Store); - store.pipe(take(1)).subscribe((state) => { - expect(state).toBe(initialState); - done(); - }); - }); + store.pipe(take(1)).subscribe((state) => { + expect(state).toBe(initialState); + done(); + }); + })); - it('should provide MockStore', (done: any) => { - const mockStore: MockStore = injector.get(MockStore); + it('should provide MockStore', () => + new Promise((done) => { + const mockStore: MockStore = + injector.get(MockStore); - mockStore.pipe(take(1)).subscribe((state) => { - expect(state).toBe(initialState); - done(); - }); - }); + mockStore.pipe(take(1)).subscribe((state) => { + expect(state).toBe(initialState); + done(); + }); + })); it('should provide the same instance for Store and MockStore', () => { const store: Store = injector.get(Store); @@ -336,17 +340,19 @@ describe('Mock Store with Injector', () => { expect(store).toBe(mockStore); }); - it('should use a mock selector', (done: any) => { - const mockStore: MockStore = injector.get(MockStore); + it('should use a mock selector', () => + new Promise((done) => { + const mockStore: MockStore = + injector.get(MockStore); - mockStore - .select(mockSelector.selector) - .pipe(take(1)) - .subscribe((selectedValue) => { - expect(selectedValue).toBe(mockSelector.value); - done(); - }); - }); + mockStore + .select(mockSelector.selector) + .pipe(take(1)) + .subscribe((selectedValue) => { + expect(selectedValue).toBe(mockSelector.value); + done(); + }); + })); it('should provide INITIAL_STATE', () => { const providedInitialState = injector.get(INITIAL_STATE); @@ -354,32 +360,36 @@ describe('Mock Store with Injector', () => { expect(providedInitialState).toBe(initialState); }); - it('should provide ActionsSubject', (done: any) => { - const actionsSubject = injector.get(ActionsSubject); + it('should provide ActionsSubject', () => + new Promise((done) => { + const actionsSubject = injector.get(ActionsSubject); - actionsSubject.pipe(take(1)).subscribe((action) => { - expect(action.type).toBe(INIT); - done(); - }); - }); + actionsSubject.pipe(take(1)).subscribe((action) => { + expect(action.type).toBe(INIT); + done(); + }); + })); - it('should provide MockState', (done: any) => { - const mockState: MockState = injector.get(MockState); + it('should provide MockState', () => + new Promise((done) => { + const mockState: MockState = + injector.get(MockState); - mockState.pipe(take(1)).subscribe((state) => { - expect(state).toEqual({}); - done(); - }); - }); + mockState.pipe(take(1)).subscribe((state) => { + expect(state).toEqual({}); + done(); + }); + })); - it('should provide StateObservable', (done: any) => { - const stateObservable = injector.get(StateObservable); + it('should provide StateObservable', () => + new Promise((done) => { + const stateObservable = injector.get(StateObservable); - stateObservable.pipe(take(1)).subscribe((state) => { - expect(state).toEqual({}); - done(); - }); - }); + stateObservable.pipe(take(1)).subscribe((state) => { + expect(state).toEqual({}); + done(); + }); + })); it('should provide the same instance for MockState and StateObservable', () => { const mockState: MockState = injector.get(MockState); @@ -417,22 +427,24 @@ describe('Mock Store with Injector', () => { mockStore = createMockStore({ initialState, selectors: [mockSelector] }); }); - it('should create MockStore', (done: any) => { - mockStore.pipe(take(1)).subscribe((state) => { - expect(state).toBe(initialState); - done(); - }); - }); - - it('should use a mock selector', (done: any) => { - mockStore - .select(mockSelector.selector) - .pipe(take(1)) - .subscribe((selectedValue) => { - expect(selectedValue).toBe(mockSelector.value); + it('should create MockStore', () => + new Promise((done) => { + mockStore.pipe(take(1)).subscribe((state) => { + expect(state).toBe(initialState); done(); }); - }); + })); + + it('should use a mock selector', () => + new Promise((done) => { + mockStore + .select(mockSelector.selector) + .pipe(take(1)) + .subscribe((selectedValue) => { + expect(selectedValue).toBe(mockSelector.value); + done(); + }); + })); }); }); diff --git a/modules/store/tsconfig.schematics.json b/modules/store/tsconfig.schematics.json index 55b625218c..bf71aa511e 100644 --- a/modules/store/tsconfig.schematics.json +++ b/modules/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/store", "paths": { diff --git a/modules/store/tsconfig.spec.json b/modules/store/tsconfig.spec.json index dcb4681eef..ba963ae942 100644 --- a/modules/store/tsconfig.spec.json +++ b/modules/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/store/vite.config.mts b/modules/store/vite.config.mts new file mode 100644 index 0000000000..556f689eaa --- /dev/null +++ b/modules/store/vite.config.mts @@ -0,0 +1,26 @@ +/// + +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', + }, + }; +});