diff --git a/README.md b/README.md
index d1efcb7..cbef566 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,8 @@ To solve the problems listed above, `redux-rest-easy` **generates actions, reduc
It also provides **sensible defaults**, allowing you to use it with **almost no configuration**, but also to **customize** anything you would like.
+And the cherry on the top: it works seamlessly with [redux-offline](https://github.com/redux-offline/redux-offline) and [redux-persist](https://github.com/rt2zz/redux-persist)!
+
[Scroll down](#minimal-example) for a small example, or [browse the documentation](#api) to get started! To learn more about the problem and solution, you can also read the [release article][release-article].
## API
@@ -61,6 +63,7 @@ import {
* [connect](./docs/api/connect.md) - connect your components to the state so the magic can happen
* [reset](./docs/api/reset.md) - reset `redux-rest-easy`'s whole state (you can reset parts of the state with actions generated by `createResource`)
* [initializeNetworkHelpers](./docs/api/initializeNetworkHelpers.md) - provide your own network handlers (optional, fallback to included defaults)
+* [getPersistableState](./docs/api/getPersistableState.md) - transform the state before storing it, in order to later persist it (using [redux-offline](https://github.com/redux-offline/redux-offline), [redux-persist](https://github.com/rt2zz/redux-persist), or friends)
## Internals
@@ -70,10 +73,10 @@ import {
## Core principles
-1. [Preflight checks](./docs/principles/preflight.md)
-2. [Actions](./docs/principles/actions.md)
-3. [Reducers](./docs/principles/reducers.md)
-4. [Selectors](./docs/principles/selectors.md)
+1. [Preflight checks](./docs/principles/preflight.md)
+2. [Actions](./docs/principles/actions.md)
+3. [Reducers](./docs/principles/reducers.md)
+4. [Selectors](./docs/principles/selectors.md)
## Minimal Example
@@ -86,7 +89,7 @@ const users = createResource('users')({
retrieve: {
method: 'GET',
url: 'https://my-api.com/users',
- afterHook: () => console.log('Users retrieved successfuly'),
+ afterHook: () => console.log('Users retrieved successfully'),
},
});
@@ -178,9 +181,11 @@ Redux-rest-easy also uses [redux-thunk][redux-thunk] to handle async actions, an
Thanks goes to these people ([emoji key][emojis]):
+
| [
Adrien HARNAY](https://adrien.harnay.me)
[📝](#blog-Zephir77167 "Blogposts") [💻](https://github.com/Brigad/redux-rest-easy/commits?author=Zephir77167 "Code") [📖](https://github.com/Brigad/redux-rest-easy/commits?author=Zephir77167 "Documentation") [🤔](#ideas-Zephir77167 "Ideas, Planning, & Feedback") [🚇](#infra-Zephir77167 "Infrastructure (Hosting, Build-Tools, etc)") [👀](#review-Zephir77167 "Reviewed Pull Requests") [⚠️](https://github.com/Brigad/redux-rest-easy/commits?author=Zephir77167 "Tests") | [
Thibault Malbranche](https://github.com/Titozzz)
[🐛](https://github.com/Brigad/redux-rest-easy/issues?q=author%3ATitozzz "Bug reports") [💻](https://github.com/Brigad/redux-rest-easy/commits?author=Titozzz "Code") [🤔](#ideas-Titozzz "Ideas, Planning, & Feedback") [👀](#review-Titozzz "Reviewed Pull Requests") | [
Grisha Ghukasyan](https://github.com/eole1712)
[🤔](#ideas-eole1712 "Ideas, Planning, & Feedback") | [
Aymeric Beaumet](https://aymericbeaumet.com)
[🤔](#ideas-aymericbeaumet "Ideas, Planning, & Feedback") | [
Jess](https://github.com/Pinesy)
[🐛](https://github.com/Brigad/redux-rest-easy/issues?q=author%3APinesy "Bug reports") [📖](https://github.com/Brigad/redux-rest-easy/commits?author=Pinesy "Documentation") |
| :---: | :---: | :---: | :---: | :---: |
+
This project follows the [all-contributors][all-contributors] specification.
diff --git a/__tests__/internals/action-creator/preflight/isCacheExpired.test.js b/__tests__/internals/action-creator/preflight/isCacheExpired.test.js
index f0bcda5..e8a27f7 100644
--- a/__tests__/internals/action-creator/preflight/isCacheExpired.test.js
+++ b/__tests__/internals/action-creator/preflight/isCacheExpired.test.js
@@ -5,14 +5,14 @@ import isCacheExpired from '../../../../src/internals/action-creator/preflight/i
const URL = 'https://api.co/fruits';
const OTHER_URL = 'https://api.co/fruits?page1';
-
const RESOURCE_NAME = 'fruits';
-const END_DATE = moment
- .utc()
- .year(2017)
- .month(0)
- .date(1)
- .startOf('day');
+
+const MOMENT_NOW = moment(Date.UTC(2017, 0, 1));
+const EXPIRE_AT_NOW = new Date(Date.UTC(2017, 0, 1)).toISOString();
+const EXPIRE_AT_ONE_SEC = new Date(
+ Date.UTC(2017, 0, 1) + 1 * 1000,
+).toISOString();
+const EXPIRE_AT_NEVER = 'never';
const EMPTY_STATE = {};
@@ -25,8 +25,8 @@ const STATE_FILLED_WITH_OTHER_REQUEST = {
[OTHER_URL]: {
resourceName: RESOURCE_NAME,
resourceId: null,
- startedAt: END_DATE,
- endedAt: END_DATE,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
hasSucceeded: true,
hasFailed: false,
didInvalidate: false,
@@ -40,8 +40,8 @@ const SUCCEEDED_STATE = {
[URL]: {
resourceName: RESOURCE_NAME,
resourceId: null,
- startedAt: END_DATE,
- endedAt: END_DATE,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
hasSucceeded: true,
hasFailed: false,
didInvalidate: false,
@@ -55,8 +55,8 @@ const FAILED_STATE = {
[URL]: {
resourceName: RESOURCE_NAME,
resourceId: null,
- startedAt: END_DATE,
- endedAt: END_DATE,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
hasSucceeded: false,
hasFailed: true,
didInvalidate: false,
@@ -70,8 +70,8 @@ const INVALIDATED_STATE = {
[URL]: {
resourceName: RESOURCE_NAME,
resourceId: null,
- startedAt: END_DATE,
- endedAt: END_DATE,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
hasSucceeded: true,
hasFailed: false,
didInvalidate: true,
@@ -80,6 +80,15 @@ const INVALIDATED_STATE = {
},
};
+const injectExpireAtInState = (state, expireAt) => ({
+ requests: {
+ [URL]: {
+ ...state.requests[URL],
+ expireAt,
+ },
+ },
+});
+
describe('isCacheExpired', () => {
afterEach(() => {
mockdate.reset();
@@ -92,118 +101,314 @@ describe('isCacheExpired', () => {
});
test('non cacheable requests', () => {
- expect(isCacheExpired(SUCCEEDED_STATE, 'POST', URL, 0)).toBe(true);
- expect(isCacheExpired(SUCCEEDED_STATE, 'PATCH', URL, 0)).toBe(true);
- expect(isCacheExpired(SUCCEEDED_STATE, 'PUT', URL, 0)).toBe(true);
- expect(isCacheExpired(SUCCEEDED_STATE, 'DELETE', URL, 0)).toBe(true);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NOW),
+ 'POST',
+ URL,
+ ),
+ ).toBe(true);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NOW),
+ 'PATCH',
+ URL,
+ ),
+ ).toBe(true);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NOW),
+ 'PUT',
+ URL,
+ ),
+ ).toBe(true);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NOW),
+ 'DELETE',
+ URL,
+ ),
+ ).toBe(true);
});
test('state empty of concerned url', () => {
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
-
- expect(isCacheExpired(EMPTY_STATE, 'GET', URL, 0)).toBe(true);
- expect(isCacheExpired(HALF_FILLED_STATE, 'GET', URL, 0)).toBe(true);
- expect(isCacheExpired(STATE_FILLED_WITH_OTHER_REQUEST, 'GET', URL, 0)).toBe(
- true,
- );
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
+
+ expect(isCacheExpired(EMPTY_STATE, 'GET', URL)).toBe(true);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(HALF_FILLED_STATE, EXPIRE_AT_NOW),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(STATE_FILLED_WITH_OTHER_REQUEST, EXPIRE_AT_NOW),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
});
test('succeeded state, cacheLifetime = 0', () => {
- mockdate.set(END_DATE);
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, 0)).toBe(false);
-
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, 0)).toBe(true);
+ mockdate.set(MOMENT_NOW);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NOW),
+ 'GET',
+ URL,
+ ),
+ ).toBe(false);
+
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NOW),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
});
test('failed state, cacheLifetime = 0', () => {
- mockdate.set(END_DATE);
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, 0)).toBe(true);
-
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, 0)).toBe(true);
+ mockdate.set(MOMENT_NOW);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NOW),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
+
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NOW),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
});
test('invalidated state, cacheLifetime = 0', () => {
- mockdate.set(END_DATE);
- expect(isCacheExpired(INVALIDATED_STATE, 'GET', URL, 0)).toBe(true);
+ mockdate.set(MOMENT_NOW);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(INVALIDATED_STATE, EXPIRE_AT_NOW),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
});
test('succeeded state, cacheLifetime = 1', () => {
- mockdate.set(END_DATE);
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, 1)).toBe(false);
-
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, 1)).toBe(false);
-
- mockdate.set(moment(END_DATE).add(999, 'milliseconds'));
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, 1)).toBe(false);
-
- mockdate.set(moment(END_DATE).add(1000, 'milliseconds'));
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, 1)).toBe(false);
-
- mockdate.set(moment(END_DATE).add(1001, 'milliseconds'));
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, 1)).toBe(true);
+ mockdate.set(MOMENT_NOW);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(false);
+
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(false);
+
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(false);
+
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(false);
+
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
});
test('failed state, cacheLifetime = 1', () => {
- mockdate.set(END_DATE);
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, 1)).toBe(true);
-
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, 1)).toBe(true);
-
- mockdate.set(moment(END_DATE).add(999, 'milliseconds'));
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, 1)).toBe(true);
-
- mockdate.set(moment(END_DATE).add(1000, 'milliseconds'));
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, 1)).toBe(true);
-
- mockdate.set(moment(END_DATE).add(1001, 'milliseconds'));
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, 1)).toBe(true);
+ mockdate.set(MOMENT_NOW);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
+
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
+
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
+
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
+
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
});
test('invalidated state, cacheLifetime = 1', () => {
- mockdate.set(END_DATE);
- expect(isCacheExpired(INVALIDATED_STATE, 'GET', URL, 1)).toBe(true);
+ mockdate.set(MOMENT_NOW);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(INVALIDATED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
});
test('succeeded state, cacheLifetime = Infinity', () => {
- mockdate.set(END_DATE);
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, Infinity)).toBe(false);
-
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, Infinity)).toBe(false);
-
- mockdate.set(moment(END_DATE).add(999, 'milliseconds'));
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, Infinity)).toBe(false);
-
- mockdate.set(moment(END_DATE).add(1000, 'milliseconds'));
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, Infinity)).toBe(false);
-
- mockdate.set(moment(END_DATE).add(1001, 'milliseconds'));
- expect(isCacheExpired(SUCCEEDED_STATE, 'GET', URL, Infinity)).toBe(false);
+ mockdate.set(MOMENT_NOW);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(false);
+
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(false);
+
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(false);
+
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(false);
+
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(SUCCEEDED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(false);
});
test('failed state, cacheLifetime = Infinity', () => {
- mockdate.set(END_DATE);
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, Infinity)).toBe(true);
-
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, Infinity)).toBe(true);
-
- mockdate.set(moment(END_DATE).add(999, 'milliseconds'));
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, Infinity)).toBe(true);
-
- mockdate.set(moment(END_DATE).add(1000, 'milliseconds'));
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, Infinity)).toBe(true);
-
- mockdate.set(moment(END_DATE).add(1001, 'milliseconds'));
- expect(isCacheExpired(FAILED_STATE, 'GET', URL, Infinity)).toBe(true);
+ mockdate.set(MOMENT_NOW);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
+
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
+
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
+
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
+
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
});
test('invalidated state, cacheLifetime = Infinity', () => {
- mockdate.set(END_DATE);
- expect(isCacheExpired(INVALIDATED_STATE, 'GET', URL, Infinity)).toBe(true);
+ mockdate.set(MOMENT_NOW);
+ expect(
+ isCacheExpired(
+ injectExpireAtInState(INVALIDATED_STATE, EXPIRE_AT_NEVER),
+ 'GET',
+ URL,
+ ),
+ ).toBe(true);
});
});
diff --git a/__tests__/internals/action-creator/preflight/isSmartCacheAvailable.test.js b/__tests__/internals/action-creator/preflight/isSmartCacheAvailable.test.js
index d0ea26a..466ec9b 100644
--- a/__tests__/internals/action-creator/preflight/isSmartCacheAvailable.test.js
+++ b/__tests__/internals/action-creator/preflight/isSmartCacheAvailable.test.js
@@ -5,10 +5,15 @@ import isSmartCacheAvailable from '../../../../src/internals/action-creator/pref
const URL = 'https://api.co/fruits';
const OTHER_URL = 'https://api.co/fruits?page1';
-
const RESOURCE_NAME = 'fruits';
const RESOURCE_ID = 2;
-const END_DATE = moment(Date.UTC(2017, 0, 1));
+
+const MOMENT_NOW = moment(Date.UTC(2017, 0, 1));
+const EXPIRE_AT_NOW = new Date(Date.UTC(2017, 0, 1)).toISOString();
+const EXPIRE_AT_ONE_SEC = new Date(
+ Date.UTC(2017, 0, 1) + 1 * 1000,
+).toISOString();
+const EXPIRE_AT_NEVER = 'never';
const EMPTY_STATE = {};
@@ -21,8 +26,8 @@ const STATE_FILLED_WITH_OTHER_ID = {
[OTHER_URL]: {
resourceName: RESOURCE_NAME,
resourceId: RESOURCE_ID + 1,
- startedAt: END_DATE,
- endedAt: END_DATE,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
hasSucceeded: true,
hasFailed: false,
didInvalidate: false,
@@ -39,8 +44,8 @@ const SUCCEEDED_STATE_1 = {
[URL]: {
resourceName: RESOURCE_NAME,
resourceId: RESOURCE_ID,
- startedAt: END_DATE,
- endedAt: END_DATE,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
hasSucceeded: true,
hasFailed: false,
didInvalidate: false,
@@ -57,8 +62,8 @@ const SUCCEEDED_STATE_2 = {
[URL]: {
resourceName: RESOURCE_NAME,
resourceId: null,
- startedAt: END_DATE,
- endedAt: END_DATE,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
hasSucceeded: true,
hasFailed: false,
didInvalidate: false,
@@ -75,8 +80,8 @@ const FAILED_STATE = {
[URL]: {
resourceName: RESOURCE_NAME,
resourceId: RESOURCE_ID,
- startedAt: END_DATE,
- endedAt: END_DATE,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
hasSucceeded: false,
hasFailed: true,
didInvalidate: false,
@@ -90,8 +95,8 @@ const INVALIDATED_STATE = {
[URL]: {
resourceName: RESOURCE_NAME,
resourceId: RESOURCE_ID,
- startedAt: END_DATE,
- endedAt: END_DATE,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
hasSucceeded: true,
hasFailed: false,
didInvalidate: true,
@@ -103,7 +108,16 @@ const INVALIDATED_STATE = {
},
};
-describe('isCacheExpired', () => {
+const injectExpireAtInState = (state, expireAt) => ({
+ requests: {
+ [URL]: {
+ ...state.requests[URL],
+ expireAt,
+ },
+ },
+});
+
+describe('isSmartCacheAvailable', () => {
afterEach(() => {
mockdate.reset();
});
@@ -117,475 +131,472 @@ describe('isCacheExpired', () => {
test('non cacheable requests', () => {
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NOW),
'POST',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(false);
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NOW),
'PATCH',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(false);
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NOW),
'PUT',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(false);
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NOW),
'DELETE',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(false);
});
test('state empty of resource/id', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(EMPTY_STATE, 'GET', RESOURCE_NAME, RESOURCE_ID, 0),
).toBe(false);
expect(
isSmartCacheAvailable(
- HALF_FILLED_STATE,
+ injectExpireAtInState(HALF_FILLED_STATE, EXPIRE_AT_NOW),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(false);
expect(
isSmartCacheAvailable(
- STATE_FILLED_WITH_OTHER_ID,
+ injectExpireAtInState(STATE_FILLED_WITH_OTHER_ID, EXPIRE_AT_NOW),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(false);
});
test('succeeded state 1, cacheLifetime = 0', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NOW),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NOW),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(false);
});
test('succeeded state 2, cacheLifetime = 0', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_NOW),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_NOW),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(false);
});
test('failed state, cacheLifetime = 0', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
- isSmartCacheAvailable(FAILED_STATE, 'GET', RESOURCE_NAME, RESOURCE_ID, 0),
+ isSmartCacheAvailable(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NOW),
+ 'GET',
+ RESOURCE_NAME,
+ RESOURCE_ID,
+ ),
).toBe(false);
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
expect(
- isSmartCacheAvailable(FAILED_STATE, 'GET', RESOURCE_NAME, RESOURCE_ID, 0),
+ isSmartCacheAvailable(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NOW),
+ 'GET',
+ RESOURCE_NAME,
+ RESOURCE_ID,
+ ),
).toBe(false);
});
test('invalidated state, cacheLifetime = 0', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(
- INVALIDATED_STATE,
+ injectExpireAtInState(INVALIDATED_STATE, EXPIRE_AT_NOW),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 0,
),
).toBe(false);
});
test('succeeded state 1, cacheLifetime = 1', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(999, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1000, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1001, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(false);
});
test('succeeded state 2, cacheLifetime = 1', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(999, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1000, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1001, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(false);
});
test('failed state, cacheLifetime = 1', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
- isSmartCacheAvailable(FAILED_STATE, 'GET', RESOURCE_NAME, RESOURCE_ID, 1),
+ isSmartCacheAvailable(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ RESOURCE_NAME,
+ RESOURCE_ID,
+ ),
).toBe(false);
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
expect(
- isSmartCacheAvailable(FAILED_STATE, 'GET', RESOURCE_NAME, RESOURCE_ID, 1),
+ isSmartCacheAvailable(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ RESOURCE_NAME,
+ RESOURCE_ID,
+ ),
).toBe(false);
- mockdate.set(moment(END_DATE).add(999, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
expect(
- isSmartCacheAvailable(FAILED_STATE, 'GET', RESOURCE_NAME, RESOURCE_ID, 1),
+ isSmartCacheAvailable(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ RESOURCE_NAME,
+ RESOURCE_ID,
+ ),
).toBe(false);
- mockdate.set(moment(END_DATE).add(1000, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
expect(
- isSmartCacheAvailable(FAILED_STATE, 'GET', RESOURCE_NAME, RESOURCE_ID, 1),
+ isSmartCacheAvailable(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ RESOURCE_NAME,
+ RESOURCE_ID,
+ ),
).toBe(false);
- mockdate.set(moment(END_DATE).add(1001, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
expect(
- isSmartCacheAvailable(FAILED_STATE, 'GET', RESOURCE_NAME, RESOURCE_ID, 1),
+ isSmartCacheAvailable(
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_ONE_SEC),
+ 'GET',
+ RESOURCE_NAME,
+ RESOURCE_ID,
+ ),
).toBe(false);
});
test('invalidated state, cacheLifetime = 1', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(
- INVALIDATED_STATE,
+ injectExpireAtInState(INVALIDATED_STATE, EXPIRE_AT_ONE_SEC),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- 1,
),
).toBe(false);
});
test('succeeded state 1, cacheLifetime = Infinity', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(999, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1000, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1001, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_1,
+ injectExpireAtInState(SUCCEEDED_STATE_1, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(true);
});
test('succeeded state 2, cacheLifetime = Infinity', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(999, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1000, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(true);
- mockdate.set(moment(END_DATE).add(1001, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
expect(
isSmartCacheAvailable(
- SUCCEEDED_STATE_2,
+ injectExpireAtInState(SUCCEEDED_STATE_2, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(true);
});
test('failed state, cacheLifetime = Infinity', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(
- FAILED_STATE,
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(false);
- mockdate.set(moment(END_DATE).add(1, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
expect(
isSmartCacheAvailable(
- FAILED_STATE,
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(false);
- mockdate.set(moment(END_DATE).add(999, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
expect(
isSmartCacheAvailable(
- FAILED_STATE,
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(false);
- mockdate.set(moment(END_DATE).add(1000, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
expect(
isSmartCacheAvailable(
- FAILED_STATE,
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(false);
- mockdate.set(moment(END_DATE).add(1001, 'milliseconds'));
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
expect(
isSmartCacheAvailable(
- FAILED_STATE,
+ injectExpireAtInState(FAILED_STATE, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(false);
});
test('invalidated state, cacheLifetime = Infinity', () => {
- mockdate.set(END_DATE);
+ mockdate.set(MOMENT_NOW);
expect(
isSmartCacheAvailable(
- INVALIDATED_STATE,
+ injectExpireAtInState(INVALIDATED_STATE, EXPIRE_AT_NEVER),
'GET',
RESOURCE_NAME,
RESOURCE_ID,
- Infinity,
),
).toBe(false);
});
diff --git a/__tests__/internals/actions/generateActionCreatorActions/__snapshots__/generateActionCreatorAction.test.js.snap b/__tests__/internals/actions/generateActionCreatorActions/__snapshots__/generateActionCreatorAction.test.js.snap
index 815c7c7..2cef50d 100644
--- a/__tests__/internals/actions/generateActionCreatorActions/__snapshots__/generateActionCreatorAction.test.js.snap
+++ b/__tests__/internals/actions/generateActionCreatorActions/__snapshots__/generateActionCreatorAction.test.js.snap
@@ -2,6 +2,7 @@
exports[`generateActionCreatorAction empty payload 1`] = `
Object {
+ "cacheLifetime": 0,
"payload": undefined,
"principalResourceIds": undefined,
"resourceId": "2",
@@ -12,6 +13,7 @@ Object {
exports[`generateActionCreatorAction filled payload without principalResourceIds 1`] = `
Object {
+ "cacheLifetime": 0,
"payload": Object {
"fruits": Object {
"1": "cherry",
@@ -26,6 +28,7 @@ Object {
exports[`generateActionCreatorAction filled payload, array principalResourceIds 1`] = `
Object {
+ "cacheLifetime": 0,
"payload": Object {
"fruits": Object {
"1": "cherry",
@@ -42,6 +45,7 @@ Object {
exports[`generateActionCreatorAction filled payload, string principalResourceIds 1`] = `
Object {
+ "cacheLifetime": 0,
"payload": Object {
"fruits": Object {
"1": "cherry",
@@ -56,8 +60,20 @@ Object {
}
`;
+exports[`generateActionCreatorAction no action type 1`] = `
+Object {
+ "cacheLifetime": 0,
+ "payload": undefined,
+ "principalResourceIds": undefined,
+ "resourceId": undefined,
+ "type": undefined,
+ "url": undefined,
+}
+`;
+
exports[`generateActionCreatorAction no args 1`] = `
Object {
+ "cacheLifetime": undefined,
"payload": undefined,
"principalResourceIds": undefined,
"resourceId": undefined,
@@ -68,6 +84,7 @@ Object {
exports[`generateActionCreatorAction no id, payload 1`] = `
Object {
+ "cacheLifetime": 0,
"payload": undefined,
"principalResourceIds": undefined,
"resourceId": undefined,
@@ -78,6 +95,7 @@ Object {
exports[`generateActionCreatorAction no payload 1`] = `
Object {
+ "cacheLifetime": 0,
"payload": undefined,
"principalResourceIds": undefined,
"resourceId": "2",
@@ -88,6 +106,7 @@ Object {
exports[`generateActionCreatorAction no url, id, payload 1`] = `
Object {
+ "cacheLifetime": 0,
"payload": undefined,
"principalResourceIds": undefined,
"resourceId": undefined,
diff --git a/__tests__/internals/actions/generateActionCreatorActions/generateActionCreatorAction.test.js b/__tests__/internals/actions/generateActionCreatorActions/generateActionCreatorAction.test.js
index 6213b54..8af149e 100644
--- a/__tests__/internals/actions/generateActionCreatorActions/generateActionCreatorAction.test.js
+++ b/__tests__/internals/actions/generateActionCreatorActions/generateActionCreatorAction.test.js
@@ -1,5 +1,6 @@
import generateActionCreatorAction from '../../../../src/internals/actions/generateActionCreatorActions/generateActionCreatorAction';
+const CACHE_LIFETIME = 0;
const ACTION_TYPE = '@@rest-easy/fruits/eat/REQUEST';
const NORMALIZED_URL = 'eat:https://api.co/fruits';
const ID = '2';
@@ -10,25 +11,38 @@ describe('generateActionCreatorAction', () => {
expect(generateActionCreatorAction()()).toMatchSnapshot();
});
+ test('no action type', () => {
+ expect(generateActionCreatorAction(CACHE_LIFETIME)()).toMatchSnapshot();
+ });
+
test('no url, id, payload', () => {
- expect(generateActionCreatorAction(ACTION_TYPE)()).toMatchSnapshot();
+ expect(
+ generateActionCreatorAction(CACHE_LIFETIME, ACTION_TYPE)(),
+ ).toMatchSnapshot();
});
test('no id, payload', () => {
expect(
- generateActionCreatorAction(ACTION_TYPE)(NORMALIZED_URL),
+ generateActionCreatorAction(CACHE_LIFETIME, ACTION_TYPE)(NORMALIZED_URL),
).toMatchSnapshot();
});
test('no payload', () => {
expect(
- generateActionCreatorAction(ACTION_TYPE)(NORMALIZED_URL, ID),
+ generateActionCreatorAction(CACHE_LIFETIME, ACTION_TYPE)(
+ NORMALIZED_URL,
+ ID,
+ ),
).toMatchSnapshot();
});
test('empty payload', () => {
expect(
- generateActionCreatorAction(ACTION_TYPE)(NORMALIZED_URL, ID, {}),
+ generateActionCreatorAction(CACHE_LIFETIME, ACTION_TYPE)(
+ NORMALIZED_URL,
+ ID,
+ {},
+ ),
).toMatchSnapshot();
});
@@ -40,7 +54,11 @@ describe('generateActionCreatorAction', () => {
};
expect(
- generateActionCreatorAction(ACTION_TYPE)(NORMALIZED_URL, ID, payload),
+ generateActionCreatorAction(CACHE_LIFETIME, ACTION_TYPE)(
+ NORMALIZED_URL,
+ ID,
+ payload,
+ ),
).toMatchSnapshot();
});
@@ -52,7 +70,12 @@ describe('generateActionCreatorAction', () => {
};
expect(
- generateActionCreatorAction(ACTION_TYPE)(NORMALIZED_URL, ID, payload, ID),
+ generateActionCreatorAction(CACHE_LIFETIME, ACTION_TYPE)(
+ NORMALIZED_URL,
+ ID,
+ payload,
+ ID,
+ ),
).toMatchSnapshot();
});
@@ -64,7 +87,7 @@ describe('generateActionCreatorAction', () => {
};
expect(
- generateActionCreatorAction(ACTION_TYPE)(
+ generateActionCreatorAction(CACHE_LIFETIME, ACTION_TYPE)(
NORMALIZED_URL,
ID,
payload,
diff --git a/__tests__/internals/persistence/getPrunedForPersistenceState.test.js b/__tests__/internals/persistence/getPrunedForPersistenceState.test.js
new file mode 100644
index 0000000..c2d235c
--- /dev/null
+++ b/__tests__/internals/persistence/getPrunedForPersistenceState.test.js
@@ -0,0 +1,338 @@
+import mockdate from 'mockdate';
+import moment from 'moment';
+
+import getPrunedForPersistenceState from '../../../src/internals/persistence/getPrunedForPersistenceState';
+
+const URL_1 = 'https://api.co/fruits?page1';
+const URL_2 = 'https://api.co/fruits?page2';
+const URL_3 = 'https://api.co/fruits?page3';
+const URL_4 = 'https://api.co/fruits?page4';
+const RESOURCE_NAME = 'fruits';
+const RESOURCE_NAME_2 = 'vegetables';
+const RESOURCE_NAME_3 = 'sauces';
+
+const MOMENT_NOW = moment(Date.UTC(2017, 0, 1));
+const EXPIRE_AT_ONE_SEC = new Date(
+ Date.UTC(2017, 0, 1) + 1 * 1000,
+).toISOString();
+const EXPIRE_AT_NEVER = 'never';
+
+const STATE_REQUESTS = {
+ requests: {
+ [URL_1]: {
+ resourceName: RESOURCE_NAME,
+ resourceId: null,
+ startedAt: MOMENT_NOW,
+ endedAt: null,
+ expireAt: EXPIRE_AT_NEVER,
+ hasSucceeded: true,
+ hasFailed: false,
+ didInvalidate: false,
+ fromCache: false,
+ },
+ [URL_2]: {
+ resourceName: RESOURCE_NAME,
+ resourceId: null,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
+ expireAt: EXPIRE_AT_NEVER,
+ hasSucceeded: true,
+ hasFailed: false,
+ didInvalidate: true,
+ fromCache: false,
+ },
+ [URL_3]: {
+ resourceName: RESOURCE_NAME,
+ resourceId: null,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
+ expireAt: EXPIRE_AT_ONE_SEC,
+ hasSucceeded: true,
+ hasFailed: false,
+ didInvalidate: false,
+ fromCache: false,
+ },
+ [URL_4]: {
+ resourceName: RESOURCE_NAME,
+ resourceId: null,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
+ expireAt: EXPIRE_AT_NEVER,
+ hasSucceeded: true,
+ hasFailed: false,
+ didInvalidate: false,
+ fromCache: false,
+ },
+ },
+};
+
+const STATE_RESOURCES = {
+ requests: {
+ [URL_1]: {
+ resourceName: RESOURCE_NAME,
+ resourceId: null,
+ startedAt: MOMENT_NOW,
+ endedAt: null,
+ expireAt: EXPIRE_AT_NEVER,
+ hasSucceeded: true,
+ hasFailed: false,
+ didInvalidate: false,
+ fromCache: false,
+ payloadIds: {
+ [RESOURCE_NAME]: [1, 2, 3],
+ },
+ },
+ [URL_4]: {
+ resourceName: RESOURCE_NAME,
+ resourceId: null,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
+ expireAt: EXPIRE_AT_NEVER,
+ hasSucceeded: true,
+ hasFailed: false,
+ didInvalidate: false,
+ fromCache: false,
+ payloadIds: {
+ [RESOURCE_NAME]: [3, 4, 5],
+ },
+ },
+ },
+ resources: {
+ [RESOURCE_NAME]: {
+ 1: 'banana',
+ 2: 'apple',
+ 3: 'cherry',
+ 4: 'pineapple',
+ 5: 'raspberry',
+ },
+ [RESOURCE_NAME_2]: {
+ 1: 'carrot',
+ 2: 'potato',
+ },
+ },
+};
+
+const STATE_RESOURCES_OTHER_ORDER = {
+ requests: {
+ [URL_4]: {
+ resourceName: RESOURCE_NAME,
+ resourceId: null,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
+ expireAt: EXPIRE_AT_NEVER,
+ hasSucceeded: true,
+ hasFailed: false,
+ didInvalidate: false,
+ fromCache: false,
+ payloadIds: {
+ [RESOURCE_NAME]: [3, 4, 5],
+ },
+ },
+ [URL_1]: {
+ resourceName: RESOURCE_NAME,
+ resourceId: null,
+ startedAt: MOMENT_NOW,
+ endedAt: null,
+ expireAt: EXPIRE_AT_NEVER,
+ hasSucceeded: true,
+ hasFailed: false,
+ didInvalidate: false,
+ fromCache: false,
+ payloadIds: {
+ [RESOURCE_NAME]: [1, 2, 3],
+ },
+ },
+ },
+ resources: {
+ [RESOURCE_NAME_2]: {
+ 1: 'carrot',
+ 2: 'potato',
+ },
+ [RESOURCE_NAME]: {
+ 1: 'banana',
+ 2: 'apple',
+ 3: 'cherry',
+ 4: 'pineapple',
+ 5: 'raspberry',
+ },
+ },
+};
+
+const STATE_RESOLVERS_HASHES = {
+ requests: {
+ [URL_1]: {
+ resourceName: RESOURCE_NAME,
+ resourceId: null,
+ startedAt: MOMENT_NOW,
+ endedAt: null,
+ expireAt: EXPIRE_AT_NEVER,
+ hasSucceeded: true,
+ hasFailed: false,
+ didInvalidate: false,
+ fromCache: false,
+ payloadIds: {
+ [RESOURCE_NAME]: [1, 2, 3],
+ },
+ },
+ [URL_4]: {
+ resourceName: RESOURCE_NAME,
+ resourceId: null,
+ startedAt: MOMENT_NOW,
+ endedAt: MOMENT_NOW,
+ expireAt: EXPIRE_AT_NEVER,
+ hasSucceeded: true,
+ hasFailed: false,
+ didInvalidate: false,
+ fromCache: false,
+ payloadIds: {
+ [RESOURCE_NAME]: [3, 4, 5],
+ [RESOURCE_NAME_3]: [1, 2],
+ },
+ },
+ },
+ resources: {
+ [RESOURCE_NAME]: {
+ 1: 'banana',
+ 2: 'apple',
+ 3: 'cherry',
+ 4: 'pineapple',
+ 5: 'raspberry',
+ },
+ [RESOURCE_NAME_2]: {
+ 1: 'carrot',
+ 2: 'potato',
+ },
+ [RESOURCE_NAME_3]: {
+ 1: 'chocolate',
+ 2: 'fudge',
+ },
+ },
+ resolversHashes: {
+ requests: {
+ [URL_1]: {
+ [RESOURCE_NAME]: 'URL_1_HASH',
+ },
+ [URL_4]: {
+ [RESOURCE_NAME]: 'URL_4_HASH',
+ },
+ },
+ resources: {
+ [RESOURCE_NAME]: 'RESOURCE_HASH',
+ [RESOURCE_NAME_2]: 'RESOURCE_2_HASH',
+ [RESOURCE_NAME_3]: 'RESOURCE_3_HASH',
+ },
+ },
+};
+
+describe('getPrunedForPersistenceState', () => {
+ afterEach(() => {
+ mockdate.reset();
+ });
+
+ test('invalid state', () => {
+ expect(Object.keys(getPrunedForPersistenceState()).length).toBe(0);
+ expect(Object.keys(getPrunedForPersistenceState(null)).length).toBe(0);
+ });
+
+ test('empty state', () => {
+ expect(Object.keys(getPrunedForPersistenceState({})).length).toBe(0);
+ });
+
+ test('requests: no endedAt', () => {
+ expect(
+ getPrunedForPersistenceState(STATE_REQUESTS).requests[URL_1],
+ ).toBeUndefined();
+ });
+
+ test('requests: didInvalidate', () => {
+ expect(
+ getPrunedForPersistenceState(STATE_REQUESTS).requests[URL_2],
+ ).toBeUndefined();
+ });
+
+ test('requests: cache expired', () => {
+ mockdate.set(MOMENT_NOW);
+ expect(
+ getPrunedForPersistenceState(STATE_REQUESTS).requests[URL_3],
+ ).not.toBeUndefined();
+
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
+ expect(
+ getPrunedForPersistenceState(STATE_REQUESTS).requests[URL_3],
+ ).not.toBeUndefined();
+
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
+ expect(
+ getPrunedForPersistenceState(STATE_REQUESTS).requests[URL_3],
+ ).not.toBeUndefined();
+
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
+ expect(
+ getPrunedForPersistenceState(STATE_REQUESTS).requests[URL_3],
+ ).toBeUndefined();
+ });
+
+ test('requests: expiredAt never', () => {
+ mockdate.set(MOMENT_NOW);
+ expect(
+ getPrunedForPersistenceState(STATE_REQUESTS).requests[URL_4]
+ .didInvalidate,
+ ).toBe(true);
+ });
+
+ test('resources first order', () => {
+ const prunedState = getPrunedForPersistenceState(STATE_RESOURCES);
+ const prunedStateResourcesIds = Object.keys(
+ prunedState.resources[RESOURCE_NAME],
+ );
+
+ expect(prunedStateResourcesIds.length).toBe(3);
+
+ expect(prunedStateResourcesIds.includes('1')).toBe(false);
+ expect(prunedStateResourcesIds.includes('2')).toBe(false);
+
+ expect(prunedStateResourcesIds.includes('3')).toBe(true);
+ expect(prunedStateResourcesIds.includes('4')).toBe(true);
+ expect(prunedStateResourcesIds.includes('5')).toBe(true);
+
+ expect(prunedState.resources[RESOURCE_NAME_2]).toBeUndefined();
+ });
+
+ test('resources second order', () => {
+ const prunedState = getPrunedForPersistenceState(
+ STATE_RESOURCES_OTHER_ORDER,
+ );
+ const prunedStateResourcesIds = Object.keys(
+ prunedState.resources[RESOURCE_NAME],
+ );
+
+ expect(prunedStateResourcesIds.length).toBe(3);
+
+ expect(prunedStateResourcesIds.includes('1')).toBe(false);
+ expect(prunedStateResourcesIds.includes('2')).toBe(false);
+
+ expect(prunedStateResourcesIds.includes('3')).toBe(true);
+ expect(prunedStateResourcesIds.includes('4')).toBe(true);
+ expect(prunedStateResourcesIds.includes('5')).toBe(true);
+
+ expect(prunedState.resources[RESOURCE_NAME_2]).toBeUndefined();
+ });
+
+ test('resolversHashes', () => {
+ const prunedStateResolversHashes = getPrunedForPersistenceState(
+ STATE_RESOLVERS_HASHES,
+ ).resolversHashes;
+
+ expect(prunedStateResolversHashes.requests[URL_1]).toBeUndefined();
+ expect(
+ prunedStateResolversHashes.requests[URL_4][RESOURCE_NAME],
+ ).not.toBeUndefined();
+ expect(prunedStateResolversHashes.resources[RESOURCE_NAME]).toBeUndefined();
+ expect(
+ prunedStateResolversHashes.resources[RESOURCE_NAME_2],
+ ).toBeUndefined();
+ expect(
+ prunedStateResolversHashes.resources[RESOURCE_NAME_3],
+ ).not.toBeUndefined();
+ });
+});
diff --git a/__tests__/internals/reducer/generateReducer/__snapshots__/getReducerCases.test.js.snap b/__tests__/internals/reducer/generateReducer/__snapshots__/getReducerCases.test.js.snap
index 051c42d..bb2dedf 100644
--- a/__tests__/internals/reducer/generateReducer/__snapshots__/getReducerCases.test.js.snap
+++ b/__tests__/internals/reducer/generateReducer/__snapshots__/getReducerCases.test.js.snap
@@ -204,6 +204,7 @@ Object {
"eat:https://api.co/fruits": Object {
"didInvalidate": false,
"endedAt": "2017-01-01T00:00:00.000Z",
+ "expireAt": "2017-01-01T00:00:00.000Z",
"fromCache": false,
"hasFailed": false,
"hasSucceeded": true,
@@ -250,6 +251,7 @@ Object {
"eat:https://api.co/fruits": Object {
"didInvalidate": false,
"endedAt": "2017-01-01T00:00:00.000Z",
+ "expireAt": "2017-01-01T00:00:00.000Z",
"fromCache": true,
"hasFailed": false,
"hasSucceeded": true,
@@ -288,6 +290,7 @@ Object {
"eat:https://api.co/fruits": Object {
"didInvalidate": false,
"endedAt": null,
+ "expireAt": null,
"fromCache": false,
"hasFailed": false,
"hasSucceeded": false,
diff --git a/__tests__/internals/reducer/generateReducer/getReducerCases.test.js b/__tests__/internals/reducer/generateReducer/getReducerCases.test.js
index 2b1c08e..7bede21 100644
--- a/__tests__/internals/reducer/generateReducer/getReducerCases.test.js
+++ b/__tests__/internals/reducer/generateReducer/getReducerCases.test.js
@@ -3,6 +3,7 @@ import moment from 'moment';
import getReducerCases from '../../../../src/internals/reducer/generateReducer/getReducerCases';
+const CACHE_LIFETIME = 0;
const RESOURCE_NAME = 'fruits';
const RESOURCE_ID = 2;
const ACTION_NAME = 'eat';
@@ -105,6 +106,7 @@ describe('getReducerCases', () => {
},
},
principalResourceIds: ['2', '1', '3'],
+ cacheLifetime: CACHE_LIFETIME,
};
expect(
@@ -135,6 +137,7 @@ describe('getReducerCases', () => {
},
},
principalResourceIds: ['1'],
+ cacheLifetime: CACHE_LIFETIME,
};
expect(
diff --git a/__tests__/internals/utils/hasCacheExpired.test.js b/__tests__/internals/utils/hasCacheExpired.test.js
index a8daa5b..23734e2 100644
--- a/__tests__/internals/utils/hasCacheExpired.test.js
+++ b/__tests__/internals/utils/hasCacheExpired.test.js
@@ -3,49 +3,53 @@ import moment from 'moment';
import hasCacheExpired from '../../../src/internals/utils/hasCacheExpired';
-const MOMENT_END_DATE = moment(Date.UTC(2017, 0, 1));
-const END_DATE = new Date(Date.UTC(2017, 0, 1)).toISOString();
+const MOMENT_NOW = moment(Date.UTC(2017, 0, 1));
+const EXPIRE_AT_NOW = new Date(Date.UTC(2017, 0, 1)).toISOString();
+const EXPIRE_AT_ONE_SEC = new Date(
+ Date.UTC(2017, 0, 1) + 1 * 1000,
+).toISOString();
+const EXPIRE_AT_NEVER = 'never';
describe('hasCacheExpired', () => {
test('cacheLifetime = 0', () => {
- mockdate.set(MOMENT_END_DATE);
- expect(hasCacheExpired(END_DATE, 0)).toBe(false);
+ mockdate.set(MOMENT_NOW);
+ expect(hasCacheExpired(EXPIRE_AT_NOW, 0)).toBe(false);
- mockdate.set(moment(MOMENT_END_DATE).add(1, 'milliseconds'));
- expect(hasCacheExpired(END_DATE, 0)).toBe(true);
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
+ expect(hasCacheExpired(EXPIRE_AT_NOW, 0)).toBe(true);
});
test('cacheLifetime = 1', () => {
- mockdate.set(MOMENT_END_DATE);
- expect(hasCacheExpired(END_DATE, 1)).toBe(false);
+ mockdate.set(MOMENT_NOW);
+ expect(hasCacheExpired(EXPIRE_AT_ONE_SEC)).toBe(false);
- mockdate.set(moment(MOMENT_END_DATE).add(1, 'milliseconds'));
- expect(hasCacheExpired(END_DATE, 1)).toBe(false);
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
+ expect(hasCacheExpired(EXPIRE_AT_ONE_SEC)).toBe(false);
- mockdate.set(moment(MOMENT_END_DATE).add(999, 'milliseconds'));
- expect(hasCacheExpired(END_DATE, 1)).toBe(false);
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
+ expect(hasCacheExpired(EXPIRE_AT_ONE_SEC)).toBe(false);
- mockdate.set(moment(MOMENT_END_DATE).add(1000, 'milliseconds'));
- expect(hasCacheExpired(END_DATE, 1)).toBe(false);
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
+ expect(hasCacheExpired(EXPIRE_AT_ONE_SEC)).toBe(false);
- mockdate.set(moment(MOMENT_END_DATE).add(1001, 'milliseconds'));
- expect(hasCacheExpired(END_DATE, 1)).toBe(true);
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
+ expect(hasCacheExpired(EXPIRE_AT_ONE_SEC)).toBe(true);
});
test('cacheLifetime = Infinity', () => {
- mockdate.set(MOMENT_END_DATE);
- expect(hasCacheExpired(END_DATE, Infinity)).toBe(false);
+ mockdate.set(MOMENT_NOW);
+ expect(hasCacheExpired(EXPIRE_AT_NEVER)).toBe(false);
- mockdate.set(moment(MOMENT_END_DATE).add(1, 'milliseconds'));
- expect(hasCacheExpired(END_DATE, Infinity)).toBe(false);
+ mockdate.set(moment(MOMENT_NOW).add(1, 'milliseconds'));
+ expect(hasCacheExpired(EXPIRE_AT_NEVER)).toBe(false);
- mockdate.set(moment(MOMENT_END_DATE).add(999, 'milliseconds'));
- expect(hasCacheExpired(END_DATE, Infinity)).toBe(false);
+ mockdate.set(moment(MOMENT_NOW).add(999, 'milliseconds'));
+ expect(hasCacheExpired(EXPIRE_AT_NEVER)).toBe(false);
- mockdate.set(moment(MOMENT_END_DATE).add(1000, 'milliseconds'));
- expect(hasCacheExpired(END_DATE, Infinity)).toBe(false);
+ mockdate.set(moment(MOMENT_NOW).add(1000, 'milliseconds'));
+ expect(hasCacheExpired(EXPIRE_AT_NEVER)).toBe(false);
- mockdate.set(moment(MOMENT_END_DATE).add(1001, 'milliseconds'));
- expect(hasCacheExpired(END_DATE, Infinity)).toBe(false);
+ mockdate.set(moment(MOMENT_NOW).add(1001, 'milliseconds'));
+ expect(hasCacheExpired(EXPIRE_AT_NEVER)).toBe(false);
});
});
diff --git a/docs/api/createResource.md b/docs/api/createResource.md
index 78b2bb6..2c5e6e5 100644
--- a/docs/api/createResource.md
+++ b/docs/api/createResource.md
@@ -153,5 +153,5 @@ export {
#### Tips
* The above example is very exhaustive, but you can export only what you really need
-* Naming is a mater of personal preference, use what works for you
+* Naming is a matter of personal preference, use what works for you
* You can alternately just export `users`, and spare yourself the trouble of mapping the names. Then just use the selectors like so: `users.selectors.resource.getResource()`. Again, use what works for you
diff --git a/docs/api/createResource/actions.md b/docs/api/createResource/actions.md
index 5e8db56..924320c 100644
--- a/docs/api/createResource/actions.md
+++ b/docs/api/createResource/actions.md
@@ -35,12 +35,12 @@ These functions can be imported in components and directly dispatched.
#### Properties
-1. (_urlParams_): (`map`) An object to replace dynamic parameters in the URL (see [actions config documentation](./actionsConfig.md#properties))
-2. (_query_): (`map`) An object to prepend a query to the URL
-3. (_body_): (`map`) An object to specify the body of the request (e.g. POST)
-4. (_onSuccess_): (`(normalizedPayload, otherArgs) : undefined`) A hook which will be invoked after the request has performed successfuly. Useful to update the UI accordingly, at the component level
-5. (_onFailure_): (`(error) : undefined`) A hook which will be invoked when the request fails. Useful to update the UI accordingly, at the component level
-6. (_...otherArgs_): (`any`) You can also pass any other args you may need in `beforeHook`, `normalizer`, `afterHook`, and `onSuccess`. They will be forwarded to these functions, as an object
+1. (_urlParams_): (`map`) An object to replace dynamic parameters in the URL (see [actions config documentation](./actionsConfig.md#properties))
+2. (_query_): (`map`) An object to prepend a query to the URL
+3. (_body_): (`map`) An object to specify the body of the request (e.g. POST)
+4. (_onSuccess_): (`(normalizedPayload, otherArgs) : undefined`) A hook which will be invoked after the request has performed successfully. Useful to update the UI accordingly, at the component level
+5. (_onFailure_): (`(error) : undefined`) A hook which will be invoked when the request fails. Useful to update the UI accordingly, at the component level
+6. (_...otherArgs_): (`any`) You can also pass any other args you may need in `beforeHook`, `normalizer`, `afterHook`, and `onSuccess`. They will be forwarded to these functions, as an object
#### Example
diff --git a/docs/api/createResource/actionsConfig.md b/docs/api/createResource/actionsConfig.md
index b8d9e2c..de0f304 100644
--- a/docs/api/createResource/actionsConfig.md
+++ b/docs/api/createResource/actionsConfig.md
@@ -6,7 +6,7 @@ Map of `` which defines the actions you will be able to perfo
1. (_method_) **mandatory**: (`string`) The method of the action. Can be one of: `GET`, `PATCH`, `PUT`, `POST`, `DELETE`
2. (_url_) **mandatory**: (`string || () : string`) The URL on which the action has to fetch. For dynamic parameters, prefix them with `::` for the resource ID (e.g. `::userId`), and `:` for other parameters (e.g. `:userType`), and they will get replaced with the `urlParams` you will provide (see [actions documentation](./actions.md#properties))
-3. (_beforeHook_): (`(urlParams, query, body, otherArgs, dispatch) : undefined || any`) A hook which can be invoked just before performing the request. Will be awaited if async. If it returns a non falsy value, the return will be used as the body for the principal request
+3. (_beforeHook_): (`(urlParams, query, body, otherArgs, dispatch) : undefined || any`) A hook which can be invoked just before performing the request. Will be awaited if async. If it returns a non-falsy value, the return will be used as the body for the principal request
4. (_normalizer_): (`(payload, resources, urlParams, query, body, otherArgs) : { entities: normalizedPayload, result: principalResourceId }`) A function which will be invoked to normalize the payload of the request. It is expected to return an object with `entities` and `result`, respectively containing the normalized payload and the sorted ids, just as [normalizr](https://github.com/paularmstrong/normalizr) does.
5. (_afterHook_): (`(normalizedPayload, urlParams, query, body, otherArgs, dispatch) : undefined`) A hook which can be invoked after performing the request and normalizing the payload. Will be awaited if async
6. (_networkHelpers_): (`map`) A map of handlers used when performing network requests. Override the default ones, and the ones specified using `initializeNetworkHelpers`. Documentation on the content of the map can be found [here](../initializeNetworkHelpers.md#arguments)
diff --git a/docs/api/createResource/selectors.md b/docs/api/createResource/selectors.md
index ec17af9..50b99f2 100644
--- a/docs/api/createResource/selectors.md
+++ b/docs/api/createResource/selectors.md
@@ -39,11 +39,11 @@ _Available to any connected component._
### `getResource(state, applyDenormalizer = true)`: `array