UNPKG

hooks-for-redux

Version:
281 lines (242 loc) 7.26 kB
// index.js import React from "react"; import renderer from "react-test-renderer"; import { Provider, createReduxModule, getStore } from "../../index"; describe("basic mode", () => { const STORE_KEY = "basicModeName"; const [subscribeToName, updateName, { getState }] = createReduxModule(STORE_KEY, "Alice"); const expectNameToEqual = expected => expect(getState()).toEqual(expected); it("updateName(newState) works", () => { updateName("Al"); expectNameToEqual("Al"); }); const App = () => <p>Hello there, {subscribeToName()}! Click to change me.</p>; it("subscribeToName works", () => { updateName("Alice"); const component = renderer.create( <Provider> <App /> </Provider> ); expect(component.toJSON()).toMatchSnapshot(); renderer.act(() => { updateName("Shane"); }); expect(component.toJSON()).toMatchSnapshot(); component.unmount(); }); it("getState", () => { expect(typeof getState()).toEqual("string"); expect(getState()).toEqual(getStore().getState()[STORE_KEY]); }); }); describe("reducers mode", () => { const STORE_KEY = "reducerModeName"; const [subscribeToName, { toggleName, mrName, updateName }, { getState, getReducers }] = createReduxModule( STORE_KEY, "Alice", { toggleName: name => (name == "Alice" ? "Bob" : "Alice"), mrName: name => (name == "Alice" ? "Mrs Alice" : "Mr Bob"), updateName: (name, newName) => newName, } ); const expectNameToEqual = expected => expect(getState()).toEqual(expected); const App = () => <p>Hello there, {subscribeToName()}! Click to change me.</p>; it("subscribeToName works", () => { updateName("Alice"); const component = renderer.create( <Provider> <App /> </Provider> ); expect(component.toJSON()).toMatchSnapshot(); renderer.act(() => { updateName("Shane"); }); expect(component.toJSON()).toMatchSnapshot(); component.unmount(); }); it("updateName(newState) works", () => { updateName("Al"); expectNameToEqual("Al"); }); it("toggleName from addReducers works", () => { updateName("Alice"); toggleName(); expectNameToEqual("Bob"); }); it("mrName from addReducers works", () => { updateName("Alice"); mrName(); expectNameToEqual("Mrs Alice"); }); it("getState", () => { expect(typeof getState()).toEqual("string"); expect(getState()).toEqual(getStore().getState()[STORE_KEY]); }); it("getStore", () => { expect(typeof getStore().injectReducer).toEqual("function"); }); }); describe("subcriptions outside react", () => { const STORE_KEY = "createReduxModule testCounter"; const [useName, { increment }, { getState, getReducers, subscribe }] = createReduxModule(STORE_KEY, 0, { increment: v => v + 1, }); it("subscribe", () => { let lastValueSeen = getState(); let firstValueSeen = lastValueSeen; const unsubscribe = subscribe(newValue => { expect(newValue).toEqual(lastValueSeen + 1); lastValueSeen = newValue; }); increment(); expect(lastValueSeen).toEqual(firstValueSeen + 1); unsubscribe(); increment(); expect(lastValueSeen).toEqual(firstValueSeen + 1); }); }); describe("duplicate action names", () => { const [useCountA, { increment: incrementCountA }, { getState: getCountAState }] = createReduxModule("count-a", 0, { increment: v => v + 1, }); const [useCountB, { increment: incrementCountB }, { getState: getCountBState }] = createReduxModule("count-b", 0, { increment: v => v + 1, }); it("doesn't interfere", () => { expect(getCountAState()).toEqual(0); expect(getCountBState()).toEqual(0); incrementCountA(); expect(getCountAState()).toEqual(1); expect(getCountBState()).toEqual(0); }); }); describe("use state subset", () => { const STORE_KEY = "subsetModeName"; const [useName, { setFirstName, setLastName }] = createReduxModule( STORE_KEY, { firstName: "Marty", lastName: "McFly", }, { setFirstName: (state, firstName) => ({ ...state, firstName }), setLastName: (state, lastName) => ({ ...state, lastName }), } ); const App = () => { renderCount++; return <p>Hello {useName(({ firstName }) => firstName)}!</p>; }; let renderCount = 0; it("initial render", () => { renderer.create( <Provider> <App /> </Provider> ); expect(renderCount).toBe(1); }); // Changing first name should trigger a render it("re-render on change", () => { renderer.act(() => { setFirstName("Emmett"); }); expect(renderCount).toBe(2); }); // Changing last name should not trigger a render it("does not re-render on change", () => { renderer.act(() => { setLastName("Brown"); }); expect(renderCount).toBe(2); }); }); describe("use state subset with custom comparator", () => { const STORE_KEY = "subsetModeName2"; const [useName, { setFirstName, setLastName }] = createReduxModule( STORE_KEY, { firstName: "Marty", lastName: "McFly", }, { setFirstName: (state, firstName) => ({ ...state, firstName }), setLastName: (state, lastName) => ({ ...state, lastName }), } ); describe("App1 does not have the custom comparator and always re-renders", () => { const App1 = () => { renderCount++; return <p>Hello {useName(({ firstName }) => [firstName])[0]}!</p>; }; let renderCount = 0; it("initial render App1", () => { renderer.create( <Provider> <App1 /> </Provider> ); expect(renderCount).toBe(1); }); // Changing first name should trigger a render it("App1 re-renders on change", () => { renderer.act(() => { setFirstName("Emmett"); }); expect(renderCount).toBe(2); }); // Changing last name should not trigger a render it("App1 re-renders all the time without the custom comparator", () => { renderer.act(() => { setLastName("Brown"); }); expect(renderCount).toBe(3); }); }); describe("App2 has a custom comparator and only re-renders when firstName changes", () => { const App2 = () => { renderCount++; return ( <p> Hello{" "} { useName( ({ firstName }) => [firstName], (a, b) => a[0] === b[0] )[0] } ! </p> ); }; let renderCount = 0; it("initial render App2", () => { renderer.act(() => { setFirstName("Marty"); }); renderer.create( <Provider> <App2 /> </Provider> ); expect(renderCount).toBe(1); }); // Changing first name should trigger a render it("App2 re-renders on change", () => { renderer.act(() => { setFirstName("Emmett"); }); expect(renderCount).toBe(2); }); // Changing last name should not trigger a render it("App2 re-renders all the time without the custom comparator", () => { renderer.act(() => { setLastName("Brown"); }); expect(renderCount).toBe(2); }); }); });