/** * Test injectors */ import { memoryHistory } from 'react-router-dom'; import { put } from 'redux-saga/effects'; import configureStore from '../../configureStore'; import getInjectors, { injectSagaFactory, ejectSagaFactory, } from '../sagaInjectors'; import { DAEMON, ONCE_TILL_UNMOUNT, RESTART_ON_REMOUNT } from '../constants'; function* testSaga() { yield put({ type: 'TEST', payload: 'yup' }); } describe('injectors', () => { const originalNodeEnv = process.env.NODE_ENV; let store; let injectSaga; let ejectSaga; describe('getInjectors', () => { beforeEach(() => { store = configureStore({}, memoryHistory); }); it('should return injectors', () => { expect(getInjectors(store)).toEqual( expect.objectContaining({ injectSaga: expect.any(Function), ejectSaga: expect.any(Function), }), ); }); it('should throw if passed invalid store shape', () => { Reflect.deleteProperty(store, 'dispatch'); expect(() => getInjectors(store)).toThrow(); }); }); describe('ejectSaga helper', () => { beforeEach(() => { store = configureStore({}, memoryHistory); injectSaga = injectSagaFactory(store, true); ejectSaga = ejectSagaFactory(store, true); }); it('should check a store if the second argument is falsy', () => { const eject = ejectSagaFactory({}); expect(() => eject('test')).toThrow(); }); it('should not check a store if the second argument is true', () => { Reflect.deleteProperty(store, 'dispatch'); injectSaga('test', { saga: testSaga }); expect(() => ejectSaga('test')).not.toThrow(); }); it("should validate saga's key", () => { expect(() => ejectSaga('')).toThrow(); expect(() => ejectSaga(1)).toThrow(); }); it('should cancel a saga in RESTART_ON_REMOUNT mode', () => { const cancel = jest.fn(); store.injectedSagas.test = { task: { cancel }, mode: RESTART_ON_REMOUNT }; ejectSaga('test'); expect(cancel).toHaveBeenCalled(); }); it('should not cancel a daemon saga', () => { const cancel = jest.fn(); store.injectedSagas.test = { task: { cancel }, mode: DAEMON }; ejectSaga('test'); expect(cancel).not.toHaveBeenCalled(); }); it('should ignore saga that was not previously injected', () => { expect(() => ejectSaga('test')).not.toThrow(); }); it("should remove non daemon saga's descriptor in production", () => { process.env.NODE_ENV = 'production'; injectSaga('test', { saga: testSaga, mode: RESTART_ON_REMOUNT }); injectSaga('test1', { saga: testSaga, mode: ONCE_TILL_UNMOUNT }); ejectSaga('test'); ejectSaga('test1'); expect(store.injectedSagas.test).toBe('done'); expect(store.injectedSagas.test1).toBe('done'); process.env.NODE_ENV = originalNodeEnv; }); it("should not remove daemon saga's descriptor in production", () => { process.env.NODE_ENV = 'production'; injectSaga('test', { saga: testSaga, mode: DAEMON }); ejectSaga('test'); expect(store.injectedSagas.test.saga).toBe(testSaga); process.env.NODE_ENV = originalNodeEnv; }); it("should not remove daemon saga's descriptor in development", () => { injectSaga('test', { saga: testSaga, mode: DAEMON }); ejectSaga('test'); expect(store.injectedSagas.test.saga).toBe(testSaga); }); }); describe('injectSaga helper', () => { beforeEach(() => { store = configureStore({}, memoryHistory); injectSaga = injectSagaFactory(store, true); ejectSaga = ejectSagaFactory(store, true); }); it('should check a store if the second argument is falsy', () => { const inject = injectSagaFactory({}); expect(() => inject('test', testSaga)).toThrow(); }); it('it should not check a store if the second argument is true', () => { Reflect.deleteProperty(store, 'dispatch'); expect(() => injectSaga('test', { saga: testSaga })).not.toThrow(); }); it("should validate saga's key", () => { expect(() => injectSaga('', { saga: testSaga })).toThrow(); expect(() => injectSaga(1, { saga: testSaga })).toThrow(); }); it("should validate saga's descriptor", () => { expect(() => injectSaga('test')).toThrow(); expect(() => injectSaga('test', { saga: 1 })).toThrow(); expect(() => injectSaga('test', { saga: testSaga, mode: 'testMode' }), ).toThrow(); expect(() => injectSaga('test', { saga: testSaga, mode: 1 })).toThrow(); expect(() => injectSaga('test', { saga: testSaga, mode: RESTART_ON_REMOUNT }), ).not.toThrow(); expect(() => injectSaga('test', { saga: testSaga, mode: DAEMON }), ).not.toThrow(); expect(() => injectSaga('test', { saga: testSaga, mode: ONCE_TILL_UNMOUNT }), ).not.toThrow(); }); it('should pass args to saga.run', () => { const args = {}; store.runSaga = jest.fn(); injectSaga('test', { saga: testSaga }, args); expect(store.runSaga).toHaveBeenCalledWith(testSaga, args); }); it('should not start daemon and once-till-unmount sagas if were started before', () => { store.runSaga = jest.fn(); injectSaga('test1', { saga: testSaga, mode: DAEMON }); injectSaga('test1', { saga: testSaga, mode: DAEMON }); injectSaga('test2', { saga: testSaga, mode: ONCE_TILL_UNMOUNT }); injectSaga('test2', { saga: testSaga, mode: ONCE_TILL_UNMOUNT }); expect(store.runSaga).toHaveBeenCalledTimes(2); }); it('should start any saga that was not started before', () => { store.runSaga = jest.fn(); injectSaga('test1', { saga: testSaga }); injectSaga('test2', { saga: testSaga, mode: DAEMON }); injectSaga('test3', { saga: testSaga, mode: ONCE_TILL_UNMOUNT }); expect(store.runSaga).toHaveBeenCalledTimes(3); }); it('should restart a saga if different implementation for hot reloading', () => { const cancel = jest.fn(); store.injectedSagas.test = { saga: testSaga, task: { cancel } }; store.runSaga = jest.fn(); function* testSaga1() { yield put({ type: 'TEST', payload: 'yup' }); } injectSaga('test', { saga: testSaga1 }); expect(cancel).toHaveBeenCalledTimes(1); expect(store.runSaga).toHaveBeenCalledWith(testSaga1, undefined); }); it('should not cancel saga if different implementation in production', () => { process.env.NODE_ENV = 'production'; const cancel = jest.fn(); store.injectedSagas.test = { saga: testSaga, task: { cancel }, mode: RESTART_ON_REMOUNT, }; function* testSaga1() { yield put({ type: 'TEST', payload: 'yup' }); } injectSaga('test', { saga: testSaga1, mode: DAEMON }); expect(cancel).toHaveBeenCalledTimes(0); process.env.NODE_ENV = originalNodeEnv; }); it('should save an entire descriptor in the saga registry', () => { injectSaga('test', { saga: testSaga, foo: 'bar' }); expect(store.injectedSagas.test.foo).toBe('bar'); }); }); });