{"id":21890797,"url":"https://github.com/chantastic/react-testing-patterns","last_synced_at":"2025-03-22T03:11:41.838Z","repository":{"id":36318773,"uuid":"40623431","full_name":"chantastic/react-testing-patterns","owner":"chantastic","description":"Mostly reasonable patterns for testing React on Rails","archived":false,"fork":false,"pushed_at":"2015-10-14T04:10:45.000Z","size":171,"stargazers_count":34,"open_issues_count":1,"forks_count":3,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-02-02T22:28:18.343Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chantastic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-12T20:44:47.000Z","updated_at":"2020-01-28T07:31:56.000Z","dependencies_parsed_at":"2022-09-24T23:22:20.451Z","dependency_job_id":null,"html_url":"https://github.com/chantastic/react-testing-patterns","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chantastic%2Freact-testing-patterns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chantastic%2Freact-testing-patterns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chantastic%2Freact-testing-patterns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chantastic%2Freact-testing-patterns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chantastic","download_url":"https://codeload.github.com/chantastic/react-testing-patterns/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244898458,"owners_count":20528341,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-28T12:16:50.308Z","updated_at":"2025-03-22T03:11:41.813Z","avatar_url":"https://github.com/chantastic.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"React Testing Patterns\n----------------------\n\nMostly reasonable patterns for testing React on Rails\n\nTable of Contents\n=================\n\n1. [Scope](#scope)\n1. [Constraints](#constraints)\n1. [A Dirty-UMD](#a-dirty-umd)\n1. [Mocha vs Jasmine vs Jest](#mocha-vs-jasmine-vs-jest)\n1. [A Mocha Setup](#a-mocha-setup)\n1. [Assertion Libraries](#assertion-libraries)\n1. [Mock a Doc](#mock-a-doc)\n1. [A Test Boilerplate](#a-test-boilerplate)\n1. [React Shallow Rendering](#react-shallow-rendering)\n1. [Watching the File System](#watching-the-file-system)\n\nScope\n=====\n\nThis is how we write tests for [React.js](http://reactjs.org/) on [Rails](http://rubyonrails.org/). We've struggled to find the happy path. This is our ongoing attempt to carve out the most direct path to testing React components on a golden-path Rails app. Recommendations here represent a good number of failed attempts. If something seems out of place, it probably is; let us know what you've found.\n\nConstraints\n===========\n\nOur approach has the following constraints.\n\n* Scripts work in the Asset Pipeline\n* Scripts work in a JS-testing framework\n* Module unit tests should work without a DOM\n* Testing envirnoment should be flexible for app/team-specific needs\n* ES2015 syntax support\n\nA Dirty-UMD\n===========\n\nComponent definitions will need to work in `window` and as a module. This is ugly but it works.\n\n```javascript\n(function (global) {\n  \"use strict\";\n\n  let React;\n\n  if (typeof module === \"object\" \u0026\u0026 module.exports) {\n    React = require(\"react\");\n  } else {\n    React = global.React;\n  }\n\n  class MyWidget extends React.Component {\n    render () {\n      return \u003cdiv /\u003e\n    }\n  }\n\n  if (typeof module === \"object\" \u0026\u0026 module.exports) {\n    module.exports = MyWidget;\n  } else {\n    global.MyWidget = MyWidget;\n  }\n})(this);\n```\n\n*Feel free to DRY this out however feel right to you.*\n\nMocha vs Jasmine vs Jest\n========================\n\nHere's how it shook out against our particular constraints.\n\n### TL;DR\n\nIn 2015, use Mocha. That might change if these Jest issue get resolved:\n\n* Speedy ES2015 support\n* Jasmine updated to 2.x\n\n### Jest\n\n* Not as flexible as Mocha for app-specific needs\n* Ships with DOM implementation, `jsdom`\n  = locked to unsuportted `3.x` tag\n* Slow. A test suite of only 4 tests and 23 assertions took 10.7 seconds.\n  - https://github.com/facebook/jest/issues/116\n* Locked to Jasmine 1.3\n\n### Jasmine\n\n* No obvious Babel/ES2015 path\n  - https://babeljs.io/docs/setup/ has very obvious setups for the other frameworks.\n\n### Mocha\n\n* Flexible for teams\n  - Very few opinions about anything\n  - Well documented\n  - Simple to configure\n* No default DOM implementation\n* Fast. A test suite of only 4 tests and 23 assertions took 1.2 seconds.\n\n#### Other considerations\n\nJest has very nice feature for auto-mocking and running tests in parallel. But, for now, it's an order of magnitude slower than Mocha (given our constraints).\n\nA Mocha Setup\n=============\n\nInit `package.json`, if you havent done so:\n\n```bash\n$ npm init\n```\n\nInstall Mocha:\n\n```bash\n$ npm install mocha --save-dev\n```\n\nCreate the `test/` directory, if one doesn't exist:\n\n```bash\n$ mkdir `test/`\n```\n\n*mocha will automatically run tests matching `./test/*.js`. [ref](http://mochajs.org/#the-test-directory)\n\nConfigure the `npm test` command:\n\n```json\n{\n  \"scripts\": {\n    \"test\": \"mocha\"\n  }\n}\n```\n\nNow you can run your local version of `mocha` via the `npm test` command.\n\nAdditionally, you can run the local version of `mocha` with flags via the `node_modules` directory:\n\n```bash\n$ node_modules/.bin/mocha --watch --compilers js:babel/register --recursive --reporter nyan\n```\n\nAdd a `test/mocha.opts` for shared options:\n\n```bash\n--watch\n--compilers js:babel/register\n--recursive\n--reporter nyan\n```\n\n*This configuration will be used in both `npm test` and `node_modules/.bin/mocha`*\n\nAssertion Libraries\n===================\n\nPeople like what they like.\n\nMy $.02. If you don't have a PM that pretends to read specs, write assertions. Just sayin'.\n\n### node/assert\n\n```bash\n$ # you already have node/assert. lucky you\n```\n\n```js\nimport assert from \"assert\";\n\nassert(result.type, \"div\");\n```\n\n[API](https://nodejs.org/api/assert.html)\n\n### expect.js\n\n```bash\n$ npm install expect.js --save-dev\n```\n\n```js\nimport expect from \"expect.js\";\n\nexpect(result.type).to.be(\"div\");\n```\n\n[API](https://github.com/Automattic/expect.js#api)\n\n### should\n\n```bash\n$ npm install should --save-dev\n```\n\n```js\nimport expect from \"should\";\n\n(result.type).should.be.exactly(\"div\");\n```\n\n[API](http://shouldjs.github.io/)\n\n### chai\n\n```bash\n$ npm install chai --save-dev\n```\n\nChai has 3 included assertion libraries. Chose your favorite.\n\n```js\nimport chai from \"chai\";\n\nconst assert = chai.assert;\nconst expect = chai.expect;\nconst should = chai.should;\n\nassert.strictEqual(result.type, \"div\");\nexpect(result.type).should.equal(\"div\");\nresult.type.should.equal(\"div\");\n```\n\n[API](http://chaijs.com/api/)\nMock a Doc\n=============\n\nOne of the criteria is testing without a DOM. That sholud be possible using [React shallow rendering]() but [there's a bug](https://github.com/facebook/react/issues/4019).\n\nYou can bypass it by mocking `document`.\n\n```javascript\n// ./test/utils/document.js\n\nif (typeof document === 'undefined') {\n  global.document = {};\n}\n```\n\nAdd this flag to your `mocha.opts`:\n\n```bash\n--require test/utils/document.js\n```\n\nShould you want a full fledged DOM, follow [this guide](http://jaketrent.com/post/testing-react-with-jsdom/) by [Jake Trent](http://jaketrent.com/).\n\nA Test Boilerplate\n==================\n\nHere's what a standard test looks like.\n\n```js\n\"use strict\";\n\nimport assert from \"assert\";\n\nimport React, { addons } from \"react/addons\";\nimport AppIcon from \"../AppIcon.js.jsx\";\n\nlet shallowRenderer = React.addons.TestUtils.createRenderer();\n\ndescribe(\"MyWidget\", () =\u003e {\n  shallowRenderer.render(\u003cMyWidget /\u003e);\n  let result = shallowRenderer.getRenderOutput();\n\n  it(\"renders an div tag as its root element\", () =\u003e {\n    assert.strictEqual(result.type, \"div\");\n  });\n});\n```\n\nYou can required your assertion library in `mocha.opts` to avoid requiring in each test.\n\n```bash\n--require assert\n```\n\nReact Shallow Rendering\n=======================\n\nWhere reasonable, use [shallow-rendering](https://facebook.github.io/react/docs/test-utils.html#shallow-rendering). Shallow rendering does not Require a DOM.\n\nThe [ReactTestUtils-test.js](https://github.com/facebook/react/blob/7deab28347eaf206217ffee8e4475a1935b02cb8/src/test/__tests__/ReactTestUtils-test.js#L32-L174) file are the best documentation on how shallow rendering works.\n\nHere are the basics:\n\n### Create a Renderer\n\n```js\nimport { addons } from \"react/addons\";\n\nlet shallowRenderer = React.addons.TestUtils.createRenderer();\n```\n\n### Render and get Result\n\n```js\nshallowRenderer.render(\u003cMyWidget /\u003e);\nlet result = shallowRenderer.getRenderOutput();\n```\n\n### Asserting type\n\n```js\nassert.strictEqual(result.type, \"div\");\n```\n\n### Assert children\n\n```js\nassert.deepEqual(result.props.children, [\n  \u003cdiv\u003ehi!\u003c/div\u003e,\n  \u003cdiv\u003eokay, bye.\u003c/div\u003e\n]);\n```\n\n### Assert update\n\n```js\nshallowRenderer.render(\u003cInterfacesIcon name=\"\" hoverStyle={{ color: \"blue\" }} /\u003e);\nresult = shallowRenderer.getRenderOutput();\n\nassert.deepEqual(result.props.style, {});\n\nresult.props.onMouseEnter();\nlet mouseEnterResult = shallowRenderer.getRenderOutput();\n\nassert.deepEqual(mouseEnterResult.props.style, { color: \"blue\" });\n```\n\n*See [Mock a Doc](#mock-a-doc)\n\nWatching the File System\n========================\n\n`mocha --watch` [is busted](https://github.com/mochajs/mocha/pull/266). I only ran into trouble when attempting to use [sinon.js](http://sinonjs.org/).\n\nIf you use `sinon` for stubs, spies, and mocks, you're going to need a dedicated fs watcher. Unfortunately, this is much slower than `mocha --watch` but is has the benefit of, you know, working.\n\nI like [nodemon](https://github.com/remy/nodemon) for filesystem watching.\n\n### Install\n\n```bash\n$ npm install nodemon --save-dev\n```\n\n### Add Script to package.json\n\n```json\n{\n  \"scripts\": {\n    \"test:watch\": \"node_modules/.bin/nodemon -w app/assets/javascripts/interfaces/components node_modules/.bin/_mocha\"\n  }\n}\n```\n\n### nodemon.json\n\nConfiguration can be pulled out into `nodemon.json`.\n\n```json\n{\n  \"watch\": [\n    \"app/assets/javascripts/interfaces/components\",\n    \"test/assets/javascripts/interfaces/components\"\n  ]\n}\n```\n\n### Run script\n\n```bash\n$ npm run test:watch\n```\n\n*note: `npm test` is first-class npm command. All other scripts must be run with the `run` prefix.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchantastic%2Freact-testing-patterns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchantastic%2Freact-testing-patterns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchantastic%2Freact-testing-patterns/lists"}