diff --git a/packages/store/src/internal/state-stream.ts b/packages/store/src/internal/state-stream.ts index 01da3b886..6d9717f2a 100644 --- a/packages/store/src/internal/state-stream.ts +++ b/packages/store/src/internal/state-stream.ts @@ -3,13 +3,19 @@ import { BehaviorSubject } from 'rxjs'; import { PlainObject } from '@ngxs/store/internals'; +import { InternalNgxsExecutionStrategy } from '../execution/internal-ngxs-execution-strategy'; + /** * BehaviorSubject of the entire state. * @ignore */ @Injectable() export class StateStream extends BehaviorSubject { - constructor() { + constructor(private _ngxsExecutionStrategy: InternalNgxsExecutionStrategy) { super({}); } + + next(value: PlainObject): void { + this._ngxsExecutionStrategy.leave(() => super.next(value)); + } } diff --git a/packages/store/tests/issues/issue-933-selectors-causing-ticks.spec.ts b/packages/store/tests/issues/issue-933-selectors-causing-ticks.spec.ts index 90fa2221a..7b173a7f1 100644 --- a/packages/store/tests/issues/issue-933-selectors-causing-ticks.spec.ts +++ b/packages/store/tests/issues/issue-933-selectors-causing-ticks.spec.ts @@ -53,7 +53,7 @@ describe('Selectors within templates causing ticks (https://github.com/ngxs/stor class TestModule {} it( - 'should run change detection whenever the selector emits after asynchronous action has been completed', + 'should not run change detection whenever the selector emits after asynchronous action has been completed', freshPlatform(async () => { // Arrange const { injector } = await skipConsoleLogging(() => @@ -68,7 +68,7 @@ describe('Selectors within templates causing ticks (https://github.com/ngxs/stor // Assert try { - expect(spy.mock.calls.length).toBeGreaterThan(count); + expect(spy).toHaveBeenCalledTimes(3); } finally { spy.mockRestore(); } diff --git a/packages/store/tests/zone.spec.ts b/packages/store/tests/zone.spec.ts index 03b165cb3..423bcb351 100644 --- a/packages/store/tests/zone.spec.ts +++ b/packages/store/tests/zone.spec.ts @@ -25,53 +25,10 @@ describe('zone', () => { } } - describe('[store.select]', () => { - it('should be performed inside Angular zone', () => { - let ticks = 0; - - class MockApplicationRef extends ApplicationRef { - public tick(): void { - ticks++; - } - } - - TestBed.configureTestingModule({ - imports: [NgxsModule.forRoot([CounterState])], - providers: [ - { - provide: ApplicationRef, - useClass: MockApplicationRef - } - ] - }); - - const store: Store = TestBed.inject(Store); - const zone: NgZone = TestBed.inject(NgZone); - - // NGXS performes initializions inside Angular zone - // thus it causes app to tick - expect(ticks).toBeGreaterThan(0); - - zone.runOutsideAngular(() => { - store - .select(({ counter }) => counter) - .pipe(take(3)) - .subscribe(() => { - expect(NgZone.isInAngularZone()).toBeTruthy(); - }); - - store.dispatch(new Increment()); - store.dispatch(new Increment()); - }); - - // Angular has run change detection 5 times - expect(ticks).toBe(5); - }); - }); - // ============================================================= it('"select" should be performed inside Angular zone', () => { let ticks = 0; + let selectCallsInAngularZone = 0; class MockApplicationRef extends ApplicationRef { public tick(): void { @@ -94,22 +51,25 @@ describe('zone', () => { // NGXS performes initializions inside Angular zone // thus it causes app to tick - expect(ticks).toBeGreaterThan(0); + expect(ticks).toEqual(4); zone.runOutsideAngular(() => { store .select(({ counter }) => counter) .pipe(take(3)) .subscribe(() => { - expect(NgZone.isInAngularZone()).toBeTruthy(); + if (NgZone.isInAngularZone()) { + selectCallsInAngularZone++; + } }); store.dispatch(new Increment()); store.dispatch(new Increment()); }); - // Angular has run change detection 5 times - expect(ticks).toBe(5); + // Angular has run change detection 7 times + expect(ticks).toBe(7); + expect(selectCallsInAngularZone).toEqual(3); }); it('"select" should be performed outside Angular zone', () => {