layout: true class: center, middle, inverse
.footnote[tonypai present]
layout: false class: inverse
.babelrc
{
"stage": 0,
"env": {
"test": {
"plugins": [
"babel-plugin-rewire"
]
}
}
}
Ref: babel-plugin-rewire
test/setup.jsx
import { jsdom } from "jsdom";
global.document = jsdom("<!doctype html><html><body></body></html>");
global.window = document.defaultView;
global.navigator = global.window.navigator;
Ref: setState in shallowRender fails due to missing document
class: inverse
package.json
{
"scripts": {
"test": "NODE_ENV=test NODE_PATH=. mocha --compilers js:babel-core/register --recursive 'test/**/*.test.jsx' --require test/setup.jsx",
},
"devDependencies": {
"babel-plugin-rewire": "^0.1.22",
"deep-freeze": "0.0.1",
"expect": "^1.13.0",
"expect-jsx": "^2.1.3",
"jsdom": "^7.0.2",
"mocha": "^2.3.4",
"nock": "^3.1.1",
"react-addons-test-utils": "^0.14.3"
}
}
$ npm i babel-plugin-rewire deep-freeze expect expect-jsx jsdom mocha nock react-addons-test-utils --save-dev
layout: false .left-column[
] .right-column[ Redux Directory Structure
- Actions
User actions and async requests
- Reducers
Business logic
- Components (a.k.a Dumb|Presentational Component)
Simply render elements
- Containers (a.k.a Smart Component)
Pass state data and each handler as props to components
Ref: Definition of containers and components
.left-column[
] .right-column[
import nock from "nock";
import expect from "expect";
import thunk from "redux-thunk";
import configureStore from "redux-mock-store";
const mockStore = configureStore([ thunk ]);
describe("Action::ACTIONS", () => {
it("#ASYNC_METHOD()", done => {
// HTTP mocking
nock(`API_URL`)
.get(`/PATH`)
.reply(HTTP_CODE, MOCK_RESPONSE)
// expected result
const expectedActions = [{
type: ACTION_TYPE,
ACTION_VALUES...
}];
const store = mockStore({}, expectedActions, done);
store.dispatch(ASYNC_METHOD());
})
it("#METHOD()", () => {
const expectedActions = [{
type: ACTION_TYPE,
ACTION_VALUES...
}];
expect(
METHOD(ARGS)
).toEqual(expectedAction);
})
})
.left-column[
] .right-column[
import expect from "expect";
import deepFreeze from "deep-freeze";
describe("Reducer::REDUCERS", () => {
// default type
it("#METHOD(undefined, {})", () => {
expect(
REDUCERS.METHOD(undefined, {})
).toEqual(EXPECTED_RESULT)
})
// action type
it("#METHOD(DEFAULT_VALUE, {type: ACTION_TYPE})", () => {
// declare default value and result
const stateBefore = DEFAULT_VALUE;
const action = {
type: actions.ACTION_TYPE,
ACTION_VALUES...
};
const stateAfter = EXPECTED_RESULT;
// make data immutable
deepFreeze(stateBefore);
deepFreeze(action);
expect(
reducers.list(stateBefore, action)
).toEqual(
stateAfter
)
})
})
.left-column[
] .right-column[
import expect from "expect";
import expectJSX from 'expect-jsx';
expect.extend(expectJSX);
import TestUtils from "react-addons-test-utils";
import React from "react";
import { Link } from "react-router";
import COMPONENT from "path/to/file";
const shallowRender = component => {
const renderer = TestUtils.createRenderer();
renderer.render(component);
return renderer.getRenderOutput();
}
const shallowRenderWithProps = (props = {}) => {
return shallowRender(<COMPONENT {...props} />);
}
describe("Components::COMPONENT", () => {
let _props, _component;
const setup = props => {
_props = props;
_component = shallowRenderWithProps(_props);
}
it("#render()", () => {
setup({ PROPS_VALUE });
expect(_component).toEqualJSX(
REACT_ELEMENTS
);
})
})
.left-column[
] .right-column[
import expect from "expect";
import TestUtils from "react-addons-test-utils";
import React from "react";
import CONNECTED_CONTAINER, { CONTAINER } from "path/to/file";
const renderWithProps = (props = {}) => {
return TestUtils.renderIntoDocument(<CONTAINER {...props} />);
}
describe("Containers::CONTAINER", () => {
let _rendered;
const setup = props => {
_rendered = renderWithProps(props);
}
// replace react component with mock component
let COMPONENT;
beforeEach(() => {
COMPONENT = React.createClass({
render() {
return (<div>MOCK COMPONENT</div>)
}
});
CONNECTED_CONTAINER.__Rewire__("COMPONENT", COMPONENT);
})
__Rewire__: babel-plugin-rewire ]
.left-column[
] .right-column[
it ("#render()", () => {
// create spy for dispatch
let fakeDispatch;
setup ({
PROPS_VALUES...,
dispatch: fakeDispatch = expect.createSpy()
});
// check if container do call dispatch while componentDidMount
expect(fakeDispatch).toHaveBeenCalled();
// text node test
let TEXTNODE = TestUtils.findRenderedDOMComponentWithTag(_rendered, "TAG_NAME");
expect(TEXTNODE.textContent).toBe("Hello Redux Unit Test!");
// react component test
let RENDERED_COMPONENT = TestUtils.findRenderedComponentWithType(_rendered, COMPONENT);
expect(RENDERED_COMPONENT.PROPS_VALUE).toBe(EXPECTED_RESULT);
})
})
]