Skip to content

Instantly share code, notes, and snippets.

@busypeoples
Last active Dec 20, 2017
Embed
What would you like to do?
Testing in React: Basic Examples + Setup
{
"name": "example-karma-jasmine-webapck-test-setup",
"description": "React Test Setup with Karma/Jasmine/Webpack",
"scripts": {
"test": "karma start --single-run --browsers PhantomJS"
},
"devDependencies": {
"babel": "^6.5.2",
"babel-core": "^6.5.2",
"babel-eslint": "^5.0.0",
"babel-loader": "^6.2.3",
"babel-preset-airbnb": "^1.1.1",
"babel-preset-es2015": "^6.5.0",
"babel-preset-react": "^6.5.0",
"enzyme": "^2.0.0",
"jasmine-core": "^2.4.1",
"json-loader": "^0.5.4",
"karma": "^0.13.21",
"karma-babel-preprocessor": "^6.0.1",
"karma-jasmine": "^0.3.7",
"karma-phantomjs-launcher": "^1.0.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^1.7.0",
"lodash": "^4.5.1",
"phantomjs-prebuilt": "^2.1.4",
"react": "^0.14.7",
"react-addons-test-utils": "^0.14.7",
"react-dom": "^0.14.7",
"react-test-utils": "0.0.1",
"webpack": "^1.12.14"
}
}
{
"name": "example-mocha-jsdom-test-setup",
"description": "React Test Setup with Mocha/jsdom",
"scripts": {
"test": "mocha --require ./setup.js --compilers js:babel-core/register --recursive"
},
"devDependencies": {
"babel": "^6.5.2",
"babel-core": "^6.6.5",
"babel-loader": "^6.2.4",
"enzyme": "^2.0.0",
"expect": "^1.14.0",
"jsdom": "^8.1.0",
"mocha": "^2.4.5",
"react-addons-test-utils": "^0.14.7"
},
"dependencies": {
"react": "^0.14.7",
"react-dom": "^0.14.7"
}
}
import React from 'react'
const Release = React.createClass({
render() {
const { title, artist, outOfPrint } = this.props.release;
const className = outOfPrint? 'release outOfPrint' : 'release';
return (
<tr className={className} >
<td className="artist">{ artist }</td>
<td className="title">{ title }</td>
<td className="comment">{ outOfPrint ? <span style={{color: 'red', fontStyle: 'italic'}}>Out Of Print!</span> : null }</td>
</tr>
);
}
});
const ReleaseTable = React.createClass({
render() {
const { searchText, releases, noOutOfPrint } = this.props;
const rows = releases.filter((release) => {
return (release.title.indexOf(searchText) !== -1
|| release.artist.indexOf(searchText) !== -1)
&& !(release.outOfPrint && noOutOfPrint);
});
return (
<table className="releaseTable">
<thead>
<tr>
<th>Artist</th>
<th>Title</th>
<th>Comment</th>
</tr>
</thead>
<tbody>{rows.map(release => {
return <Release release={ release }
key={ release.title } />
})}</tbody>
</table>
);
}
});
const SearchBar = React.createClass({
updateSearch() {
this.props.onSearch(
this.refs.search.value,
this.refs.noOutOfPrint.checked
);
},
render() {
return (
<form className="searchBar">
<input
type="text"
placeholder="Search..."
value={this.props.searchText}
ref="search"
onChange={this.updateSearch}
id="searchFilter"
/>
<p>
<input
type="checkbox"
checked={this.props.noOutOfPrint}
ref="noOutOfPrint"
onChange={this.updateSearch}
id="noOutOfPrint"
/>
{' '}
Only show available releases
</p>
</form>
);
}
});
const Root = React.createClass({
getInitialState() {
return {
searchText: '',
noOutOfPrint: false
};
},
updateSearch: function (searchText, noOutOfPrint) {
this.setState({ searchText, noOutOfPrint });
},
render() {
return (
<div className="main">
<SearchBar
searchText={this.state.searchText}
inStockOnly={this.state.noOutOfPrint}
onSearch={this.updateSearch}
/>
<ReleaseTable
releases={this.props.releases}
searchText={this.state.searchText}
noOutOfPrint={this.state.noOutOfPrint}
/>
</div>
);
}
});
export {
Release,
ReleaseTable,
SearchBar
};
export default Root;
import React from 'react'
import { shallow, mount, render } from 'enzyme'
import Root, { SearchBar, ReleaseTable, Release } from '../src/Root'
const createShallowRelease = (outOfPrint = true) => {
let props = {release: { artist: 'foobar', title: 'bar', outOfPrint }};
return shallow(<Release {...props} />);
};
const createShallowRelaseTable = (noOutOfPrint = false, searchText = '') => {
let items = [{ artist: 'foobar', title: 'bar', outOfPrint: true }];
let props = { searchText, releases: items, noOutOfPrint };
return shallow(<ReleaseTable { ...props } />);
}
describe('<SearchBar>', () => {
let onSearch;
beforeEach(() => {
onSearch = jasmine.createSpy('onSearch');
});
it('calls onSearch when search text changes', () => {
let props = { searchText: '', noOutOfPrint: false, onSearch };
let search = mount(<SearchBar { ...props } />);
let input = search.find('#searchFilter');
input.get(0).value = 'foobar';
input.simulate('change');
expect(onSearch).toHaveBeenCalledWith('foobar', false);
});
it('calls onSearch when no out print is checked', () => {
let props = { searchText: '', noOutOfPrint: false, onSearch };
let search = mount(<SearchBar { ...props } />);
let input = search.find('#noOutOfPrint');
input.get(0).checked = true;
input.simulate('change', {target: { checked: true }});
expect(onSearch).toHaveBeenCalledWith('', true);
});
});
describe('<ReleaseTable>', () => {
it('contains the class name releaseTable', () => {
let release = createShallowRelaseTable();
expect(release.is('.releaseTable')).toBeTruthy();
});
it('renders release item', () => {
let release = createShallowRelaseTable();
expect(release.find(Release).length).toBe(1);
});
it('filters out any out of print items', () => {
let release = createShallowRelaseTable(true, '');
expect(release.find(Release).length).toBe(0);
});
it('filters out any out of items when filtering by search text', () => {
let release = createShallowRelaseTable(false, 'bla');
expect(release.find(Release).length).toBe(0);
});
});
describe('<Release>', () => {
it('contains the class name release', () => {
let release = createShallowRelease();
expect(release.is('.release')).toBeTruthy();
});
it ('contains the class name outOfPrint if out of print', () => {
let release = createShallowRelease(true);
expect(release.is('.outOfPrint')).toBeTruthy();
});
it ('does not contain the class name outOfPrint if available', () => {
let release = createShallowRelease(false);
expect(release.is('.outOfPrint')).toBeFalsy();
});
it ('renders the artist name', () => {
let release = createShallowRelease();
expect(release.find('.artist').text()).toEqual('foobar');
});
it ('renders the release title', () => {
let release = createShallowRelease();
expect(release.find('.title').text()).toEqual('bar');
});
it ('renders the correct comment', () => {
let release = createShallowRelease(true);
expect(release.find('.comment').text()).toEqual('Out Of Print!');
});
});
// needed when choosing the mocha/jsdom setup
var jsdom = require('jsdom')
global.document = jsdom.jsdom('<!doctype html><html><body></body></html>')
global.window = document.defaultView;
global.navigator = {userAgent: 'node.js'};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment