From 66e44ebdcfba153dab4248d3249c7a4f8263a605 Mon Sep 17 00:00:00 2001 From: Andres Martin Date: Fri, 12 Mar 2021 11:31:45 +0100 Subject: [PATCH] Add had* states to request module Add a permanent flag to the request module for knowing when a request had ever been succeeded or errored (even if cleared) --- lib/request/index.js | 32 ++++++++++----- lib/request/index.test.js | 75 +++++++++++++++++++++++++++++++++++ lib/requestById/index.js | 9 +++++ lib/requestById/index.test.js | 75 +++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+), 9 deletions(-) diff --git a/lib/request/index.js b/lib/request/index.js index 44dc1fb..b7748c0 100644 --- a/lib/request/index.js +++ b/lib/request/index.js @@ -10,6 +10,9 @@ const STATES = { const INITIAL_STATE = { state: STATES.EMPTY, error: undefined, + + hadSucceeded: false, + hadErrored: false, } const makeRequestReducer = ({ start, success, error, clear }) => ( @@ -18,6 +21,7 @@ const makeRequestReducer = ({ start, success, error, clear }) => ( ) => { if (matchPattern(start, action)) { return { + ...state, state: STATES.REQUESTING, error: undefined, } @@ -25,45 +29,55 @@ const makeRequestReducer = ({ start, success, error, clear }) => ( if (matchPattern(success, action)) { return { + ...state, state: STATES.SUCCESS, error: undefined, + hadSucceeded: true, } } if (matchPattern(error, action)) { return { + ...state, state: STATES.ERROR, error: action.payload, + hadErrored: true, } } if (matchPattern(clear, action)) { - return INITIAL_STATE + return { + ...INITIAL_STATE, + hadSucceeded: state.hadSucceeded, + hadErrored: state.hadErrored, + } } return state } -makeRequestReducer.getIsEmpty = state => - state.state === STATES.EMPTY +makeRequestReducer.getIsEmpty = state => state.state === STATES.EMPTY -makeRequestReducer.getIsRequesting = state => - state.state === STATES.REQUESTING +makeRequestReducer.getIsRequesting = state => state.state === STATES.REQUESTING makeRequestReducer.getIsRequestSucceeded = state => state.state === STATES.SUCCESS -makeRequestReducer.getIsError = state => - state.state === STATES.ERROR +makeRequestReducer.getIsError = state => state.state === STATES.ERROR -makeRequestReducer.getError = state => - state.error +makeRequestReducer.getError = state => state.error makeRequestReducer.getIsLoading = state => state.state === STATES.EMPTY || state.state === STATES.REQUESTING makeRequestReducer.getIsDone = state => !makeRequestReducer.getIsLoading(state) + +makeRequestReducer.getHadSucceeded = state => state.hadSucceeded + +makeRequestReducer.getHadErrored = state => state.hadErrored + +makeRequestReducer.getHadCompleted = state => state.hadSucceeded || state.hadErrored makeRequestReducer.STATES = STATES diff --git a/lib/request/index.test.js b/lib/request/index.test.js index 5b6a7d4..6548af5 100644 --- a/lib/request/index.test.js +++ b/lib/request/index.test.js @@ -13,6 +13,9 @@ describe('request', () => { expect(request.getError(nextState)).toEqual(undefined) expect(request.getIsLoading(nextState)).toEqual(true) expect(request.getIsDone(nextState)).toEqual(false) + expect(request.getHadSucceeded(nextState)).toEqual(false) + expect(request.getHadErrored(nextState)).toEqual(false) + expect(request.getHadCompleted(nextState)).toEqual(false) }) }) @@ -28,6 +31,9 @@ describe('request', () => { expect(request.getError(nextState)).toEqual(undefined) expect(request.getIsLoading(nextState)).toEqual(true) expect(request.getIsDone(nextState)).toEqual(false) + expect(request.getHadSucceeded(nextState)).toEqual(false) + expect(request.getHadErrored(nextState)).toEqual(false) + expect(request.getHadCompleted(nextState)).toEqual(false) }) it('success', () => { @@ -41,6 +47,9 @@ describe('request', () => { expect(request.getError(nextState)).toEqual(undefined) expect(request.getIsLoading(nextState)).toEqual(false) expect(request.getIsDone(nextState)).toEqual(true) + expect(request.getHadSucceeded(nextState)).toEqual(true) + expect(request.getHadErrored(nextState)).toEqual(false) + expect(request.getHadCompleted(nextState)).toEqual(true) }) it('error', () => { @@ -54,6 +63,9 @@ describe('request', () => { expect(request.getError(nextState)).toEqual('foobar') expect(request.getIsLoading(nextState)).toEqual(false) expect(request.getIsDone(nextState)).toEqual(true) + expect(request.getHadSucceeded(nextState)).toEqual(false) + expect(request.getHadErrored(nextState)).toEqual(true) + expect(request.getHadCompleted(nextState)).toEqual(true) }) it('clear', () => { @@ -67,6 +79,69 @@ describe('request', () => { expect(request.getError(nextState)).toEqual(undefined) expect(request.getIsLoading(nextState)).toEqual(true) expect(request.getIsDone(nextState)).toEqual(false) + expect(request.getHadSucceeded(nextState)).toEqual(false) + expect(request.getHadErrored(nextState)).toEqual(false) + expect(request.getHadCompleted(nextState)).toEqual(false) + }) + }) + + describe('Preserves had* states', () => { + it('preserves hadSuccess', () => { + const reducer = request({ + start: 'START', + success: 'SUCCESS', + error: 'ERROR', + clear: 'CLEAR', + }) + + let nextState = reducer(undefined, { type: 'SUCCESS' }) + + expect(request.getHadSucceeded(nextState)).toEqual(true) + expect(request.getHadCompleted(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'START' }) + + expect(request.getHadSucceeded(nextState)).toEqual(true) + expect(request.getHadCompleted(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'CLEAR' }) + + expect(request.getHadSucceeded(nextState)).toEqual(true) + expect(request.getHadCompleted(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'ERROR' }) + + expect(request.getHadSucceeded(nextState)).toEqual(true) + expect(request.getHadCompleted(nextState)).toEqual(true) + }) + + it('preserves hadSuccess', () => { + const reducer = request({ + start: 'START', + success: 'SUCCESS', + error: 'ERROR', + clear: 'CLEAR', + }) + + let nextState = reducer(undefined, { type: 'ERROR' }) + + expect(request.getHadErrored(nextState)).toEqual(true) + expect(request.getHadCompleted(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'START' }) + + expect(request.getHadErrored(nextState)).toEqual(true) + expect(request.getHadCompleted(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'CLEAR' }) + + expect(request.getHadErrored(nextState)).toEqual(true) + expect(request.getHadCompleted(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'SUCCESS' }) + + expect(request.getHadErrored(nextState)).toEqual(true) + expect(request.getHadCompleted(nextState)).toEqual(true) }) }) }) diff --git a/lib/requestById/index.js b/lib/requestById/index.js index be781cb..a2ac3f3 100644 --- a/lib/requestById/index.js +++ b/lib/requestById/index.js @@ -42,6 +42,15 @@ makeRequestByIdReducer.getIsLoadingById = id => makeRequestByIdReducer.getIsDoneById = id => F.pipe(makeRequestByIdReducer.getById(id), request.getIsDone) +makeRequestByIdReducer.getHadSucceededById = id => + F.pipe(makeRequestByIdReducer.getById(id), request.getHadSucceeded) + +makeRequestByIdReducer.getHadErroredById = id => + F.pipe(makeRequestByIdReducer.getById(id), request.getHadErrored) + +makeRequestByIdReducer.getHadCompletedById = id => + F.pipe(makeRequestByIdReducer.getById(id), request.getHadCompleted) + makeRequestByIdReducer.STATES = request.STATES export default makeRequestByIdReducer diff --git a/lib/requestById/index.test.js b/lib/requestById/index.test.js index 1f68bcd..0a458e1 100644 --- a/lib/requestById/index.test.js +++ b/lib/requestById/index.test.js @@ -13,6 +13,9 @@ describe('requestById', () => { expect(requestById.getErrorById('foo')(nextState)).toEqual(undefined) expect(requestById.getIsLoadingById('foo')(nextState)).toEqual(true) expect(requestById.getIsDoneById('foo')(nextState)).toEqual(false) + expect(requestById.getHadSucceededById('foo')(nextState)).toEqual(false) + expect(requestById.getHadErroredById('foo')(nextState)).toEqual(false) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(false) }) }) @@ -28,6 +31,9 @@ describe('requestById', () => { expect(requestById.getErrorById('foo')(nextState)).toEqual(undefined) expect(requestById.getIsLoadingById('foo')(nextState)).toEqual(true) expect(requestById.getIsDoneById('foo')(nextState)).toEqual(false) + expect(requestById.getHadSucceededById('foo')(nextState)).toEqual(false) + expect(requestById.getHadErroredById('foo')(nextState)).toEqual(false) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(false) }) it('success', () => { @@ -41,6 +47,9 @@ describe('requestById', () => { expect(requestById.getErrorById('foo')(nextState)).toEqual(undefined) expect(requestById.getIsLoadingById('foo')(nextState)).toEqual(false) expect(requestById.getIsDoneById('foo')(nextState)).toEqual(true) + expect(requestById.getHadSucceededById('foo')(nextState)).toEqual(true) + expect(requestById.getHadErroredById('foo')(nextState)).toEqual(false) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(true) }) it('error', () => { @@ -57,6 +66,9 @@ describe('requestById', () => { expect(requestById.getErrorById('foo')(nextState)).toEqual('error') expect(requestById.getIsLoadingById('foo')(nextState)).toEqual(false) expect(requestById.getIsDoneById('foo')(nextState)).toEqual(true) + expect(requestById.getHadSucceededById('foo')(nextState)).toEqual(false) + expect(requestById.getHadErroredById('foo')(nextState)).toEqual(true) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(true) }) it('clear', () => { @@ -70,6 +82,69 @@ describe('requestById', () => { expect(requestById.getErrorById('foo')(nextState)).toEqual(undefined) expect(requestById.getIsLoadingById('foo')(nextState)).toEqual(true) expect(requestById.getIsDoneById('foo')(nextState)).toEqual(false) + expect(requestById.getHadSucceededById('foo')(nextState)).toEqual(false) + expect(requestById.getHadErroredById('foo')(nextState)).toEqual(false) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(false) + }) + }) + + describe('Preserves had* states', () => { + it('preserves hadSuccess', () => { + const reducer = requestById({ + start: 'START', + success: 'SUCCESS', + error: 'ERROR', + clear: 'CLEAR', + }) + + let nextState = reducer(undefined, { type: 'SUCCESS', payload: { id: 'foo' } }) + + expect(requestById.getHadSucceededById('foo')(nextState)).toEqual(true) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'START', payload: { id: 'foo' } }) + + expect(requestById.getHadSucceededById('foo')(nextState)).toEqual(true) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'CLEAR', payload: { id: 'foo' } }) + + expect(requestById.getHadSucceededById('foo')(nextState)).toEqual(true) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'ERROR', payload: { id: 'foo' } }) + + expect(requestById.getHadSucceededById('foo')(nextState)).toEqual(true) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(true) + }) + + it('preserves hadSuccess', () => { + const reducer = requestById({ + start: 'START', + success: 'SUCCESS', + error: 'ERROR', + clear: 'CLEAR', + }) + + let nextState = reducer(undefined, { type: 'ERROR', payload: { id: 'foo' } }) + + expect(requestById.getHadErroredById('foo')(nextState)).toEqual(true) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'START', payload: { id: 'foo' } }) + + expect(requestById.getHadErroredById('foo')(nextState)).toEqual(true) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'CLEAR', payload: { id: 'foo' } }) + + expect(requestById.getHadErroredById('foo')(nextState)).toEqual(true) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(true) + + nextState = reducer(nextState, { type: 'SUCCESS', payload: { id: 'foo' } }) + + expect(requestById.getHadErroredById('foo')(nextState)).toEqual(true) + expect(requestById.getHadCompletedById('foo')(nextState)).toEqual(true) }) }) })