├── .gitignore
├── .travis.yml
├── src
├── actions
│ └── MemberActions.js
├── stores
│ ├── MemberStore.js
│ └── __tests__
│ │ └── MemberStore-test.js
└── components
│ ├── __tests__
│ └── MemberList-test.js
│ └── MemberList.jsx
├── LICENSE
├── README.md
├── package.json
├── karma.conf.js
└── tests.webpack.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "4.1"
4 | - "4.0"
5 | - "0.12"
6 | - "0.11"
7 | - "0.10"
8 | - "iojs"
9 |
--------------------------------------------------------------------------------
/src/actions/MemberActions.js:
--------------------------------------------------------------------------------
1 | var Reflux = require('reflux');
2 |
3 | var MemberActions = Reflux.createActions([
4 | 'addMember',
5 | ]);
6 |
7 | module.exports = MemberActions;
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2 | Version 2, December 2004
3 |
4 | Copyright (C) 2015 Kenneth Chung
5 |
6 | Everyone is permitted to copy and distribute verbatim or modified
7 | copies of this license document, and changing it is allowed as long
8 | as the name is changed.
9 |
10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12 |
13 | 0. You just DO WHAT THE FUCK YOU WANT TO.
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/kentor/react-flux-testing)
2 |
3 | Sample repository of testing React and Flux (Reflux) with Karma,
4 | Jasmine, and Webpack.
5 |
6 | `npm install` then `npm test`.
7 |
8 | Note: If you haven't already started a React project, I'd recommend using [Redux](https://github.com/rackt/redux) rather than some form of Flux. Redux reducers is a lot easier to test than Flux stores, and does not need to use the technique shown in this repo.
9 |
--------------------------------------------------------------------------------
/src/stores/MemberStore.js:
--------------------------------------------------------------------------------
1 | var Immutable = require('immutable');
2 | var MemberActions = require('../actions/MemberActions');
3 | var Reflux = require('reflux');
4 |
5 | var members = Immutable.List();
6 |
7 | var MemberStore = Reflux.createStore({
8 | listenables: [
9 | MemberActions,
10 | ],
11 |
12 | members() {
13 | return members;
14 | },
15 |
16 | onAddMember(name) {
17 | members = members.push(Immutable.Map({ name }));
18 | this.triggerAsync();
19 | },
20 | });
21 |
22 | module.exports = MemberStore;
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-flux-testing",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "test": "karma start karma.conf.js"
6 | },
7 | "author": "Kenneth Chung",
8 | "dependencies": {
9 | "babel-core": "^5.8.22",
10 | "babel-loader": "^5.3.2",
11 | "core-js": "^1.1.0",
12 | "immutable": "^3.7.4",
13 | "jasmine-core": "^2.3.4",
14 | "karma": "^0.13.9",
15 | "karma-cli": "0.1.0",
16 | "karma-jasmine": "^0.3.6",
17 | "karma-phantomjs-launcher": "^0.2.1",
18 | "karma-webpack": "^1.7.0",
19 | "node-libs-browser": "^0.5.2",
20 | "phantomjs": "^1.9.18",
21 | "react": "^0.13.3",
22 | "reflux": "0.2.10",
23 | "webpack": "^1.11.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 | config.set({
3 | browsers: [
4 | 'PhantomJS',
5 | ],
6 | files: [
7 | {
8 | pattern: 'tests.webpack.js',
9 | watched: false,
10 | },
11 | ],
12 | frameworks: [
13 | 'jasmine',
14 | ],
15 | preprocessors: {
16 | 'tests.webpack.js': [
17 | 'webpack',
18 | ],
19 | },
20 | reporters: [
21 | 'dots',
22 | ],
23 | singleRun: true,
24 | webpack: {
25 | module: {
26 | loaders: [
27 | { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader' },
28 | ],
29 | },
30 | watch: true,
31 | },
32 | webpackServer: {
33 | noInfo: true,
34 | },
35 | });
36 | };
37 |
--------------------------------------------------------------------------------
/src/stores/__tests__/MemberStore-test.js:
--------------------------------------------------------------------------------
1 | describe('MemberStore', () => {
2 | var MemberActions;
3 | var MemberStore;
4 |
5 | beforeEach(() => {
6 | MemberActions = require('../../actions/MemberActions');
7 | MemberStore = require('../MemberStore');
8 |
9 | MemberActions.addMember('foo');
10 | jasmine.clock().tick();
11 | });
12 |
13 | it('can add a member', () => {
14 | var members = MemberStore.members();
15 | expect(members.toJS()).toEqual([{ name: 'foo' }]);
16 | });
17 |
18 | it('busts the require cache', () => {
19 | MemberActions.addMember('bar');
20 | jasmine.clock().tick();
21 |
22 | var members = MemberStore.members();
23 | expect(members.toJS()).toEqual([{ name: 'foo' }, { name: 'bar' }]);
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/components/__tests__/MemberList-test.js:
--------------------------------------------------------------------------------
1 | describe('MemberList', () => {
2 | var MemberList;
3 | var React = require('react');
4 | var TestUtils = require('react/lib/ReactTestUtils');
5 |
6 | beforeEach(() => {
7 | MemberList = require('../MemberList.jsx')
8 | });
9 |
10 | it('can add a new member', () => {
11 | var c = TestUtils.renderIntoDocument();
12 | var input = React.findDOMNode(c.refs.input);
13 | var submit = React.findDOMNode(c.refs.submit);
14 |
15 | expect(React.findDOMNode(c).textContent).toBe('');
16 |
17 | TestUtils.Simulate.change(input, { target: { value: 'baz' } });
18 | TestUtils.Simulate.click(submit);
19 | jasmine.clock().tick(1);
20 |
21 | expect(React.findDOMNode(c).textContent).toBe('baz');
22 | expect(input.value).toBe('');
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/src/components/MemberList.jsx:
--------------------------------------------------------------------------------
1 | var MemberActions = require('../actions/MemberActions');
2 | var MemberStore = require('../stores/MemberStore');
3 | var React = require('react/addons');
4 | var Reflux = require('reflux');
5 |
6 | var MemberList = React.createClass({
7 | mixins: [
8 | React.addons.LinkedStateMixin,
9 | Reflux.ListenerMixin,
10 | ],
11 |
12 | getInitialState() {
13 | return {
14 | members: MemberStore.members(),
15 | newMemberName: '',
16 | };
17 | },
18 |
19 | componentDidMount() {
20 | this.listenTo(MemberStore, () => {
21 | this.setState(this.getInitialState());
22 | });
23 | },
24 |
25 | addMember() {
26 | MemberActions.addMember(this.state.newMemberName);
27 | this.setState({ newMemberName: '' });
28 | },
29 |
30 | render() {
31 | return (
32 |
33 |
34 | {this.state.members.map(member => (
35 | - {member.get('name')}
36 | ))}
37 |
38 |
39 |
40 |
41 |
42 | );
43 | },
44 | });
45 |
46 | module.exports = MemberList;
47 |
--------------------------------------------------------------------------------
/tests.webpack.js:
--------------------------------------------------------------------------------
1 | var Immutable = require('immutable');
2 |
3 | /**
4 | * ES5 polyfills for PhantomJS
5 | */
6 | require('core-js/es5');
7 |
8 | /**
9 | * Create a set of webpack module ids for our project's modules, excluding
10 | * tests. This will be used to clear the module cache before each test.
11 | */
12 | var projectContext = require.context('./src', true, /^((?!__tests__).)*.jsx?$/);
13 | var projectModuleIds = Immutable.Set(
14 | projectContext.keys().map(module => (
15 | String(projectContext.resolve(module))
16 | ))
17 | );
18 |
19 | beforeEach(() => {
20 | /**
21 | * Clear the module cache before each test. Many of our modules, such as
22 | * Stores and Actions, are singletons that have state that we don't want to
23 | * carry over between tests. Clearing the cache makes `require(module)`
24 | * return a new instance of the singletons. Modules are still cached within
25 | * each test case.
26 | */
27 | var cache = require.cache;
28 | projectModuleIds.forEach(id => delete cache[id]);
29 |
30 | /**
31 | * Automatically mock the built in setTimeout and setInterval functions.
32 | */
33 | jasmine.clock().install();
34 | });
35 |
36 | afterEach(() => {
37 | jasmine.clock().uninstall();
38 | });
39 |
40 | /**
41 | * Load each test using webpack's dynamic require with contexts.
42 | */
43 | var context = require.context('./src', true, /-test\.js?$/);
44 | context.keys().forEach(context);
45 |
--------------------------------------------------------------------------------