(Jest) Snapshot Testing
Snapshot Testing ?
Le soucis des tests
Mise en place
Courbe d'apprentissage
Écriture
Alternative : Snapshot Testing
Gold(en) Master Testing
Entrée fixe → [application] → Sortie fixe
Boîte noire
Gold Master
Pourquoi on en reparle aujourd'hui ?

Snapshot Testing avec React
Jest
Painless JavaScript Testing


Test d'un composant react
(react-test-render)
export default class Link extends React.Component {
...
render() {
return (
<a
className={this.state.class}
href={this.props.page || '#'}
onMouseEnter={this._onMouseEnter}
onMouseLeave={this._onMouseLeave}>
{this.props.children}
</a>
);
}
}
Composant
import renderer from 'react-test-renderer';
test('Link renders correctly', () => {
const tree = renderer.create(
<Link page="http://www.facebook.com">Facebook</Link>
).toJSON();
expect(tree).toMatchSnapshot();
});
exports[`Link renders correctly 1`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function bound _onMouseEnter]}
onMouseLeave={[Function bound _onMouseLeave]}>
Facebook
</a>
`;
Test
Snapshot

Sortie console



Github Pull Request
Life Cycle React
class Progress extends React.Component {
...
componentWillReceiveProps(nextProps) {
this.setState({
position: Progress.getProgressPosition(nextProps.value)
});
}
...
render() {
const progressStyle = {
transform: `scaleX(${this.state.position})`
};
return (
<div>
<div style={progressStyle} />
</div>
);
}
}
test('Progress Control goes from 250 to 500', () => {
const progressConfig = {
min: 0,
max: 1000,
value: 250
};
const component = renderer.create(
<Progress {...progressConfig} />
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
progressConfig.value = 500;
component.update(<Progress {...progressConfig} />);
tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
exports[`test Progress Control goes from 250 to 500 1`] = `
<div
className="test">
<div
className="test-progress"
style={
Object {
"transform": "scaleX(0.25)"
}
} />
</div>
`;
exports[`test Progress Control goes from 250 to 500 2`] = `
<div
className="test">
<div
className="test-progress"
style={
Object {
"transform": "scaleX(0.5)"
}
} />
</div>
`;
React DOM / DOM Ref
class Slider extends Progress {
...
handleDown(event) {
this.manageListeners(ReactDOM.findDOMNode(this).ownerDocument);
}
...
}
test('Slider Control renders correctly', () => {
const sliderConfig = {
min: 0,
max: 1000,
value: 250
};
const tree = renderer.create(
<Slider {...sliderConfig} />
).toJSON();
expect(tree).toMatchSnapshot();
});
Using Jest CLI v14.1.0, jasmine2, babel-jest
FAIL app/components/controls/slider/tests/Slider.test.js (0s)
Runtime Error
- Invariant Violation: ReactCompositeComponent: injectEnvironment() can only be called once.
at invariant (node_modules/fbjs/lib/invariant.js:38:15)
at Object.ReactComponentEnvironment.injection.injectEnvironment (node_modules/react/lib/ReactComponentEnvironment.js:36:60)
at Object.inject (node_modules/react/lib/ReactDefaultInjection.js:79:28)
at Object.<anonymous> (node_modules/react/lib/ReactDOM.js:28:23)
at Object.<anonymous> (node_modules/react-dom/index.js:3:18)
at Object.<anonymous> (app/components/controls/slider/Slider.jsx:2:43)
at Object.<anonymous> (app/components/controls/slider/tests/Slider.test.js:3:41)
at process._tickCallback (internal/process/next_tick.js:103:7)
1 test suite failed, 0 tests passed (0 total in 1 test suite, run time 1.62s)
jest.mock('react-dom');




Enzyme
( jsdom + enzyme-to-json )
import { mount } from 'enzyme';
import { mountToJson } from 'enzyme-to-json';
test('Slider Control renders correctly', () => {
const sliderConfig = {
min: 0,
max: 1000,
value: 250
};
const wrapper = mount(
<Slider {...sliderConfig} />
);
expect(mountToJson(wrapper)).toMatchSnapshot();
});

Snapshot Testing Redux and More
JSON et Objets
describe('Configurator', () => {
it('should get config in json format', () => {
Configurator.getJson().then((config) => {
expect(JSON.parse(config)).toMatchSnapshot();
})
});
});
Redux Reducer
describe('MY_TESTED_ACTION', () => {
it('should do something', () => {
const action = {
type: MY_TESTED_ACTION,
payload: {...}
};
expect(reducer(initialState, action)).toMatchSnapshot();
});
});
The Good, The Bad

& The Ugly
The Good
- Simple à mettre en place.
- Simple à appréhender
- Simple à écrire

The Bad
- Pas de TDD & DDD
- Manque de documentation
- Le snapshot ne suffit pas...

The Ugly
- autoMock
- -u
- ⚠️ Attention aux Review ⚠️

The Volkswagen Syndrome



(Jest) Snapshot Testing
By nafresne
(Jest) Snapshot Testing
- 828