Skip to content

Commit

Permalink
Added ObservableStore.resetState() API and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Wahlin authored and Dan Wahlin committed Feb 29, 2020
1 parent 7b4d17f commit ad850cb
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 12 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -554,24 +554,25 @@ Observable Store provides a simple API that can be used to get/set state, subscr
Functions | Description
| ----------------------------------------------| -----------------------------------------------------
| `static addExtension(extension: ObservableStoreExtension)` | Used to add an extension into ObservableStore. The extension must implement the `ObservableStoreExtension` interface.
| `static initializeState(state: any)` | Used to initialize the store's state. An error will be thrown if this is called and store state already exists so this should be set when the application first loads. No notifications are sent out to store subscribers when the store state is initialized.
| `dispatchState(stateChanges: Partial<T>, dispatchGlobalState: boolean = true) : T` | Dispatch the store's state without modifying the state. Service state can be dispatched as well as the global store state. If `dispatchGlobalState` is false then global state will not be dispatched to subscribers (defaults to `true`).
| `getState() : T` | Retrieve store's state. If using TypeScript (optional) then the state type defined when the store was created will be returned rather than `any`.
| `logStateAction(state: any, action: string): void` | Add a custom state value and action into the state history. Assumes `trackStateHistory` setting was set on store or using the global settings.
| `resetStateHistory(): void` | Reset the store's state history to an empty array.
| `setState(state: T, action: string, dispatchState: boolean = true) : T` | Set the store state. Pass the state to be updated as well as the action that is occuring. The state value can be a function (see example below). The latest store state is returned and any store subscribers are notified of the state change. The dispatchState parameter can be set to `false` if you do not want to send state change notifications to subscribers.
| `static addExtension(extension: ObservableStoreExtension)` | Used to add an extension into ObservableStore. The extension must implement the `ObservableStoreExtension` interface.
| `static initializeState(state: any)` | Used to initialize the store's state. An error will be thrown if this is called and store state already exists so this should be set when the application first loads. No notifications are sent out to store subscribers when the store state is initialized.
| `static resetState(state)` | Used to reset the state of the store to a desired value for all services that derive from ObservableStore<T>. A state change notification and global state change notification is sent out to subscribers if the dispatchState parameter is true (the default value).
<br>

