Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ Add the following lines to `package.json` for code coverage
"collectCoverageFrom": [
"src/**/*.{js,jsx,mjs}",
"!src/index.js",
"!src/store.js",
"!src/registerServiceWorker.js"
],
"coverageThreshold": {
Expand All @@ -118,7 +117,7 @@ Add the following lines to `package.json` for code coverage

Run unit tests
```sh
yarn test
yarn test --coverage
```

Run
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ if (taskArg === 'create' && typeArg === 'firstcontainer') {
create.rootSagaJs(nameArg);
create.rootSagaTestJs(nameArg);
create.storeJs(nameArg);
create.storeTestJs(nameArg);
create.navigatorJs(nameArg);
create.navigatorTestJs(nameArg);
create.appJs(nameArg);
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cli-react-redux",
"version": "1.2.1",
"version": "1.3.0",
"description": "React Redux CLI",
"main": "index.js",
"scripts": {
Expand Down
14 changes: 14 additions & 0 deletions src/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,20 @@ async function storeJs(name) {
}
module.exports.storeJs = storeJs;

async function storeTestJs(name) {
try {
const filePath = path.join(pwd, 'src', '__tests__', 'store.test.js');
await fs.copy(
path.join(cliDir, 'templates', 'store.test'),
filePath,
);
await replacePlaceHolders(filePath, name);
} catch (error) {
console.error(error);
}
}
module.exports.storeTestJs = storeTestJs;

async function navigatorJs(name) {
try {
const filePath = path.join(pwd, 'src', 'Navigator.js');
Expand Down
2 changes: 1 addition & 1 deletion src/templates/App.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import App from '../App';

// ./node_modules/.bin/jest ./src/__tests__/App.test.js --env=jsdom
// yarn test ./src/__tests__/App.test.js --coverage
describe('<App />', () => {
it('renders without crashing', () => {
const div = document.createElement('div');
Expand Down
2 changes: 1 addition & 1 deletion src/templates/IndexComponent.test
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import renderer from 'react-test-renderer';
import { mount } from 'enzyme';
import '<NameOf>' from '../'<NameOf>'';

// ./node_modules/.bin/jest ./src/containers/'<nameof>'/__tests__/'<NameOf>'.test.js --env=jsdom
// yarn test ./src/containers/'<nameof>'/__tests__/'<NameOf>'.test.js --coverage
describe('<'<NameOf>' />', () => {
const propsMock = {
data: { foo: 'bar' },
Expand Down
2 changes: 1 addition & 1 deletion src/templates/index.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as actionType from '../actionTypes';
import '<NameOf>', { mapStateToProps, mapDispatchToProps } from '../index';

// ./node_modules/.bin/jest ./src/containers/'<nameof>'/__tests__/index.test.js --env=jsdom
// yarn test ./src/containers/'<nameof>'/__tests__/index.test.js --coverage
describe('<'<NameOf>' /> Connected', () => {
it('should export default connected <'<NameOf>' />', () => {
expect('<NameOf>'.displayName)
Expand Down
2 changes: 1 addition & 1 deletion src/templates/navigator.test
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { shallow } from 'enzyme';

import Navigator from '../Navigator';

// ./node_modules/.bin/jest ./src/__tests__/Navigator.test.js --env=jsdom
// yarn test ./src/__tests__/Navigator.test.js --coverage
describe('<Navigator />', () => {
it('has at least one route defined', () => {
expect(shallow(<Navigator />).find(Route).length)
Expand Down
2 changes: 1 addition & 1 deletion src/templates/reducer.test
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import '<nameOf>'Reducer from '../reducer';
import * as actionType from '../actionTypes';

// ./node_modules/.bin/jest ./src/containers/'<nameof>'/__tests__/reducer.test.js --env=jsdom
// yarn test ./src/containers/'<nameof>'/__tests__/reducer.test.js --coverage
describe('<'<NameOf>' /> reducer', () => {
let state;
beforeEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/templates/rootReducer.test
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import rootReducer from '../rootReducer';

// ./node_modules/.bin/jest ./src/__tests__/rootReducer.test.js --env=jsdom
// yarn test ./src/__tests__/rootReducer.test.js --coverage
describe('rootReducer', () => {
it('exists', () => {
expect(typeof rootReducer).toEqual('function');
Expand Down
2 changes: 1 addition & 1 deletion src/templates/rootSaga.test
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { all } from 'redux-saga/effects';
import { watch'<NameOf>'Sagas } from '../containers/'<nameof>'/sagas';
import rootSaga from '../rootSaga';

// ./node_modules/.bin/jest ./src/__tests__/rootSaga.test.js --env=jsdom
// yarn test ./src/__tests__/rootSaga.test.js --coverage
describe('rootSaga', () => {
it('starts to watch Sagas', () => {
const generator = rootSaga();
Expand Down
2 changes: 1 addition & 1 deletion src/templates/sagas.test
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import axios from 'axios';
import { fetchDataAsync, watch'<NameOf>'Sagas } from '../sagas';
import * as actionType from '../actionTypes';

// ./node_modules/.bin/jest ./src/containers/'<nameof>'/__tests__/sagas.test.js --env=jsdom
// yarn test ./src/containers/'<nameof>'/__tests__/sagas.test.js --coverage
describe('<'<NameOf>' /> sagas', () => {
describe('fetchDataAsync', () => {
it('ends with fetchDataSuccess if successful API call', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/templates/selectors.test
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { select'<NameOf>', makeSelectData } from '../selectors';

// ./node_modules/.bin/jest ./src/containers/'<nameof>'/__tests__/selectors.test.js --env=jsdom
// yarn test ./src/containers/'<nameof>'/__tests__/selectors.test.js --coverage
describe('<'<NameOf>' /> selectors', () => {
describe('select'<NameOf>'', () => {
it('should select the '<nameOf>' state', () => {
Expand Down
62 changes: 39 additions & 23 deletions src/templates/store
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,66 @@ import createHistory from 'history/createBrowserHistory'; // eslint-disable-line
import rootReducer from './rootReducer';
import rootSaga from './rootSaga';

export const storeElements = {
export const rdx = {
initialState: {},
enhancers: [],
history: undefined,
store: undefined,
};
createHistory,
sagaMiddleware: undefined,
createSagaMiddleware,
middleware: undefined,
routerMiddleware,
appliedMiddleware: undefined,
compose,
composedEnhancers: undefined,
applyMiddleware,
createStore,
rootReducer,
rootSaga,
}

export default function configureStore() {
storeElements.history = createHistory();

const initialState = {};
const enhancers = [];
const sagaMiddleware = createSagaMiddleware();
const middleware = [
sagaMiddleware,
routerMiddleware(storeElements.history),
rdx.history = rdx.createHistory();

rdx.sagaMiddleware = rdx.createSagaMiddleware();
rdx.middleware = [
rdx.sagaMiddleware,
rdx.routerMiddleware(rdx.history),
];

if (process.env.NODE_ENV === 'development') {
const { devToolsExtension } = window;
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension());
rdx.enhancers.push(devToolsExtension());
}
}

const composedEnhancers = compose(
applyMiddleware(...middleware),
...enhancers,
rdx.appliedMiddleware = rdx.applyMiddleware(...rdx.middleware);
rdx.composedEnhancers = rdx.compose(
rdx.appliedMiddleware,
...rdx.enhancers,
);

storeElements.store = createStore(
rootReducer(),
initialState,
composedEnhancers,
rdx.store = rdx.createStore(
rdx.rootReducer(),
rdx.initialState,
rdx.composedEnhancers,
);

sagaMiddleware.run(rootSaga);
rdx.sagaMiddleware.run(rdx.rootSaga);
}
rdx.configureStore = configureStore;

export function getStore() {
if(!storeElements.store) {
configureStore();
if (!rdx.store) {
rdx.configureStore();
}
return storeElements.store;
return rdx.store;
}
rdx.getStore = getStore;

export function getHistory() {
return storeElements.history;
return rdx.history;
}
rdx.getHistory = getHistory;
98 changes: 77 additions & 21 deletions src/templates/store.test
Original file line number Diff line number Diff line change
@@ -1,30 +1,86 @@
import React from 'react';
import ReactDOM from 'react-dom';
import config from '../config';
import configureStore, { getStore } from '../store';
import { rdx, getStore, getHistory } from '../store';

// yarn test ./src/__tests__/store.test.js --coverage
describe('getStore', () => {
it('returns store', () => {
configureStore();
const store = getStore();
expect(typeof store.dispatch).toEqual('function');
expect(typeof store.subscribe).toEqual('function');
expect(typeof store.getState).toEqual('function');
it('creates store', () => {
rdx.configureStore();
rdx.getStore();
expect(typeof rdx.store.dispatch).toEqual('function');
expect(typeof rdx.store.subscribe).toEqual('function');
expect(typeof rdx.store.getState).toEqual('function');
});

it('adds devToolsExtension to enhanchers if NODE_ENV is development', () => {
// process.env.NODE_ENV = 'development';
// Object.defineProperty(window, 'devToolsExtension', {
// writable: true,
// value: jest.fn(),
// });
// configureStore();
// const devToolsExtension = jest.fn()
// window.devToolsExtension = devToolsExtension;
// getStore();

// expect(window.devToolsExtension).toHaveBeenCalled();
// process.env.NODE_ENV = env;
it('calls all required methods to create store in "development" environment', () => {
const prevEnv = process.env.NODE_ENV;
process.env.NODE_ENV = 'development';
Object.defineProperty(window, 'devToolsExtension', {
writable: true,
value: jest.fn(),
});
const historyMock = 'history';
rdx.createHistory = jest.fn().mockReturnValue(historyMock);
rdx.createSagaMiddleware = jest.fn().mockReturnValue({ run: jest.fn() });
rdx.routerMiddleware = jest.fn();
rdx.applyMiddleware = jest.fn();
rdx.compose = jest.fn();
rdx.createStore = jest.fn();
rdx.rootReducer = jest.fn();
rdx.rootSaga = jest.fn();

rdx.configureStore();
expect(rdx.createHistory).toHaveBeenCalled();
expect(rdx.history).toEqual(historyMock);
expect(rdx.createSagaMiddleware).toHaveBeenCalled();
expect(rdx.routerMiddleware).toHaveBeenCalled();

expect(window.devToolsExtension).toHaveBeenCalled();

expect(rdx.applyMiddleware).toHaveBeenCalled();
expect(rdx.compose).toHaveBeenCalled();
expect(rdx.createStore).toHaveBeenCalled();
expect(rdx.sagaMiddleware.run).toHaveBeenCalled();
process.env.NODE_ENV = prevEnv;
});

it('does not add devToolsExtension if it is not function', () => {
const prevEnv = process.env.NODE_ENV;
process.env.NODE_ENV = 'development';
Object.defineProperty(window, 'devToolsExtension', {
writable: true,
value: 'foo',
});
const historyMock = 'history';
rdx.createHistory = jest.fn().mockReturnValue(historyMock);
rdx.createSagaMiddleware = jest.fn().mockReturnValue({ run: jest.fn() });
rdx.routerMiddleware = jest.fn();
rdx.applyMiddleware = jest.fn();
rdx.compose = jest.fn();
rdx.createStore = jest.fn();
rdx.rootReducer = jest.fn();
rdx.rootSaga = jest.fn();
rdx.enhancers.push = jest.fn();
rdx.configureStore();
expect(rdx.enhancers.push).not.toHaveBeenCalled();
process.env.NODE_ENV = prevEnv;
});

it('creates store if getStore being called and no store exists', () => {
rdx.configureStore = jest.fn();
getStore();
expect(rdx.configureStore).toHaveBeenCalled();
});

it('does not create store if getStore being called and store exists', () => {
rdx.store = 'foo';
rdx.configureStore = jest.fn();
getStore();
expect(rdx.configureStore).not.toHaveBeenCalled();
});

it('returns history if getHistory is called', () => {
rdx.history = 'foo';
expect(getHistory()).toEqual(rdx.history);
});
});