{"id":18064812,"url":"https://github.com/franciscop/react-test","last_synced_at":"2025-04-09T15:04:22.078Z","repository":{"id":38208493,"uuid":"231590500","full_name":"franciscop/react-test","owner":"franciscop","description":"🧯 Make readable assertions for your App and be confident about the code you ship. Reduce user-facing bugs and increase satisfaction.","archived":false,"fork":false,"pushed_at":"2025-03-02T18:28:45.000Z","size":3318,"stargazers_count":23,"open_issues_count":1,"forks_count":13,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-09T15:03:36.228Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://react-test.dev","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/franciscop.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"Contributing.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":"https://www.paypal.me/franciscopresencia/19"}},"created_at":"2020-01-03T13:04:03.000Z","updated_at":"2025-03-02T18:28:48.000Z","dependencies_parsed_at":"2024-12-31T23:07:14.865Z","dependency_job_id":"ff883839-7f76-4232-b14a-03003a2e47b8","html_url":"https://github.com/franciscop/react-test","commit_stats":{"total_commits":255,"total_committers":8,"mean_commits":31.875,"dds":"0.11764705882352944","last_synced_commit":"d4fd42bbda471623dcf5f1773cae4b2c9ab2fbca"},"previous_names":["franciscop/react-query-test"],"tags_count":46,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franciscop%2Freact-test","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franciscop%2Freact-test/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franciscop%2Freact-test/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franciscop%2Freact-test/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/franciscop","download_url":"https://codeload.github.com/franciscop/react-test/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248055276,"owners_count":21040156,"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-10-31T06:07:56.547Z","updated_at":"2025-04-09T15:04:22.059Z","avatar_url":"https://github.com/franciscop.png","language":"JavaScript","funding_links":["https://www.paypal.me/franciscopresencia/19"],"categories":[],"sub_categories":[],"readme":"# React Test [![npm install react-test](https://img.shields.io/badge/npm%20install-react--test-blue.svg)](https://www.npmjs.com/package/react-test) [![test badge](https://github.com/franciscop/react-test/workflows/tests/badge.svg)](https://github.com/franciscop/react-test/actions) [![gzip size](https://img.badgesize.io/franciscop/react-test/master/index.js.svg?compression=gzip)](https://github.com/franciscop/react-test/blob/master/index.js)\n\nExpressive testing library for React to make sure your code works as expected:\n\n```js\nimport $ from \"react-test\";\n\nit(\"increments when clicked\", async () =\u003e {\n  const counter = $(\u003cCounter /\u003e);\n  expect(counter).toHaveText(\"0\");\n  await counter.click();\n  expect(counter).toHaveText(\"1\");\n});\n```\n\nThe `react-test` syntax follows a similar schema to jQuery so it's very easy to write expressive tests. It also adds some Jest matchers (if you are using Jest) for convenience.\n\n\u003e Early package! We are [looking for **beginner Open Source contributors**](https://github.com/franciscop/react-test/blob/master/Contributing.md)! ❤️\n\n## Getting Started\n\nFirst you'll need a working React project. As an example you can start a working React project with [Create React App](https://create-react-app.dev/):\n\n```bash\nnpx create-react-app my-app\ncd my-app\n```\n\nThen install `react-test`. It is only needed for development:\n\n```bash\nnpm install react-test --save-dev\n```\n\nFinally you can write tests. Let's say you have [the `\u003cCounter /\u003e` component from this example](/tree/master/src/examples/Counter) and you want to test it to make sure it works as expected:\n\n```js\n// src/Counter.js\nimport React, { useState } from \"react\";\n\nexport default function Counter() {\n  const [counter, setCounter] = useState(0);\n  const increment = () =\u003e setCounter(counter + 1);\n  return \u003cbutton onClick={increment}\u003e{counter}\u003c/button\u003e;\n}\n```\n\n```js\n// src/Counter.test.js\nimport React from \"react\";\nimport $ from \"react-test\";\nimport Counter from \"./Counter\";\n\ndescribe(\"Counter.js\", () =\u003e {\n  it(\"is initialized to 0\", () =\u003e {\n    const counter = $(\u003cCounter /\u003e);\n    expect(counter.text()).toBe(\"0\");\n  });\n\n  it(\"can be incremented with a click\", async () =\u003e {\n    const counter = $(\u003cCounter /\u003e);\n    await counter.click();\n    expect(counter.text()).toBe(\"1\");\n  });\n\n  it(\"can be incremented multiple times\", async () =\u003e {\n    const counter = $(\u003cCounter /\u003e);\n    await counter.click();\n    await counter.click();\n    await counter.click();\n    expect(counter.text()).toBe(\"3\");\n  });\n});\n```\n\nFinally run the tests with Jest:\n\n```bash\nnpm run test\n```\n\n### Basics of testing\n\nReact applications are divided in components, and these components can be tested either individually or in group. Self-contained components are easier to test, document and debug.\n\nFor example, a plain button can be defined with a callback function, and change colors depending on the `primary` attribute:\n\n```js\nimport React from \"react\";\n\nexport default function Button({ primary, onClick, children }) {\n  const background = primary ? \"blue\" : \"gray\";\n  return (\n    \u003cbutton onClick={onClick} style={{ background }}\u003e\n      {children}\n    \u003c/button\u003e\n  );\n}\n```\n\nThen we can test it with `react-test` by creating a `Button.test.js` file and adding some assertions:\n\n```js\nimport React from \"react\";\nimport $ from \"react-test\";\nimport Button from \"./Button\";\n\ndescribe(\"Button.js\", () =\u003e {\n  it(\"has different backgrounds depending on the props\", () =\u003e {\n    const $button = $(\u003cButton\u003eHello\u003c/Button\u003e);\n    expect($button).toHaveStyle(\"background\", \"gray\");\n    const $primary = $(\u003cButton primary\u003eHello\u003c/Button\u003e);\n    expect($primary).toHaveStyle(\"background\", \"blue\");\n  });\n\n  it(\"can be clicked\", async () =\u003e {\n    const fn = jest.fn();\n    const $button = $(\u003cButton onClick={fn}\u003eHello\u003c/Button\u003e);\n    expect(fn).not.toBeCalled();\n    await $button.click();\n    expect(fn).toBeCalled();\n  });\n\n  // FAILS\n  it(\"cannot be clicked if it's disabled\", async () =\u003e {\n    const fn = jest.fn();\n    const $button = $(\n      \u003cButton onClick={fn} disabled\u003e\n        Hello\n      \u003c/Button\u003e\n    );\n    await $button.click();\n    expect(fn).not.toBeCalled(); // ERROR!\n  });\n});\n```\n\nGreat! All of our tests are working except for the last one. Now we can go back to our component and fix it:\n\n```js\nimport React from \"react\";\n\nexport default function Button({ primary, onClick, children, ...props }) {\n  const background = primary ? \"blue\" : \"gray\";\n  return (\n    \u003cbutton onClick={onClick} style={{ background }} {...props}\u003e\n      {children}\n    \u003c/button\u003e\n  );\n}\n```\n\n### Concepts\n\n#### Matched nodes\n\nWhen we talk about \"the first element\" or \"the elements matched\" we always refer to the top-level element (unless specified differently). So in this example:\n\n```js\nconst list = $(\n  \u003cul\u003e\n    \u003cli\u003eA\u003c/li\u003e\n    \u003cli\u003eB\u003c/li\u003e\n  \u003c/ul\u003e\n);\n```\n\nThe first element, which is the same as the matched nodes, is the `ul` and **not the \u003cli\u003e**. We can always \"go down a level\" with the proper DOM navigation methods:\n\n```js\nconst list = $(...);  // The node \u003cul\u003e\nconst items = list.children();  // An array of \u003cli\u003e nodes\n```\n\nIn this case the _matched nodes_ of `list` is an array containing only the `\u003cul\u003e`, while the _matched nodes_ for `items` is an array with both of the `\u003cli\u003e`.\n\nThis is very important for many things, e.g. if you are trying to `.filter()` the `\u003cli\u003e` you need to use `items` and not `list`, same as if you want to get the first `\u003cli\u003e`'s Node:\n\n```js\nlist.get(0); // \u003cul\u003e...\u003c/ul\u003e ~\u003e The whole thing\nitems.get(0); // \u003cli\u003eA\u003c/li\u003e   ~\u003e The first item\nitems.get(1); // \u003cli\u003eB\u003c/li\u003e   ~\u003e The second item\nitems.get(-1); // \u003cli\u003eB\u003c/li\u003e   ~\u003e The last item\n```\n\n### FAQ\n\n#### Is this an official Facebook/React library?\n\nNo. This follows the community convention of calling a library related to React as `react-NAME`. It is made [by these contributors](https://github.com/franciscop/react-test/graphs/contributors) without any involvement of Facebook or [React](https://reactjs.org/).\n\n#### How can I contribute?\n\nThanks! Please read the [Contributing Guide](./Contributing.md) where we explain how to get started with the project. Right now there are [some beginner-friendly issues](https://github.com/franciscop/react-test/labels/good%20first%20issue) so please feel free to implement those!\n\nI will try to help as much as possible on the PRs.\n\n#### I have a problem, how do I fix it?\n\nDon't sweat it, [just open an issue](https://github.com/franciscop/react-test/issues/new). React Test is in an early phase with incomplete documentation so feel free to read the code or ask directly in the issues.\n\nThis will change once the library is more stable, there's more documentation and if the community grows (maybe a chat, or reddit group, or ...).\n\n#### How did you get `react-test`?\n\nI've [written a blog post about this](https://medium.com/server-for-node-js/getting-a-great-npm-name-b0b2b27a0e1b), but the gist of it is that the npm package was taken [by Deepstream.io](https://deepstream.io/) before but not used. So I asked politely and they allowed me to use it.\n\n#### How is this different from [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)?\n\nThis is a difficult one. First, React Testing Library, the documentation and the work from [@kentcdodds](https://github.com/kentcdodds) and other collaborators is amazing and I've learned a lot from it. The main differences are:\n\nThe syntax follows jQuery-style chaining:\n\n```js\n// react-test\nimport $ from \"react-test\";\ntest(\"Increments when clicked\", async () =\u003e {\n  const $counter = $(\u003cCounter /\u003e);\n  expect($counter).toHaveText(\"0\");\n  await $counter.click();\n  expect($counter).toHaveText(\"1\");\n});\n\n// react testing library\nimport { render, fireEvent } from \"@testing-library/react\";\ntest(\"Increments when clicked\", () =\u003e {\n  const { getByRole, container } = render(\u003cCounter /\u003e);\n  expect(container).toHaveTextContent(\"0\");\n  fireEvent.click(getByRole(\"button\"));\n  expect(container).toHaveTextContent(\"1\");\n});\n```\n\nReact Test is a work in progress, so if you are writing tests for production right now please use one of the better known alternatives.\n\n#### jQuery syntax, ewwh\n\nThat's not really a question! But if for some reason you deeply despise those dollars, perhaps because they remind you of PHP, you can avoid them altogether:\n\n```js\nimport render from \"react-test\";\n\ntest(\"Increments when clicked\", async () =\u003e {\n  const counter = render(\u003cCounter /\u003e);\n  expect(counter).toHaveText(\"0\");\n  await counter.click();\n  expect(counter).toHaveText(\"1\");\n});\n```\n\nWe obviously love React, but let's not forget that jQuery also has some great things as well. This library brings some of these nice things to react testing.\n\n#### When will the 1.0 be ready?\n\nTo launch the version 1.0, I'd like to finish a few tasks:\n\n- Write more documentation and normalize it\n- Normalize code, specially across testing\n- Add some more event-based functionality, like extending native events (if possible).\n- Write 5 working examples in total. Counter, Signup, MovieList, CRUD and Swipe (names TBD).\n\nI don't know how long that'll take, right now I'm normalizing the code and documentation.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranciscop%2Freact-test","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffranciscop%2Freact-test","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranciscop%2Freact-test/lists"}