[React Unit Testing] React unit testing demo

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!');
    });

});

 

{
  "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"
  }
}

 

posted @ 2017-04-14 22:35  Zhentiw  阅读(258)  评论(0编辑  收藏  举报