├── .babelrc ├── .github └── FUNDING.yml ├── .gitignore ├── .prettierrc ├── .travis.yml ├── README.md ├── cypress.json ├── cypress ├── fixtures │ └── example.json ├── integration │ └── App.e2e.js ├── plugins │ └── index.js └── support │ ├── commands.js │ └── index.js ├── dist └── index.html ├── package-lock.json ├── package.json ├── src ├── App.js ├── App.spec.js └── index.js ├── test ├── dom.js └── helpers.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-react" 5 | ] 6 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: rwieruch 4 | patreon: # rwieruch 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with a single custom sponsorship URL 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "es5", 4 | "singleQuote": true, 5 | "printWidth": 70, 6 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - stable 5 | 6 | addons: 7 | apt: 8 | packages: 9 | # Ubuntu 16+ does not install this dependency by default, so we need to install it ourselves 10 | - libgconf-2-4 11 | 12 | install: 13 | - npm install 14 | 15 | script: 16 | - npm run test -- --coverage && npm run test:cypress 17 | 18 | after_script: 19 | - COVERALLS_REPO_TOKEN=$coveralls_repo_token npm run coveralls 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-testing-mocha-chai-enzyme 2 | 3 | [](https://travis-ci.org/the-road-to-learn-react/react-testing-mocha-chai-enzyme) [](https://coveralls.io/github/the-road-to-learn-react/react-testing-mocha-chai-enzyme?branch=master) [](https://slack-the-road-to-learn-react.wieruch.com/) [](https://greenkeeper.io/) 4 | 5 | A test setup for React components with Mocha, Chai and Enzyme in a [React + Webpack](https://github.com/the-road-to-learn-react/minimal-react-webpack-babel-setup) application. [Read more about it.](https://www.robinwieruch.de/react-testing-mocha-chai-enzyme-sinon/) 6 | 7 | **Optional:** 8 | 9 | - [Cypress Tutorial](https://www.robinwieruch.de/react-testing-cypress/) 10 | - [CI Tutorial](https://www.robinwieruch.de/javascript-continuous-integration/) 11 | - [Test Coverage Tutorial](https://www.robinwieruch.de/javascript-test-coverage/) 12 | 13 | **Recommended alternative: Instead of Mocha/Chai, [using Jest as test runner and assertion library](https://github.com/the-road-to-learn-react/react-testing-jest-enzyme/).** 14 | 15 | ## Features 16 | 17 | - React 18 | - Webpack 19 | - Testing 20 | - Mocha, Chai, Enzyme: Unit/Integration 21 | - Optional E2E Tests: Cypress 22 | - Optional CI: Travis CI 23 | - Optional Reporting: Coveralls.io 24 | 25 | ## Installation 26 | 27 | - `git clone git@github.com:the-road-to-learn-react/react-testing-mocha-chai-enzyme.git` 28 | - cd react-testing-mocha-chai-enzyme 29 | - npm install 30 | - npm start 31 | - visit `http://localhost:8080/` 32 | - npm test 33 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "video": false, 3 | "baseUrl": "http://localhost:8080" 4 | } -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/integration/App.e2e.js: -------------------------------------------------------------------------------- 1 | describe('App E2E', () => { 2 | it('should have a header', () => { 3 | cy.visit('/'); 4 | 5 | cy.get('h1') 6 | .should('have.text', 'My Counter'); 7 | }); 8 | 9 | it('should increment and decrement the counter', () => { 10 | cy.visit('/'); 11 | 12 | cy.get('p') 13 | .should('have.text', '0'); 14 | 15 | cy.contains('Increment').click(); 16 | cy.get('p') 17 | .should('have.text', '1'); 18 | 19 | cy.contains('Increment').click(); 20 | cy.get('p') 21 | .should('have.text', '2'); 22 | 23 | cy.contains('Decrement').click(); 24 | cy.get('p') 25 | .should('have.text', '1'); 26 | }); 27 | }); -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | module.exports = (on, config) => { 15 | // `on` is used to hook into various events Cypress emits 16 | // `config` is the resolved Cypress config 17 | } 18 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |{counter}
; 61 | 62 | export default App; 63 | -------------------------------------------------------------------------------- /src/App.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import axios from 'axios'; 3 | import App, { doIncrement, doDecrement, Counter } from './App'; 4 | 5 | describe('Local State', () => { 6 | it('should increment the counter in state', () => { 7 | const state = { counter: 0 }; 8 | const newState = doIncrement(state); 9 | 10 | expect(newState.counter).to.equal(1); 11 | }); 12 | 13 | it('should decrement the counter in state', () => { 14 | const state = { counter: 0 }; 15 | const newState = doDecrement(state); 16 | 17 | expect(newState.counter).to.equal(-1); 18 | }); 19 | }); 20 | 21 | describe('App Component', () => { 22 | const result = [3, 5, 9]; 23 | const promise = Promise.resolve(result); 24 | 25 | before(() => { 26 | sinon.stub(axios, 'get').withArgs('http://mydomain/counter').returns(promise); 27 | }); 28 | 29 | after(() => { 30 | axios.get.restore(); 31 | }); 32 | 33 | it('renders the Counter wrapper', () => { 34 | const wrapper = shallow(