Skip to content

Commit

Permalink
Polish code and improve tests
Browse files Browse the repository at this point in the history
  • Loading branch information
emanueleDiVizio committed Oct 18, 2019
1 parent 7e5ddae commit df12a54
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 52 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ type MiddlewareConfig = {
regexActionType?: RegExp = /FETCH.*REQUEST/,
actionTypes?: Array<string> = [],
queueReleaseThrottle?: number = 50,
shouldDequeueSelector: (state: State) => boolean = state => state.conditionToReleaseQueue
shouldDequeueSelector: (state: RootReduxState) => boolean = () => true
}
```

Expand All @@ -361,7 +361,7 @@ By default it's configured to intercept actions for fetching data following the

`queueReleaseThrottle`: waiting time in ms between dispatches when flushing the offline queue. Useful to reduce the server pressure when coming back online. Defaults to 50ms.

`shouldDequeueSelector`: state selector used to control if the queue should be released on connection change. Returning `true` releases the queue, returning `false` prevents queue release. Note, if the result of `shouldDequeueSelector` changes *while* the queue is being released, the queue will not halt. If you want to halt the queue *while* is being released, please see relevant FAQ section.
`shouldDequeueSelector`: function that receives the redux application state and returns a boolean. It'll be executed every time an action is dispatched, before it reaches the reducer. This is useful to control if the queue should be released when the connection is regained and there were actions queued up. Returning `true` (the default behaviour) releases the queue, whereas returning `false` prevents queue release. For example, you may wanna perform some authentication checks, prior to releasing the queue. Note, if the result of `shouldDequeueSelector` changes *while* the queue is being released, the queue will not halt. If you want to halt the queue *while* is being released, please see relevant FAQ section.


##### Thunks Config
Expand Down
16 changes: 13 additions & 3 deletions src/redux/createNetworkMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,20 @@ function didQueueResume(action, isQueuePaused) {
);
}

export const createReleaseQueue = (getState, next, delay) => async queue => {
export const createReleaseQueue = (
getState,
next,
delay,
shouldDequeueSelector,
) => async queue => {
// eslint-disable-next-line
for (const action of queue) {
const { isConnected, isQueuePaused } = getState().network;
if (isConnected && !isQueuePaused) {
const state = getState();
const {
network: { isConnected, isQueuePaused },
} = state;

if (isConnected && !isQueuePaused && shouldDequeueSelector(state)) {
next(removeActionFromQueue(action));
next(action);
// eslint-disable-next-line
Expand All @@ -109,6 +118,7 @@ function createNetworkMiddleware({
getState,
next,
queueReleaseThrottle,
shouldDequeueSelector,
);
validateParams(regexActionType, actionTypes);

Expand Down
3 changes: 2 additions & 1 deletion src/redux/createReducer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* @flow */

import { get, without } from 'lodash';
import { SEMAPHORE_COLOR } from '../utils/constants';
import actionTypes from './actionTypes';
import getSimilarActionInQueue from '../utils/getSimilarActionInQueue';
import type {
Expand Down Expand Up @@ -89,7 +90,7 @@ function handleChangeQueueSemaphore(
): NetworkState {
return {
...state,
isQueuePaused: semaphoreColor === 'RED',
isQueuePaused: semaphoreColor === SEMAPHORE_COLOR.RED,
};
}

Expand Down
95 changes: 57 additions & 38 deletions test/createNetworkMiddleware.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,15 +393,46 @@ describe('createNetworkMiddleware with dismissing actions functionality', () =>
});
});

describe('createNetworkMiddleware with queueDeselector', () => {
const mockDequeueSelector = jest.fn();
const networkMiddleware = createNetworkMiddleware({
shouldDequeueSelector: mockDequeueSelector,
});
const middlewares = [networkMiddleware];
const mockStore = configureStore(middlewares);

it('Proxies action to next middleware if deselector returns false', () => {
const initialState = {
network: {
isConnected: true,
actionQueue: [],
},
};
const store = mockStore(initialState);
const action = getFetchAction('REFRESH_DATA');
store.dispatch(action);

const actions = store.getActions();
expect(actions).toEqual([getFetchAction('REFRESH_DATA')]);
});
});

describe('createReleaseQueue', () => {
const mockDispatch = jest.fn();
const mockGetState = jest.fn().mockImplementation(() => ({
network: {
isConnected: true,
isQueuePaused: false,
},
}));
const mockGetState = jest.fn();
const mockDequeueSelector = jest.fn();
const mockDelay = 50;

beforeEach(() => {
mockDequeueSelector.mockImplementation(() => true);
mockGetState.mockImplementation(() => ({
network: {
isConnected: true,
isQueuePaused: false,
},
}));
});

afterEach(() => {
mockDispatch.mockClear();
mockGetState.mockClear();
Expand All @@ -412,6 +443,7 @@ describe('createReleaseQueue', () => {
mockGetState,
mockDispatch,
mockDelay,
mockDequeueSelector,
);
const actionQueue = ['foo', 'bar'];
await releaseQueue(actionQueue);
Expand All @@ -428,7 +460,7 @@ describe('createReleaseQueue', () => {
expect(mockDispatch).toHaveBeenNthCalledWith(4, 'bar');
});

it('does not empty the queue if we are online and dequeue selector returns false', async () => {
it('does not empty the queue if dequeue selector returns false', async () => {
const mockDequeueSelector = () => false;
const releaseQueue = createReleaseQueue(
mockGetState,
Expand All @@ -438,17 +470,24 @@ describe('createReleaseQueue', () => {
);
const actionQueue = ['foo', 'bar'];
await releaseQueue(actionQueue);
expect(mockDispatch).toHaveBeenCalledTimes(4);
expect(mockDispatch).toHaveBeenNthCalledWith(
1,
actionCreators.removeActionFromQueue('foo'),
);
expect(mockDispatch).toHaveBeenNthCalledWith(2, 'foo');
expect(mockDispatch).toHaveBeenNthCalledWith(
3,
actionCreators.removeActionFromQueue('bar'),
expect(mockDispatch).toHaveBeenCalledTimes(0);
});

it('does not empty the queue if queue has been halted', async () => {
mockGetState.mockImplementation(() => ({
network: {
isQueuePaused: true,
},
}));
const releaseQueue = createReleaseQueue(
mockGetState,
mockDispatch,
mockDelay,
mockDequeueSelector,
);
expect(mockDispatch).toHaveBeenNthCalledWith(4, 'bar');
const actionQueue = ['foo', 'bar'];
await releaseQueue(actionQueue);
expect(mockDispatch).toHaveBeenCalledTimes(0);
});

it('dispatches only during the online window', async () => {
Expand All @@ -466,6 +505,7 @@ describe('createReleaseQueue', () => {
mockGetState,
mockDispatch,
mockDelay,
mockDequeueSelector,
);
const actionQueue = ['foo', 'bar'];
await Promise.all([releaseQueue(actionQueue), switchToOffline()]);
Expand All @@ -476,27 +516,6 @@ describe('createReleaseQueue', () => {
);
expect(mockDispatch).toHaveBeenNthCalledWith(2, 'foo');
});

it('should stop dispatching if queue has been halted', async () => {
const haltQueue = () =>
new Promise(async resolve => {
await wait(30);
mockGetState.mockImplementation(() => ({
network: {
isQueuePaused: true,
},
}));
resolve();
});
const releaseQueue = createReleaseQueue(
mockGetState,
mockDispatch,
mockDelay,
);
const actionQueue = ['foo', 'bar'];
await Promise.all([releaseQueue(actionQueue), haltQueue()]);
expect(mockDispatch).toHaveBeenCalledTimes(0);
});
});

describe('createNetworkMiddleware with wrong type params', () => {
Expand Down
8 changes: 0 additions & 8 deletions test/reducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -406,11 +406,3 @@ describe('networkSelector', () => {
});
});
});

describe('network reducer config', () => {
it('has isQueuePaused set to false by default', () => {
expect(networkReducer(undefined, { type: 'ACTION_I_DONT_CARE' })).toEqual(
initialState,
);
});
});

0 comments on commit df12a54

Please sign in to comment.