diff --git a/.eslintrc b/.eslintrc index 2789917..244dd24 100644 --- a/.eslintrc +++ b/.eslintrc @@ -30,7 +30,7 @@ "env": { "browser": true, "es6": true, - "mocha": true, + "jest": true, "node": true }, "globals": { diff --git a/README.md b/README.md index a83e7e9..92e4bae 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ boilerplate comes with: - CSS, SASS and [css-modules](https://github.com/css-modules/css-modules) support with hot reloading and no [flash of unstyled content](https://en.wikipedia.org/wiki/Flash_of_unstyled_content) ([css-hot-loader](https://github.com/shepherdwind/css-hot-loader)) - Routing with [react-router-v4](https://github.com/ReactTraining/react-router) - Full production builds that do not rely on `babel-node`. +- Pre-configured testing tools with `jest` and `enzyme` to work with css modules, static files, and aliased module paths. ## Philosophy @@ -71,6 +72,30 @@ If using Heroku, simply add a `Procfile` in the root directory. The web: npm run serve ``` +## Path Aliases + +In `package.json`, there is a property named `_moduleAliases`. This object +defines the require() aliases used by both webpack and node. + +Aliased paths are prefixed with one of two symbols, which denote different +things: + +`@` - paths in the `common/` folder, e.g. `@components` or `@actions`, etc. +`$` - paths in the `server/` folder + +Aliases are nice to use for convenience, and lets us avoid using relative paths +in our components: + +``` +// This sucks +import SomeComponent from '../../../components/SomeComponent'; + +// This is way better +import SomeComponent from '@components/SomeComponent'; +``` + +You can add additional aliases in `package.json` to your own liking. + ## Environment Variables In development mode, environment variables are loaded by `dotenv` off the `.env` @@ -160,20 +185,19 @@ higher. If you experience errors, please upgrade your version of Node.js. ## Testing -The default testing framework is Mocha, though you can use whatever you want. -Make sure you have it installed: +The default testing framework is Jest, though you can use whatever you want. -``` -npm install -g mocha -``` - -Tests should reside in `test/spec` in their appropriate folders: +Tests and their corresponding files such as Jest snapshots, should be co-located +alongside the modules they are testing, in a `spec/` folder. For example: ``` -├── test -│   ├── spec -│   │   ├── api -│   │   │   ├── todos.test.js +├── components +│   ├── todos +│   │   ├── TodoForm +│   │   │   ├── spec +│   │   │   │   ├── TodoForm.test.js +│   │   │   ├── index.js +│   │   │   ├── index.scss ``` Tests can be written with ES2015, since it passes through `babel-register`. @@ -184,21 +208,19 @@ To run a single test: ``` npm test /path/to/single.test.js -``` -To run a directory of tests: - -``` -npm test /path/to/test/directory +// Or, to watch for changes +npm run test:watch /path/to/single.test.js ``` To run all tests: ``` npm run test:all -``` -This will run all tests in the `test/spec` directory. +// Or, to watch for changes +npm run test:all:watch +``` ## Running ESLint diff --git a/client/index.js b/client/index.js index 55d505d..2d9268b 100644 --- a/client/index.js +++ b/client/index.js @@ -5,8 +5,8 @@ import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import { ConnectedRouter } from 'react-router-redux'; import createHistory from 'history/createBrowserHistory'; -import configureStore from 'store'; -import App from 'containers/App'; +import configureStore from '@store'; +import App from '@containers/App'; import Loadable from 'react-loadable'; // Hydrate the redux store from server state. diff --git a/client/styles.js b/client/styles.js index ebc7e86..4d7f06f 100644 --- a/client/styles.js +++ b/client/styles.js @@ -2,4 +2,4 @@ import 'semantic-ui-css/semantic.min.css'; // Base styles -import 'css/base/index.scss'; +import '@css/base/index.scss'; diff --git a/common/js/actions/todos.js b/common/js/actions/todos.js index a44565a..c10277a 100644 --- a/common/js/actions/todos.js +++ b/common/js/actions/todos.js @@ -5,9 +5,9 @@ import { FETCH_TODOS_REQUEST, FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE -} from 'constants/index'; -import api from 'lib/api'; -import generateActionCreator from 'lib/generateActionCreator'; +} from '@constants/index'; +import api from '@lib/api'; +import generateActionCreator from '@lib/generateActionCreator'; export const addTodo = generateActionCreator(ADD_TODO, 'text'); export const removeTodo = generateActionCreator(REMOVE_TODO, 'id'); diff --git a/common/js/components/todos/TodoForm/spec/TodoForm.test.js b/common/js/components/todos/TodoForm/spec/TodoForm.test.js new file mode 100644 index 0000000..eae389f --- /dev/null +++ b/common/js/components/todos/TodoForm/spec/TodoForm.test.js @@ -0,0 +1,23 @@ +import React from 'react'; +import TodoForm from '../index'; +import { mount } from 'enzyme'; + +describe('TodoForm', () => { + it('renders correctly', () => { + const component = mount(); + expect(component).toMatchSnapshot(); + }); + + describe('clicking on submit button', () => { + test('calls the onSubmit prop', () => { + const mockSubmit = jest.fn(); + const component = mount(); + + // test form submission + component.setState({ todoText: 'Foobar' }); + component.find('form').simulate('submit'); + + expect(mockSubmit.mock.calls.length).toEqual(1); + }); + }); +}); diff --git a/common/js/components/todos/TodoForm/spec/__snapshots__/TodoForm.test.js.snap b/common/js/components/todos/TodoForm/spec/__snapshots__/TodoForm.test.js.snap new file mode 100644 index 0000000..877d9f0 --- /dev/null +++ b/common/js/components/todos/TodoForm/spec/__snapshots__/TodoForm.test.js.snap @@ -0,0 +1,102 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TodoForm renders correctly 1`] = ` + +
+ + +
+ + +
+ +
+ +
+ +
+
+
+ + +
+