Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

revert(Store): store should fail synchronously #1871

Merged
merged 2 commits into from
May 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 93 additions & 102 deletions modules/store/spec/runtime_checks.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as ngCore from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { TestBed, fakeAsync, flush } from '@angular/core/testing';
import { Store, StoreModule, META_REDUCERS } from '..';
import { createActiveRuntimeChecks } from '../src/runtime_checks';
import { RuntimeChecks } from '../src/models';
Expand Down Expand Up @@ -113,32 +113,29 @@ describe('Runtime checks:', () => {
describe('State Serialization:', () => {
const invalidAction = () => ({ type: ErrorTypes.UnserializableState });

it('should throw when enabled', (done: DoneFn) => {
const store = setupStore({ strictStateSerializability: true });

store.subscribe({
error: err => {
expect(err).toMatch(/Detected unserializable state/);
done();
},
});

store.dispatch(invalidAction());
});

it('should not throw when disabled', (done: DoneFn) => {
const store = setupStore({ strictStateSerializability: false });

store.subscribe({
next: ({ state }) => {
if (state.invalidSerializationState) {
done();
}
},
});

store.dispatch(invalidAction());
});
it(
'should throw when enabled',
fakeAsync(() => {
const store = setupStore({ strictStateSerializability: true });

expect(() => {
store.dispatch(invalidAction());
flush();
}).toThrowError(/Detected unserializable state/);
})
);

it(
'should not throw when disabled',
fakeAsync(() => {
const store = setupStore({ strictStateSerializability: false });

expect(() => {
store.dispatch(invalidAction());
flush();
}).not.toThrow();
})
);
});

describe('Action Serialization:', () => {
Expand All @@ -147,63 +144,59 @@ describe('Runtime checks:', () => {
invalid: new Date(),
});

it('should throw when enabled', (done: DoneFn) => {
const store = setupStore({ strictActionSerializability: true });

store.subscribe({
error: err => {
expect(err).toMatch(/Detected unserializable action/);
done();
},
});
store.dispatch(invalidAction());
});

it('should not throw when disabled', (done: DoneFn) => {
const store = setupStore({ strictActionSerializability: false });

store.subscribe({
next: ({ state }) => {
if (state.invalidSerializationAction) {
done();
}
},
});

store.dispatch(invalidAction());
});
it(
'should throw when enabled',
fakeAsync(() => {
const store = setupStore({ strictActionSerializability: true });

expect(() => {
store.dispatch(invalidAction());
flush();
}).toThrowError(/Detected unserializable action/);
})
);

it(
'should not throw when disabled',
fakeAsync(() => {
const store = setupStore({ strictActionSerializability: false });

expect(() => {
store.dispatch(invalidAction());
flush();
}).not.toThrow();
})
);
});

describe('State Mutations', () => {
const invalidAction = () => ({
type: ErrorTypes.MutateState,
});

it('should throw when enabled', (done: DoneFn) => {
const store = setupStore({ strictImmutability: true });

store.subscribe({
error: _ => {
done();
},
});

store.dispatch(invalidAction());
});

it('should not throw when disabled', (done: DoneFn) => {
const store = setupStore({ strictImmutability: false });

store.subscribe({
next: ({ state }) => {
if (state.invalidMutationState) {
done();
}
},
});

store.dispatch(invalidAction());
});
it(
'should throw when enabled',
fakeAsync(() => {
const store = setupStore({ strictImmutability: true });

expect(() => {
store.dispatch(invalidAction());
flush();
}).toThrowError(/Cannot add property/);
})
);

it(
'should not throw when disabled',
fakeAsync(() => {
const store = setupStore({ strictImmutability: false });

expect(() => {
store.dispatch(invalidAction());
flush();
}).not.toThrow();
})
);
});

describe('Action Mutations', () => {
Expand All @@ -212,31 +205,29 @@ describe('Runtime checks:', () => {
foo: 'foo',
});

it('should throw when enabled', (done: DoneFn) => {
const store = setupStore({ strictImmutability: true });

store.subscribe({
error: _ => {
done();
},
});

store.dispatch(invalidAction());
});

it('should not throw when disabled', (done: DoneFn) => {
const store = setupStore({ strictImmutability: false });

store.subscribe({
next: ({ state }) => {
if (state.invalidMutationAction) {
done();
}
},
});

store.dispatch(invalidAction());
});
it(
'should throw when enabled',
fakeAsync(() => {
const store = setupStore({ strictImmutability: true });

expect(() => {
store.dispatch(invalidAction());
flush();
}).toThrowError(/Cannot assign to read only property/);
})
);

it(
'should not throw when disabled',
fakeAsync(() => {
const store = setupStore({ strictImmutability: false });

expect(() => {
store.dispatch(invalidAction());
flush();
}).not.toThrow();
})
);
});
});

Expand Down
35 changes: 28 additions & 7 deletions modules/store/spec/state.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { TestBed } from '@angular/core/testing';
import { INIT, Store, StoreModule } from '@ngrx/store';
import { TestBed, fakeAsync, flush } from '@angular/core/testing';
import { INIT, Store, StoreModule, Action } from '@ngrx/store';

describe('ngRx State', () => {
const initialState = 123;
const reducer = jasmine.createSpy('reducer').and.returnValue(initialState);
it('should call the reducer to scan over the dispatcher', () => {
const initialState = 123;
const reducer = jasmine.createSpy('reducer').and.returnValue(initialState);

beforeEach(() => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot(
Expand All @@ -14,13 +14,34 @@ describe('ngRx State', () => {
),
],
});
});

it('should call the reducer to scan over the dispatcher', function() {
TestBed.get(Store);

expect(reducer).toHaveBeenCalledWith(initialState, {
type: INIT,
});
});

it(
'should fail synchronously',
fakeAsync(() => {
function reducer(state: any, action: Action) {
if (action.type === 'THROW_ERROR') {
throw new Error('(╯°□°)╯︵ ┻━┻');
}

return state;
}

TestBed.configureTestingModule({
imports: [StoreModule.forRoot({ reducer })],
});

const store = TestBed.get(Store) as Store<any>;
expect(() => {
store.dispatch({ type: 'THROW_ERROR' });
flush();
}).toThrow();
})
);
});
9 changes: 3 additions & 6 deletions modules/store/src/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,9 @@ export class State<T> extends BehaviorSubject<any> implements OnDestroy {
)
);

this.stateSubscription = stateAndAction$.subscribe({
next: ({ state, action }) => {
this.next(state);
scannedActions.next(action);
},
error: err => this.error(err),
this.stateSubscription = stateAndAction$.subscribe(({ state, action }) => {
this.next(state);
scannedActions.next(action);
});
}

Expand Down