From f3ef45702b90118e27a3a6d9f5c966b54fc3eb75 Mon Sep 17 00:00:00 2001 From: mat Date: Tue, 6 Mar 2018 11:20:05 +0100 Subject: [PATCH] #110 add support for getContext and setContext side effects --- .../expectSaga/assertions/get-context.test.js | 35 ++++++++++++ .../expectSaga/assertions/set-context.test.js | 35 ++++++++++++ .../expectSaga/providers/get-context.test.js | 53 +++++++++++++++++++ .../expectSaga/providers/set-context.test.js | 17 ++++++ decls/index.js | 2 + src/expectSaga/index.js | 16 ++++++ src/expectSaga/matchers/index.js | 2 + src/expectSaga/parseEffect.js | 16 ++++++ src/expectSaga/provideValue.js | 4 ++ src/shared/keys.js | 2 + 10 files changed, 182 insertions(+) create mode 100644 __tests__/expectSaga/assertions/get-context.test.js create mode 100644 __tests__/expectSaga/assertions/set-context.test.js create mode 100644 __tests__/expectSaga/providers/get-context.test.js create mode 100644 __tests__/expectSaga/providers/set-context.test.js diff --git a/__tests__/expectSaga/assertions/get-context.test.js b/__tests__/expectSaga/assertions/get-context.test.js new file mode 100644 index 00000000..4bb87ed4 --- /dev/null +++ b/__tests__/expectSaga/assertions/get-context.test.js @@ -0,0 +1,35 @@ +import { getContext } from 'redux-saga/effects'; +import expectSaga from 'expectSaga'; +import { errorRegex, unreachableError } from './_helper'; + +function* saga() { + yield getContext('theAnswer'); +} + +test('getContext assertion passes', () => + expectSaga(saga) + .getContext('theAnswer') + .run()); + +test('negative getContext assertion passes with wrong property name', () => + expectSaga(saga) + .not.getContext('wrongAnswer') + .run()); + +test('getContext assertion fails with wrong property name', () => + expectSaga(saga) + .getContext('wrongAnswer') + .run() + .then(unreachableError) + .catch(e => { + expect(e.message).toMatch(errorRegex); + })); + +test('negative getContext assertion fails with correct property name', () => + expectSaga(saga) + .not.getContext('theAnswer') + .run() + .then(unreachableError) + .catch(e => { + expect(e.message).toMatch(errorRegex); + })); diff --git a/__tests__/expectSaga/assertions/set-context.test.js b/__tests__/expectSaga/assertions/set-context.test.js new file mode 100644 index 00000000..c89b19c3 --- /dev/null +++ b/__tests__/expectSaga/assertions/set-context.test.js @@ -0,0 +1,35 @@ +import { setContext } from 'redux-saga/effects'; +import expectSaga from 'expectSaga'; +import { errorRegex, unreachableError } from './_helper'; + +function* saga() { + yield setContext({ answer: 42 }); +} + +test('setContext assertion passes', () => + expectSaga(saga) + .setContext({ answer: 42 }) + .run()); + +test('negative setContext assertion passes with wrong properties', () => + expectSaga(saga) + .not.setContext({ answer: 41 }) + .run()); + +test('setContext assertion fails with wrong properties', () => + expectSaga(saga) + .setContext({ answer: 41 }) + .run() + .then(unreachableError) + .catch(e => { + expect(e.message).toMatch(errorRegex); + })); + +test('negative setContext assertion fails with correct properties', () => + expectSaga(saga) + .not.setContext({ answer: 42 }) + .run() + .then(unreachableError) + .catch(e => { + expect(e.message).toMatch(errorRegex); + })); diff --git a/__tests__/expectSaga/providers/get-context.test.js b/__tests__/expectSaga/providers/get-context.test.js new file mode 100644 index 00000000..9d9c22c1 --- /dev/null +++ b/__tests__/expectSaga/providers/get-context.test.js @@ -0,0 +1,53 @@ +// @flow +import { getContext, put } from 'redux-saga/effects'; +import expectSaga from 'expectSaga'; +import * as m from 'expectSaga/matchers'; +import { dynamic } from 'expectSaga/providers'; + +const contextVar = 'contextValue'; + +function* saga() { + const value = yield getContext(contextVar); + + yield put({ type: 'DONE', payload: value }); +} + +test('uses provided value for `getContext`', () => + expectSaga(saga) + .provide({ + getContext(property, next) { + if (property === contextVar) { + return 42; + } + + return next(); + }, + }) + .put({ type: 'DONE', payload: 42 }) + .run()); + +test('uses static provided values from redux-saga/effects', () => + expectSaga(saga) + .provide([[getContext(contextVar), 42]]) + .put({ type: 'DONE', payload: 42 }) + .run()); + +test('uses static provided values from matchers', () => + expectSaga(saga) + .provide([[m.getContext(contextVar), 42]]) + .put({ type: 'DONE', payload: 42 }) + .run()); + +test('dynamic values have access to effect', () => + expectSaga(saga) + .provide([ + [ + m.getContext(contextVar), + dynamic(property => { + expect(property).toBe(contextVar); + return 42; + }), + ], + ]) + .put({ type: 'DONE', payload: 42 }) + .run()); diff --git a/__tests__/expectSaga/providers/set-context.test.js b/__tests__/expectSaga/providers/set-context.test.js new file mode 100644 index 00000000..bca9be4f --- /dev/null +++ b/__tests__/expectSaga/providers/set-context.test.js @@ -0,0 +1,17 @@ +// @flow +import { setContext } from 'redux-saga/effects'; +import expectSaga from 'expectSaga'; + +function* saga() { + yield setContext({ answer: 42 }); +} + +test('dynamic values have access to effect', () => + expectSaga(saga) + .provide({ + setContext(properties, next) { + expect(properties.answer).toBe(42); + return next(); + }, + }) + .run()); diff --git a/decls/index.js b/decls/index.js index 0cddc747..f5328e63 100644 --- a/decls/index.js +++ b/decls/index.js @@ -228,10 +228,12 @@ type Providers = { cps?: Provider, flush?: Provider, fork?: Provider, + getContext?: Provider, join?: Provider, put?: Provider, race?: Provider, select?: Provider, + setContext?: Provider, spawn?: Provider, take?: Provider, }; diff --git a/src/expectSaga/index.js b/src/expectSaga/index.js index 91c88168..29b0a77b 100644 --- a/src/expectSaga/index.js +++ b/src/expectSaga/index.js @@ -35,9 +35,11 @@ import { CALL, CPS, FORK, + GET_CONTEXT, PUT, RACE, SELECT, + SET_CONTEXT, TAKE, } from '../shared/keys'; @@ -83,7 +85,9 @@ const exposableEffects = { [CALL]: 'call', [CPS]: 'cps', [FORK]: 'fork', + [GET_CONTEXT]: 'getContext', [SELECT]: 'select', + [SET_CONTEXT]: 'setContext', [ACTION_CHANNEL]: 'actionChannel', }; @@ -99,6 +103,8 @@ export default function expectSaga( [CALL]: new ArraySet(), [CPS]: new ArraySet(), [FORK]: new ArraySet(), + [GET_CONTEXT]: new ArraySet(), + [SET_CONTEXT]: new ArraySet(), [SELECT]: new ArraySet(), [ACTION_CHANNEL]: new ArraySet(), }; @@ -484,10 +490,20 @@ export default function expectSaga( call: createEffectTesterFromEffects('call', CALL, asEffect.call), cps: createEffectTesterFromEffects('cps', CPS, asEffect.cps), fork: createEffectTesterFromEffects('fork', FORK, asEffect.fork), + getContext: createEffectTesterFromEffects( + 'getContext', + GET_CONTEXT, + asEffect.getContext, + ), put: createEffectTesterFromEffects('put', PUT, asEffect.put), race: createEffectTesterFromEffects('race', RACE, asEffect.race), select: createEffectTesterFromEffects('select', SELECT, asEffect.select), spawn: createEffectTesterFromEffects('spawn', FORK, asEffect.fork), + setContext: createEffectTesterFromEffects( + 'setContext', + SET_CONTEXT, + asEffect.setContext, + ), take: createEffectTesterFromEffects('take', TAKE, asEffect.take), }; diff --git a/src/expectSaga/matchers/index.js b/src/expectSaga/matchers/index.js index 1aeb8448..84fdb50e 100644 --- a/src/expectSaga/matchers/index.js +++ b/src/expectSaga/matchers/index.js @@ -9,11 +9,13 @@ export const cancel = wrapEffectCreator(effects.cancel); export const cancelled = wrapEffectCreator(effects.cancelled); export const cps = wrapEffectCreator(effects.cps); export const flush = wrapEffectCreator(effects.flush); +export const getContext = wrapEffectCreator(effects.getContext); export const fork = wrapEffectCreator(effects.fork); export const join = wrapEffectCreator(effects.join); export const put = wrapEffectCreator(effects.put); export const race = wrapEffectCreator(effects.race); export const select = wrapEffectCreator(effects.select); +export const setContext = wrapEffectCreator(effects.setContext); export const spawn = wrapEffectCreator(effects.spawn); export const take = wrapEffectCreator(effects.take); diff --git a/src/expectSaga/parseEffect.js b/src/expectSaga/parseEffect.js index a4010aca..ad4de6ba 100644 --- a/src/expectSaga/parseEffect.js +++ b/src/expectSaga/parseEffect.js @@ -11,11 +11,13 @@ import { CPS, FLUSH, FORK, + GET_CONTEXT, JOIN, NONE, PUT, RACE, SELECT, + SET_CONTEXT, TAKE, } from '../shared/keys'; @@ -98,6 +100,13 @@ export default function parseEffect(effect: Object): Object { providerKey: parsedEffect.detached ? 'spawn' : 'fork', }; + case is.notUndef((parsedEffect = asEffect.getContext(effect))): + return { + type: GET_CONTEXT, + effect: parsedEffect, + providerKey: 'getContext', + }; + case is.notUndef((parsedEffect = asEffect.join(effect))): return { type: JOIN, @@ -112,6 +121,13 @@ export default function parseEffect(effect: Object): Object { providerKey: 'select', }; + case is.notUndef((parsedEffect = asEffect.setContext(effect))): + return { + type: SET_CONTEXT, + effect: parsedEffect, + providerKey: 'setContext', + }; + case is.notUndef((parsedEffect = asEffect.actionChannel(effect))): return { type: ACTION_CHANNEL, diff --git a/src/expectSaga/provideValue.js b/src/expectSaga/provideValue.js index e1eb044d..4e75cb23 100644 --- a/src/expectSaga/provideValue.js +++ b/src/expectSaga/provideValue.js @@ -11,10 +11,12 @@ import { CPS, FLUSH, FORK, + GET_CONTEXT, JOIN, PUT, RACE, SELECT, + SET_CONTEXT, TAKE, } from '../shared/keys'; @@ -50,10 +52,12 @@ export const handlers = { return NEXT; }, + [GET_CONTEXT]: 'getContext', [JOIN]: 'join', [PUT]: 'put', [RACE]: 'race', [SELECT]: 'select', + [SET_CONTEXT]: 'setContext', [TAKE]: 'take', }; diff --git a/src/shared/keys.js b/src/shared/keys.js index 3e5e690d..eb30b681 100644 --- a/src/shared/keys.js +++ b/src/shared/keys.js @@ -7,10 +7,12 @@ export const CANCELLED = 'CANCELLED'; export const CPS = 'CPS'; export const FLUSH = 'FLUSH'; export const FORK = 'FORK'; +export const GET_CONTEXT = 'GET_CONTEXT'; export const JOIN = 'JOIN'; export const NONE = 'NONE'; export const PUT = 'PUT'; export const RACE = 'RACE'; export const SELECT = 'SELECT'; +export const SET_CONTEXT = 'SET_CONTEXT'; export const TAKE = 'TAKE'; export const HELPER = '@@redux-saga/HELPER';