{"id":13727210,"url":"https://github.com/keiya01/react-performance-testing","last_synced_at":"2025-04-04T19:13:00.608Z","repository":{"id":38779700,"uuid":"285998667","full_name":"keiya01/react-performance-testing","owner":"keiya01","description":"A library to test runtime performance in React","archived":false,"fork":false,"pushed_at":"2021-08-15T12:06:50.000Z","size":1261,"stargazers_count":291,"open_issues_count":7,"forks_count":10,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-28T18:17:43.236Z","etag":null,"topics":["javascript","react-hooks","react-native","reactjs","testing","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/keiya01.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-08-08T07:49:30.000Z","updated_at":"2024-10-16T11:55:34.000Z","dependencies_parsed_at":"2022-07-14T03:30:37.145Z","dependency_job_id":null,"html_url":"https://github.com/keiya01/react-performance-testing","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keiya01%2Freact-performance-testing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keiya01%2Freact-performance-testing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keiya01%2Freact-performance-testing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keiya01%2Freact-performance-testing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/keiya01","download_url":"https://codeload.github.com/keiya01/react-performance-testing/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246970295,"owners_count":20862508,"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":["javascript","react-hooks","react-native","reactjs","testing","typescript"],"created_at":"2024-08-03T01:03:44.269Z","updated_at":"2025-04-04T19:13:00.576Z","avatar_url":"https://github.com/keiya01.png","language":"TypeScript","readme":"# react-performance-testing\n\n![npm](https://img.shields.io/npm/v/react-performance-testing)\n[![codecov](https://codecov.io/gh/keiya01/react-performance-testing/branch/master/graph/badge.svg)](https://codecov.io/gh/keiya01/react-performance-testing)\n![GitHub Workflow Status](https://github.com/keiya01/react-performance-testing/workflows/test/badge.svg)\n![GitHub Workflow Status](https://github.com/keiya01/react-performance-testing/workflows/build/badge.svg)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nThis library is perfect for testing React or ReactNative runtime performance. `react-performance-testing` counts **the number of renders** and the **render time** in a test environment.\n\n## Table of Contents\n\n- [The problem](#the-problem)\n- [The solution](#the-solution)\n- [Installation](#installation)\n- [Example](#example)\n  - [count renders](#count-renders)\n  - [measure render time](#measure-render-time)\n- [API](#api)\n  - [perf](#perf)\n    - [renderCount](#renderCount)\n    - [renderTime](#renderTime)\n  - [wait](#wait)\n  - [cleanup](#cleanup)\n  - [ReactNative](#reactnative)\n  - [TypeScript](#typescript)\n- [Tips](#tips)\n  - [Performance](#performance)\n  - [Anonymous Component](#anonymous-component)\n  - [Hooks](#hooks)\n- [LICENSE](#license)\n\n## The problem\n\nIf you need to develop high-performance features, you need to count renders and render time. Normally you would have to go through the arduous process of manually checking dev-tools or Lighthouse. With `react-performance-testing` you can automate this process, saving you time and ensuring you always have one eye on performance.\n\n## The solution\n\n`react-performance-testing` monkey patches `React` to provide you with an API that can count the number of renders and measure render time.\n\n## Installation\n\nnpm:\n\n```sh\nnpm install --save-dev react-performance-testing\n```\n\nyarn:\n\n```sh\nyarn add --dev react-performance-testing\n```\n\nUse [jest-performance-testing](https://github.com/keiya01/react-performance-testing/tree/master/packages/jest-performance-testing) for a great testing experience.\n\nAdditionally, you can use [performance-testing-cli](https://github.com/keiya01/react-performance-testing/tree/master/packages/performance-testing-cli) if you use `renderTime`. If you use this library, you can execute test for each files. Therefore you will not need to test one by one.\n\nIf you want to use `jsx-runtime` in React@17.x, you need to modify `tsconfig.json` like the following.\n\n```json\n\"compilerOptions\": {\n  \"jsx\": \"react-jsxdev\",\n  \"jsxImportSource\": \"react-performance-testing\"\n}\n```\n\n## Example\n\n### count renders\n\n```jsx\ntest('should have two renders when state is updated', async () =\u003e {\n  const Counter = () =\u003e {\n    const [count, setCount] = React.useState(0);\n    return (\n      \u003cdiv\u003e\n        \u003cp\u003e{count}\u003c/p\u003e\n        \u003cbutton type=\"button\" onClick={() =\u003e setCount((c) =\u003e c + 1)}\u003e\n          count\n        \u003c/button\u003e\n      \u003c/div\u003e\n    );\n  };\n  const Component = () =\u003e {\n    return \u003cCounter /\u003e;\n  };\n\n  const { renderCount } = perf(React);\n\n  render(\u003cComponent /\u003e);\n\n  fireEvent.click(screen.getByRole('button', { name: /count/i }));\n\n  await wait(() =\u003e expect(renderCount.current.Counter.value).toBe(2));\n});\n\ntest('should have two renders when state is updated with multiple of the same component', async () =\u003e {\n  const Counter = ({ testid }) =\u003e {\n    const [count, setCount] = React.useState(0);\n    return (\n      \u003cdiv\u003e\n        \u003cp\u003e{count}\u003c/p\u003e\n        \u003cbutton\n          data-testid={testid}\n          type=\"button\"\n          onClick={() =\u003e setCount((c) =\u003e c + 1)}\n        \u003e\n          count\n        \u003c/button\u003e\n      \u003c/div\u003e\n    );\n  };\n  const Component = () =\u003e {\n    return (\n      \u003cdiv\u003e\n        \u003cCounter /\u003e\n        \u003cCounter testid=\"button\" /\u003e\n        \u003cCounter /\u003e\n      \u003c/div\u003e\n    );\n  };\n\n  const { renderCount } = perf(React);\n\n  render(\u003cComponent /\u003e);\n\n  fireEvent.click(screen.getByTestId('button'));\n\n  await wait(() =\u003e {\n    expect(renderCount.current.Counter[0].value).toBe(1);\n    expect(renderCount.current.Counter[1].value).toBe(2);\n    expect(renderCount.current.Counter[2].value).toBe(1);\n  });\n});\n```\n\n### measure render time\n\nIf you want to use `renderTime`, please check out the docs: [renderTime](#renderTime).\n\n```jsx\ntest('render time should be less than 16ms', async () =\u003e {\n  const Counter = () =\u003e {\n    const [count, setCount] = React.useState(0);\n    return (\n      \u003cdiv\u003e\n        \u003cp\u003e{count}\u003c/p\u003e\n        \u003cbutton type=\"button\" onClick={() =\u003e setCount((c) =\u003e c + 1)}\u003e\n          count\n        \u003c/button\u003e\n      \u003c/div\u003e\n    );\n  };\n\n  const { renderTime } = perf(React);\n\n  render(\u003cCounter /\u003e);\n\n  fireEvent.click(screen.getByRole('button', { name: /count/i }));\n\n  await wait(() =\u003e {\n    // 16ms is meaning it is 60fps\n    expect(renderTime.current.Counter.mount).toBeLessThan(16);\n    // renderTime.current.Counter.updates[0] is second render\n    expect(renderTime.current.Counter.updates[0]).toBeLessThan(16);\n  });\n});\n\ntest('should measure re-render time when state is updated with multiple of the same component', async () =\u003e {\n  const Counter = ({ testid }) =\u003e {\n    const [count, setCount] = React.useState(0);\n    return (\n      \u003cdiv\u003e\n        \u003cp\u003e{count}\u003c/p\u003e\n        \u003cbutton\n          data-testid={testid}\n          type=\"button\"\n          onClick={() =\u003e setCount((c) =\u003e c + 1)}\n        \u003e\n          count\n        \u003c/button\u003e\n      \u003c/div\u003e\n    );\n  };\n  const Component = () =\u003e {\n    return (\n      \u003cdiv\u003e\n        \u003cCounter /\u003e\n        \u003cCounter testid=\"button\" /\u003e\n        \u003cCounter /\u003e\n      \u003c/div\u003e\n    );\n  };\n\n  const { renderTime } = perf(React);\n\n  render(\u003cComponent /\u003e);\n\n  fireEvent.click(screen.getByTestId('button'));\n\n  await wait(() =\u003e {\n    expect(renderTime.current.Counter[0].updates).toHaveLength(0);\n    expect(renderTime.current.Counter[1].updates[0]).toBeLessThan(16);\n    expect(renderTime.current.Counter[2].updates).toHaveLength(0);\n  });\n});\n```\n\n## API\n\nIf you use the API with a large component, the component's performance could be affected because we monkey patch React.\nTherefore, if you want to measure accurately, you should use the API with **components that have one feature** like `List`, `Modal` etc.\n\n### perf\n\n`perf` method observes your component. So you can get the `renderCount` to count the number of renders and `renderTime` to measure render time.\n\n```js\nconst { renderCount, renderTime } = perf(React);\n```\n\nNote that You need to invoke the `perf` method before the `render` method is invoked. Additionally, You need to pass `React` to the `perf` method because we are monkey patching `React`.\n\n**Note**: If you are using `jsx-runtime` in React@17.x, you don't need to pass `React` for monkey patching.\n\n**Note**: You need to wrap the returned value with [wait](#wait) method.\n\n#### renderCount\n\n`renderCount` will count the number of renders.\n\n```jsx\nconst Component = () =\u003e \u003cp\u003etest\u003c/p\u003e;\nconst { renderCount } = perf(React);\n// render is imported from react-testing-library\nrender(\u003cComponent /\u003e);\nwait(() =\u003e console.log(renderCount.current.Component.value)); // output: 1\n```\n\n**Note**: You need to set a display name. If you have an anonymous component, we can not set the `renderCount` property correctly.\n\n##### Properties\n\n- `renderCount.current`\n  - `ComponentName: string | Array`\n    - `value: number`\n\n**Note**: If you have the same component, these components combine into an `array`\n\n#### renderTime\n\n`renderTime` will count the time elapsed between renders.\n\n```jsx\nconst Component = () =\u003e \u003cp\u003etest\u003c/p\u003e;\nconst { renderTime } = perf(React);\n// render is imported from react-testing-library\nrender(\u003cComponent /\u003e);\nwait(() =\u003e {\n  console.log(renderTime.current.Component.mount); // output: ...ms\n  console.log(renderTime.current.Component.updates); // output: []\n});\n```\n\n**Note**: If you want to measure render time, you need to test renders **one by one**. V8 has a feature called [inline caching](https://blog.sessionstack.com/how-javascript-works-inside-the-v8-engine-5-tips-on-how-to-write-optimized-code-ac089e62b12e), so if you measure just the result there will be a **large difference**. Therefore You need to execute tests **one by one** like `jest --testNamePattern=...` or `jest src/something.test.js`.\n\n**Note**: You need to set a display name. If you have an anonymous component, we can not set a property to `renderTime` correctly.\n\n##### Properties\n\n- `renderCount.current`\n  - `ComponentName: string | Array`\n    - `mount: number` ... This property has the initial render time.\n    - `updates: Array\u003cnumber\u003e` ... This property has the second and the subsequent render time (the second render is the index of `0`)\n\n**Note**: If you have the duplicate components, these components combine into `array`  \n**Note**: time is measured in `ms`, milliseconds elapsed.\n\n### wait\n\nThe `wait` method is a feature that waits for `renderCount` or `renderTime` to be assigned. We need to wrap all returned values from `perf()` because we are assigning `renderCount` and `renderTime` asynchronous. If we were to assign some value to `renderCount` or `renderTime` synchronous, extra processing would be included in the rendering phase.\n\n```js\nwait(() =\u003e console.log(renderTime.current.Component));\n```\n\n### cleanup\n\nThe `cleanup` method is executed automatically in `afterEach()` if you are using `Jest`, `Mocha`, and `Jasmine`. You need to clean up your component by using `cleanup`.\nIf your testing library has `afterEach()`, you need to invoke `cleanup()` manually.\n\n### ReactNative\n\nIf you are using ReactNative, you need to import modules from `react-performance-testing/native`.\n\n```js\nimport { perf } from 'react-performance-testing/native';\n```\n\n### TypeScript\n\nIf you are using Typescript, you can get benefits from type inference as seen below.\n\n```tsx\nconst Text = (): React.ReactElement =\u003e \u003cp\u003etest\u003c/p\u003e;\nconst Component = (): React.ReactElement =\u003e (\n  \u003cdiv\u003e\n    \u003cText /\u003e\n    \u003cText /\u003e\n  \u003c/div\u003e\n);\n\n// If you didn't pass your type to the type argument\nconst { renderCount, renderTime } = perf(React);\nrenderCount.current // Editor will suggest `Text | Text[]` and `Component | Component[]`\n\n// If you passed your type to the type argument\nconst { renderCount, renderTime } = perf \u003c{ Text: unknown[], Component: unknown }\u003e React;\nrenderCount.current // Editor will suggest `Text[]` and `Component`\n```\n\nYou can pass the `{ComponentName: unknown or unknown[]}` type for the type argument. If you passed to the type argument, then the editor will suggest the correct type dependent on the passed type.\n\n**Note**: If you are using `ts-jest`, you need to combine it with `babel`. You can check the way to set up config [here](https://github.com/keiya01/react-performance-testing/tree/master/example). This is because, `TypeScript` compiler can not compile named arrow functions correctly. You can read up on the issue here: https://github.com/microsoft/TypeScript/issues/6433.\n\n## Tips\n\n### Performance\n\nThis library is using the `Proxy` API to optimize testing speed. So you should use either `renderCount` or `renderTime` in a single test case. If you use both variables or you are testing a large component, the testing time will be a little slower.\n\n### Anonymous Component\n\nIf you are using an anonymous component, this library doesn't work correctly. To make this library work correctly, you need to set the display name as seen below.\n\n```js\nReact.memo(function MemoComponent() {\n  return \u003cp\u003etest\u003c/p\u003e;\n});\n\n// or\n\nconst MemoComponent = () =\u003e \u003cp\u003etest\u003c/p\u003e;\nReact.memo(MemoComponent);\n```\n\nSetting a display name will get benefits not only from this library but also when [you debug in React](https://reactjs.org/docs/react-component.html#displayname).\n\n### Hooks\n\nIf you are using `@testing-library/react-hooks`, you can check the number of renders with the `perf` method as bellows.\n\n```js\nconst { renderCount } = perf(React);\nconst { result } = renderHook(() =\u003e {\n  /**\n   * use some hooks\n   */\n});\n\n// You can get value from the TestHook component\nwait(() =\u003e console.log(renderCount.current.TestHook.value));\n```\n\nThis is because the `renderHook` method is wrapping callbacks with the `TestHook` component.\n\n## LICENSE\n\n[MIT](LICENSE)\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkeiya01%2Freact-performance-testing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkeiya01%2Freact-performance-testing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkeiya01%2Freact-performance-testing/lists"}