Properties | Description
| ----------------------------------------------| -----------------------------------------------------
| `static allStoreServices: any[]`| Provides access to all services that interact with ObservableStore. Useful for extensions that need to be able to access a specific service.
| `static globalSettings: ObservableStoreGlobalSettings`| get/set global settings throughout the application for ObservableStore. See the [Observable Store Settings](#settings) below for additional information. Note that global settings can only be set once as the application first loads.
| `globalStateChanged: Observable<any>` | Subscribe to global store changes i.e. changes in any slice of state of the store. The global store may consist of 'n' slices of state each managed by a particular service. This property notifies of a change in any of the 'n' slices of state. Returns an RxJS Observable containing the current store state.
| `globalStateWithPropertyChanges: Observable<StateWithPropertyChanges<any>>` | Subscribe to global store changes i.e. changes in any slice of state of the store and also include the properties that changed as well. The global store may consist of 'n' slices of state each managed by a particular service. This property notifies of a change in any of the 'n' slices of state. Upon subscribing to `globalStateWithPropertyChanges` you will get back an object containing `state` (which has the current store state) and `stateChanges` (which has the individual properties/data that were changed in the store).
| `stateChanged: Observable<T>` | Subscribe to store changes in the particlar slice of state updated by a Service. If the store contains 'n' slices of state each being managed by one of 'n' services, then changes in any of the other slices of state will not generate values in the stateChanged stream. Returns an RxJS Observable containing the current store state (or a specific slice of state if a stateSliceSelector has been specified).
| `stateWithPropertyChanges: Observable<StateWithPropertyChanges<T>>` | Subscribe to store changes in the particlar slice of state updated by a Service and also include the properties that changed as well. Upon subscribing to `stateWithPropertyChanges` you will get back an object containing `state` (which has the current slice of store state) and `stateChanges` (which has the individual properties/data that were changed in the store).
| `stateHistory: StateHistory` | Retrieve state history. Assumes `trackStateHistory` setting was set on the store.
| `static allStoreServices: any[]`| Provides access to all services that interact with ObservableStore. Useful for extensions that need to be able to access a specific service.
| `static globalSettings: ObservableStoreGlobalSettings`| get/set global settings throughout the application for ObservableStore. See the [Observable Store Settings](#settings) below for additional information. Note that global settings can only be set once as the application first loads.
<br>

Note that TypeScript types are used to describe parameters and return types above. TypeScript is not required to use Observable Store though.
Expand Down
17 changes: 9 additions & 8 deletions modules/observable-store/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -554,24 +554,25 @@ Observable Store provides a simple API that can be used to get/set state, subscr
Functions | Description
| ----------------------------------------------| -----------------------------------------------------
| `static addExtension(extension: ObservableStoreExtension)` | Used to add an extension into ObservableStore. The extension must implement the `ObservableStoreExtension` interface.
| `static initializeState(state: any)` | Used to initialize the store's state. An error will be thrown if this is called and store state already exists so this should be set when the application first loads. No notifications are sent out to store subscribers when the store state is initialized.
| `dispatchState(stateChanges: Partial<T>, dispatchGlobalState: boolean = true) : T` | Dispatch the store's state without modifying the state. Service state can be dispatched as well as the global store state. If `dispatchGlobalState` is false then global state will not be dispatched to subscribers (defaults to `true`).
| `getState() : T` | Retrieve store's state. If using TypeScript (optional) then the state type defined when the store was created will be returned rather than `any`.
| `logStateAction(state: any, action: string): void` | Add a custom state value and action into the state history. Assumes `trackStateHistory` setting was set on store or using the global settings.
| `resetStateHistory(): void` | Reset the store's state history to an empty array.
| `setState(state: T, action: string, dispatchState: boolean = true) : T` | Set the store state. Pass the state to be updated as well as the action that is occuring. The state value can be a function (see example below). The latest store state is returned and any store subscribers are notified of the state change. The dispatchState parameter can be set to `false` if you do not want to send state change notifications to subscribers.
| `static addExtension(extension: ObservableStoreExtension)` | Used to add an extension into ObservableStore. The extension must implement the `ObservableStoreExtension` interface.
| `static initializeState(state: any)` | Used to initialize the store's state. An error will be thrown if this is called and store state already exists so this should be set when the application first loads. No notifications are sent out to store subscribers when the store state is initialized.
| `static resetState(state)` | Used to reset the state of the store to a desired value for all services that derive from ObservableStore<T>. A state change notification and global state change notification is sent out to subscribers if the dispatchState parameter is true (the default value).
<br>

Properties | Description
| ----------------------------------------------| -----------------------------------------------------
| `static allStoreServices: any[]`| Provides access to all services that interact with ObservableStore. Useful for extensions that need to be able to access a specific service.
| `static globalSettings: ObservableStoreGlobalSettings`| get/set global settings throughout the application for ObservableStore. See the [Observable Store Settings](#settings) below for additional information. Note that global settings can only be set once as the application first loads.
| `globalStateChanged: Observable<any>` | Subscribe to global store changes i.e. changes in any slice of state of the store. The global store may consist of 'n' slices of state each managed by a particular service. This property notifies of a change in any of the 'n' slices of state. Returns an RxJS Observable containing the current store state.
| `globalStateWithPropertyChanges: Observable<StateWithPropertyChanges<any>>` | Subscribe to global store changes i.e. changes in any slice of state of the store and also include the properties that changed as well. The global store may consist of 'n' slices of state each managed by a particular service. This property notifies of a change in any of the 'n' slices of state. Upon subscribing to `globalStateWithPropertyChanges` you will get back an object containing `state` (which has the current store state) and `stateChanges` (which has the individual properties/data that were changed in the store).
| `stateChanged: Observable<T>` | Subscribe to store changes in the particlar slice of state updated by a Service. If the store contains 'n' slices of state each being managed by one of 'n' services, then changes in any of the other slices of state will not generate values in the stateChanged stream. Returns an RxJS Observable containing the current store state (or a specific slice of state if a stateSliceSelector has been specified).
| `stateWithPropertyChanges: Observable<StateWithPropertyChanges<T>>` | Subscribe to store changes in the particlar slice of state updated by a Service and also include the properties that changed as well. Upon subscribing to `stateWithPropertyChanges` you will get back an object containing `state` (which has the current slice of store state) and `stateChanges` (which has the individual properties/data that were changed in the store).
| `stateHistory: StateHistory` | Retrieve state history. Assumes `trackStateHistory` setting was set on the store.
| `static allStoreServices: any[]`| Provides access to all services that interact with ObservableStore. Useful for extensions that need to be able to access a specific service.
| `static globalSettings: ObservableStoreGlobalSettings`| get/set global settings throughout the application for ObservableStore. See the [Observable Store Settings](#settings) below for additional information. Note that global settings can only be set once as the application first loads.
<br>

Note that TypeScript types are used to describe parameters and return types above. TypeScript is not required to use Observable Store though.
Expand Down Expand Up @@ -920,13 +921,13 @@ Minor updates to the Observable Store docs. Fixed a bug in the Redux DevTools ex

Thanks to <a href="https://github.com/riscie" target="_blank">Matthias Langhard</a> for the feedback and discussion on these changes.

### Building the Project

See the `README.md` file in the `modules` folder.

#### 2.2.5 - February 26, 2020

- Added `ObservableStore.initializeState()` API.
- Refactored unit tests.

### Building the Project

See the `README.md` file in the `modules` folder.


17 changes: 17 additions & 0 deletions modules/observable-store/observable-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,23 @@ export class ObservableStore<T> {
ObservableStoreBase.initializeState(state);
}

/**
* Used to reset the state of the store to a desired value for all services that derive
* from ObservableStore<T> to a desired value.
* A state change notification and global state change notification is sent out to subscribers if the dispatchState parameter is true (the default value).
*/
static resetState(state: any, dispatchState: boolean = true) {
ObservableStoreBase.setStoreState(state);
if (dispatchState) {
const services = ObservableStore.allStoreServices;
if (services) {
for (const service of services) {
service.dispatchState(state);
}
}
}
}

/**
* Retrieve store's state. If using TypeScript (optional) then the state type defined when the store
* was created will be returned rather than `any`.
Expand Down
23 changes: 23 additions & 0 deletions modules/observable-store/tests/observable-store.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ describe('Observable Store', () => {
expect(mockStore.currentState.prop1).toEqual('test');
});

it('should change reset the store state', () => {
mockStore.updateProp1('test');
ObservableStore.resetState(null);
expect(mockStore.currentState).toBe(null);
});

it('should execute an anonymous function', () => {
const capitalizeProp1: stateFunc<MockState> = (state: MockState) => {
state.prop1 = state.prop1.toLocaleUpperCase();
Expand Down Expand Up @@ -76,6 +82,23 @@ describe('Observable Store', () => {
sub.unsubscribe();
});

// we will skip 1 to account for the initial BehaviorSubject<T> value
it('should receive notification when state has been reset', () => {
let receivedUpdate = false;
let receivedState = null;
const sub = mockStore.stateChanged.pipe(skip(1)).subscribe((state) => {
receivedUpdate = true;
receivedState = state;
});
mockStore.updateProp1('initial state');
ObservableStore.resetState({ prop1: 'state reset', prop2: null, user: null, users: null });

expect(receivedUpdate).toBeTruthy();
expect(receivedState.prop1).toEqual('state reset');
expect(receivedState.prop2).toBe(null);
sub.unsubscribe();
});

// deprecated
// we will skip 1 to account for the initial BehaviorSubject<T> value
it('should receive state notification when includeStateChangesOnSubscribe set [deprecated]', () => {
Expand Down

0 comments on commit ad850cb

Please sign in to comment.