<commit_before>jest.unmock('../src/Store');

import Immutable from 'immutable';
import Store from '../src/Store';

function createUpdater(finalState) {
  return jest.fn().mockImplementation((initialState) => finalState? finalState: initialState);
}

function createMiddleware(impl) {
  return jest.fn().mockImplementation(impl? impl: (state, action, next) => next(state, action));
}

describe('Store', () => {
  describe('dispatch(...)', () => {
    pit('will call each updater, with the given action', () => {
      // Test Data
      const action = { type: 'TEST_ACTION' };
      const updaters = [
        createUpdater(),
        createUpdater(),
        createUpdater()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters
      });

      // Perform Tests
      return store.dispatch(action).then(() => {
        updaters.forEach((updater) => {
          const { calls } = updater.mock;
          expect(calls.length).toBe(1);

          const [_, dispatchedAction] = calls[0];
          expect(dispatchedAction).toBe(action);
        });
      });
    });

    pit('will call the first updaters, with given the state', () => {
      // Test Data
      const initialState = { data: 'test state' };
      const updaters = [
        createUpdater(),
        createUpdater(),
        createUpdater()
      ];
      const store = Store.createStore({
        initialState,
        updaters
      });

      // Perform Tests
      return store.dispatch({ }).then(() => {
        const { calls } = updaters[0].mock;
        expect(calls.length).toBe(1);

        const [dispatchedState] = calls[0];
        expect(dispatchedState).toBe(initialState);
      });
    });

    pit('will call all but the first updaters, with the value returned from the previous updater', () => {
      // Test Data
      const updatedStates = [
        null,
        { data: 'updated state 1' },
        { data: 'updated state 2' }
      ];
      const updaters = [
        createUpdater(updatedStates[1]),
        createUpdater(Promise.resolve(updatedStates[2])),
        createUpdater()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters
      });

      // Perform Tests
      return store.dispatch({ }).then(() => {
        for(let i=1; i<updaters.length; i++) {
          const { calls } = updaters[i].mock;
          expect(calls.length).toBe(1);

          const [dispatchedState] = calls[0];
          expect(dispatchedState).toBe(updatedStates[i]);
        }
      });
    });

    pit('will return a promise with the state from the final updater', () => {
      // Test Data
      const finalState = { data: 'test state' };
      const store = Store.createStore({
        initialState: {},
        updaters: [
          createUpdater(),
          createUpdater(),
          createUpdater(finalState)
        ]
      });

      // Perform Tests
      return store.dispatch({ }).then((newStore) => {
        expect(newStore.getState()).toEqual(finalState);
      });
    });

    pit('will call all the middleware in the store for each updater', () => {
      // Test Data
      const updaters = [
        createUpdater(),
        createUpdater(),
        createUpdater()
      ];
      const middleware = [
        createMiddleware(),
        createMiddleware(),
        createMiddleware()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters,
        middleware
      });

       // Perform Tests
      return store.dispatch({ }).then(() => {
        for(let i=0; i<middleware.length; i++) {
          const { calls } = middleware[i].mock;
          expect(calls.length).toBe(updaters.length);
        }
      });
    });

    pit('will call the middleware with stores state', () => {
      // Test Data
      const initialState = { data: 'test state' };
      const middleware = [
        createMiddleware(),
        createMiddleware(),
        createMiddleware()
      ];
      const store = Store.createStore({
        initialState,
        updaters: [
          createUpdater(),
          createUpdater(),
          createUpdater()
        ],
        middleware
      });

       // Perform Tests
      return store.dispatch({ }).then(() => {
        for(let i=0; i<middleware.length; i++) {
          const { calls } = middleware[i].mock;
          for(let j=0; j<calls.length; j++) {
            const [ state ] = calls[j];

            expect(state).toEqual(initialState);
          }
        }
      });
    });

    pit('will call the middleware with dispatched action', () => {
      // Test Data
      const action = { type: 'TEST_ACTION' };
      const middleware = [
        createMiddleware(),
        createMiddleware(),
        createMiddleware()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters: [
          createUpdater(),
          createUpdater(),
          createUpdater()
        ],
        middleware
      });

       // Perform Tests
      return store.dispatch(action).then(() => {
        for(let i=0; i<middleware.length; i++) {
          const { calls } = middleware[i].mock;
          for(let j=0; j<calls.length; j++) {
            const [ _, dispatchedAction ] = calls[j];

            expect(dispatchedAction).toBe(action);
          }
        }
      });
    });

    pit('will have a next function, that calls the updaters and "lower" middleware with modified action/state', () => {
      // Test Data
      const initialState = { data: 'test state' };
      const updatedState = { data: 'modified test state' };
      const initialAction = { type: 'TEST_ACTION' };
      const updatedAction = { type: 'TEST_ACTION', isUpdated: true };
      const updaters = [
        createUpdater(),
        createUpdater(),
        createUpdater()
      ];
      const middleware = [
        createMiddleware((_, action, next) => next(updatedState, action)),
        createMiddleware((state, _, next) => next(state, updatedAction)),
        createMiddleware()
      ];
      const store = Store.createStore({
        initialState,
        updaters,
        middleware
      });

       // Perform Tests
      return store.dispatch(initialAction).then(() => {
        for(let m=0; m<middleware.length; m++) {
          // Check if the middleware is passed the correct state / action
          const { calls } = middleware[m].mock;
          for(let c=0; c<calls.length; c++) {
            const [ state, action ] = calls[c];

            if(c === 0 && m <= 0) expect(state).toBe(initialState);
            else                  expect(state).toBe(updatedState);

            if(m <= 1)            expect(action).toBe(initialAction);
            else                  expect(action).toBe(updatedAction);
          }

          // Check if the updaters are passed the updated state
          for(let u=0; u<updaters.length; u++) {
            const { calls: updaterCalls } = updaters[u].mock;
            expect(updaterCalls.length).toBe(1);

            const [ state, action ] = updaterCalls[0];
            expect(state).toEqual(updatedState);
            expect(action).toEqual(updatedAction);
          }
        }
      });
    });

    pit('will return a reject promise if an updater throws an error', () => {
      // Test Data
      const testError = new Error();
      const updaters = [
        createUpdater(),
        jest.fn(() => { throw testError; }),
        createUpdater()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters
      });

      // Perform Tests<commit_msg>Add Tests for Middleware / Plugins<commit_after>jest.unmock('../src/Store');

import Immutable from 'immutable';
import Store from '../src/Store';

function createUpdater(finalState) {
  return jest.fn().mockImplementation((initialState) => finalState? finalState: initialState);
}

function createMiddleware(impl) {
  return jest.fn().mockImplementation(impl? impl: (state, action, plugins, next) => next(state, action, plugins));
}

describe('Store', () => {
  describe('dispatch(...)', () => {
    pit('will call each updater, with the given action', () => {
      // Test Data
      const action = { type: 'TEST_ACTION' };
      const updaters = [
        createUpdater(),
        createUpdater(),
        createUpdater()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters
      });

      // Perform Tests
      return store.dispatch(action).then(() => {
        updaters.forEach((updater) => {
          const { calls } = updater.mock;
          expect(calls.length).toBe(1);

          const [_, dispatchedAction] = calls[0];
          expect(dispatchedAction).toBe(action);
        });
      });
    });

    pit('will call the first updaters, with given the state', () => {
      // Test Data
      const initialState = { data: 'test state' };
      const updaters = [
        createUpdater(),
        createUpdater(),
        createUpdater()
      ];
      const store = Store.createStore({
        initialState,
        updaters
      });

      // Perform Tests
      return store.dispatch({ }).then(() => {
        const { calls } = updaters[0].mock;
        expect(calls.length).toBe(1);

        const [dispatchedState] = calls[0];
        expect(dispatchedState).toBe(initialState);
      });
    });

    pit('will call all but the first updaters, with the value returned from the previous updater', () => {
      // Test Data
      const updatedStates = [
        null,
        { data: 'updated state 1' },
        { data: 'updated state 2' }
      ];
      const updaters = [
        createUpdater(updatedStates[1]),
        createUpdater(Promise.resolve(updatedStates[2])),
        createUpdater()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters
      });

      // Perform Tests
      return store.dispatch({ }).then(() => {
        for(let i=1; i<updaters.length; i++) {
          const { calls } = updaters[i].mock;
          expect(calls.length).toBe(1);

          const [dispatchedState] = calls[0];
          expect(dispatchedState).toBe(updatedStates[i]);
        }
      });
    });

    pit('will call the updaters with a plugins object', () => {
      // Test Data
      const updaters = [
        createUpdater(),
        createUpdater(),
        createUpdater()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters
      });

      // Perform Tests
      return store.dispatch({}).then(() => {
        for(let u=0; u<updaters.length; u++) {
          const { calls } = updaters[u].mock;
          expect(calls.length).toBe(1);

          const [ _, __, plugins ] = calls[0];
          expect(plugins).toBeDefined();
        }
      });
    });

    pit('will call the updaters with the getIndex plugin, that returns the current index of the updater', () => {
      // Test Data
      const updaters = [
        createUpdater(),
        createUpdater(),
        createUpdater()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters
      });

      // Perform Tests
      return store.dispatch({}).then(() => {
        for(let u=0; u<updaters.length; u++) {
          const { calls } = updaters[u].mock;
          expect(calls.length).toBe(1);

          const [ _, __, plugins ] = calls[0];
          expect(plugins.getIndex()).toEqual(u);
        }
      });
    });

    pit('will return a promise with the state from the final updater', () => {
      // Test Data
      const finalState = { data: 'test state' };
      const store = Store.createStore({
        initialState: {},
        updaters: [
          createUpdater(),
          createUpdater(),
          createUpdater(finalState)
        ]
      });

      // Perform Tests
      return store.dispatch({ }).then((newStore) => {
        expect(newStore.getState()).toEqual(finalState);
      });
    });

    pit('will call all the middleware in the store for each updater', () => {
      // Test Data
      const updaters = [
        createUpdater(),
        createUpdater(),
        createUpdater()
      ];
      const middleware = [
        createMiddleware(),
        createMiddleware(),
        createMiddleware()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters,
        middleware
      });

       // Perform Tests
      return store.dispatch({ }).then(() => {
        for(let i=0; i<middleware.length; i++) {
          const { calls } = middleware[i].mock;
          expect(calls.length).toBe(updaters.length);
        }
      });
    });

    pit('will call the middleware with stores state', () => {
      // Test Data
      const initialState = { data: 'test state' };
      const middleware = [
        createMiddleware(),
        createMiddleware(),
        createMiddleware()
      ];
      const store = Store.createStore({
        initialState,
        updaters: [
          createUpdater(),
          createUpdater(),
          createUpdater()
        ],
        middleware
      });

       // Perform Tests
      return store.dispatch({ }).then(() => {
        for(let i=0; i<middleware.length; i++) {
          const { calls } = middleware[i].mock;
          for(let j=0; j<calls.length; j++) {
            const [ state ] = calls[j];

            expect(state).toEqual(initialState);
          }
        }
      });
    });

    pit('will call the middleware with dispatched action', () => {
      // Test Data
      const action = { type: 'TEST_ACTION' };
      const middleware = [
        createMiddleware(),
        createMiddleware(),
        createMiddleware()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters: [
          createUpdater(),
          createUpdater(),
          createUpdater()
        ],
        middleware
      });

       // Perform Tests
      return store.dispatch(action).then(() => {
        for(let i=0; i<middleware.length; i++) {
          const { calls } = middleware[i].mock;
          for(let j=0; j<calls.length; j++) {
            const [ _, dispatchedAction ] = calls[j];

            expect(dispatchedAction).toBe(action);
          }
        }
      });
    });

    pit('will have middleware with next(), that calls updaters/middleware with updated action/state/plugins', () => {
      // Test Data
      const initialState = { data: 'test state' };
      const updatedState = { data: 'modified test state' };
      const initialAction = { type: 'TEST_ACTION' };
      const updatedAction = { type: 'TEST_ACTION', isUpdated: true };
      const updatedPlugin = { test: 'plugin' };
      const updaters = [
        createUpdater(),
        createUpdater(),
        createUpdater()
      ];
      const middleware = [
        createMiddleware((_, action, plugins, next) => next(updatedState, action, plugins)),
        createMiddleware((state, _, plugins, next) => next(state, updatedAction, plugins)),
        createMiddleware((state, action, plugins, next) => {
          plugins.testPlugin = updatedPlugin;
          return next(state, updatedAction, plugins);
        }),
        createMiddleware()
      ];
      const store = Store.createStore({
        initialState,
        updaters,
        middleware
      });

       // Perform Tests
      return store.dispatch(initialAction).then(() => {
        for(let m=0; m<middleware.length; m++) {
          // Check if the middleware is passed the correct state / action
          const { calls } = middleware[m].mock;
          for(let c=0; c<calls.length; c++) {
            const [ state, action, plugins ] = calls[c];

            if(c === 0 && m <= 0) expect(state).toBe(initialState);
            else                  expect(state).toBe(updatedState);

            if(m <= 1)            expect(action).toBe(initialAction);
            else                  expect(action).toBe(updatedAction);

            //NOTE, can't check before/after because plugins is mutable
            if(m > 2)             expect(plugins.testPlugin).toBe(updatedPlugin);
            //if(m <= 2)            expect(plugins.testPlugin).toBeUndefined();
            //else                  expect(plugins.testPlugin).toBe(updatedPlugin);
          }
        }

        // Check if the updaters are passed the updated state
        for(let u=0; u<updaters.length; u++) {
          const { calls } = updaters[u].mock;
          expect(calls.length).toBe(1);

          const [ state, action, plugins ] = calls[0];
          expect(state).toEqual(updatedState);
          expect(action).toEqual(updatedAction);
          expect(plugins.testPlugin).toBe(updatedPlugin);
        }
      });
    });

    pit('will return a reject promise if an updater throws an error', () => {
      // Test Data
      const testError = new Error();
      const updaters = [
        createUpdater(),
        jest.fn(() => { throw testError; }),
        createUpdater()
      ];
      const store = Store.createStore({
        initialState: {},
        updaters
      });

      // Perform Tests
{'fraction_non_alphanumeric': 0.1389002512709636, 'fraction_numerical': 0.003389236253140887, 'mean_word_length': 1.907577302072715, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '734865', 'n_tokens_mistral': 4742, 'n_tokens_neox': 4735, 'n_words': 1085}