Need help with react-performance-testing?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

keiya01
127 Stars 5 Forks MIT License 218 Commits 3 Opened issues

Description

A library to test runtime performance in React

Services available

!
?

Need anything else?

Contributors list

# 16,553
React N...
form-va...
TypeScr...
React
206 commits
# 507,290
JavaScr...
TypeScr...
React N...
react-h...
1 commit
# 16,808
Shell
TypeScr...
React N...
form-va...
1 commit
# 15,039
applesc...
React
ecmascr...
ecmascr...
1 commit
# 62,931
React N...
form-va...
TypeScr...
React
1 commit

react-performance-testing

npm codecov GitHub Workflow Status GitHub Workflow Status License: MIT

This 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.

Table of Contents

The problem

If 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.

The solution

react-performance-testing
monkey patches
React
to provide you with an API that can count the number of renders and measure render time.

Installation

npm:

npm install --save-dev react-performance-testing

yarn:

yarn add --dev react-performance-testing

Use jest-performance-testing for a great testing experience.

Additionally, you can use 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.

Example

count renders

test('should have two renders when state is updated', async () => {
  const Counter = () => {
    const [count, setCount] = React.useState(0);
    return (
      

{count}

setCount((c) => c + 1)}> count
); }; const Component = () => { return ; };

const { renderCount } = perf(React);

render();

fireEvent.click(screen.getByRole('button', { name: /count/i }));

await wait(() => expect(renderCount.current.Counter.value).toBe(2)); });

test('should have two renders when state is updated with multiple of the same component', async () => { const Counter = ({ testid }) => { const [count, setCount] = React.useState(0); return (

{count}

setCount((c) => c + 1)} > count
); }; const Component = () => { return (
); };

const { renderCount } = perf(React);

render();

fireEvent.click(screen.getByTestId('button'));

await wait(() => { expect(renderCount.current.Counter[0].value).toBe(1); expect(renderCount.current.Counter[1].value).toBe(2); expect(renderCount.current.Counter[2].value).toBe(1); }); });

measure render time

If you want to use

renderTime
, please check out the docs: renderTime.
test('render time should be less than 16ms', async () => {
  const Counter = () => {
    const [count, setCount] = React.useState(0);
    return (
      

{count}

setCount((c) => c + 1)}> count
); };

const { renderTime } = perf(React);

render();

fireEvent.click(screen.getByRole('button', { name: /count/i }));

await wait(() => { // 16ms is meaning it is 60fps expect(renderTime.current.Counter.mount).toBeLessThan(16); // renderTime.current.Counter.updates[0] is second render expect(renderTime.current.Counter.updates[0]).toBeLessThan(16); }); });

test('should measure re-render time when state is updated with multiple of the same component', async () => { const Counter = ({ testid }) => { const [count, setCount] = React.useState(0); return (

{count}

setCount((c) => c + 1)} > count
); }; const Component = () => { return (
); };

const { renderTime } = perf(React);

render();

fireEvent.click(screen.getByTestId('button'));

await wait(() => { expect(renderTime.current.Counter[0].updates).toHaveLength(0); expect(renderTime.current.Counter[1].updates[0]).toBeLessThan(16); expect(renderTime.current.Counter[2].updates).toHaveLength(0); }); });

API

If you use the API with a large component, the component's performance could be affected because we monkey patch React. Therefore, if you want to measure accurately, you should use the API with components that have one feature like

List
,
Modal
etc.

perf

perf
method observes your component. So you can get the
renderCount
to count the number of renders and
renderTime
to measure render time.
const { renderCount, renderTime } = perf(React);

Note 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
.

Note: You need to wrap the returned value with wait method.

renderCount

renderCount
will count the number of renders.
const Component = () => 

test

; const { renderCount } = perf(React); // render is imported from react-testing-library render(); wait(() => console.log(renderCount.current.Component.value)); // output: 1

Note: You need to set a display name. If you have an anonymous component, we can not set the

renderCount
property correctly.
Properties
  • renderCount.current
    • ComponentName: string | Array
    • value: number

Note: If you have the same component, these components combine into an

array

renderTime

renderTime
will count the time elapsed between renders.
const Component = () => 

test

; const { renderTime } = perf(React); // render is imported from react-testing-library render(); wait(() => { console.log(renderTime.current.Component.mount); // output: ...ms console.log(renderTime.current.Component.updates); // output: [] });

Note: If you want to measure render time, you need to test renders one by one. V8 has a feature called inline caching, 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
.

Note: You need to set a display name. If you have an anonymous component, we can not set a property to

renderTime
correctly.
Properties
  • renderCount.current
    • ComponentName: string | Array
    • mount: number
      ... This property has the initial render time.
    • updates: Array
      ... This property has the second and the subsequent render time (the second render is the index of
      0
      )

Note: If you have the duplicate components, these components combine into

array

Note: time is measured in
ms
, milliseconds elapsed.

wait

The

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.
wait(() => console.log(renderTime.current.Component));

cleanup

The

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
. If your testing library has
afterEach()
, you need to invoke
cleanup()
manually.

ReactNative

If you are using ReactNative, you need to import modules from

react-performance-testing/native
.
import { perf } from 'react-performance-testing/native';

TypeScript

If you are using Typescript, you can get benefits from type inference as seen below.

const Text = (): React.ReactElement => 

test

; const Component = (): React.ReactElement => (
);

// If you didn't pass your type to the type argument const { renderCount, renderTime } = perf(React); renderCount.current // Editor will suggest Text | Text[] and Component | Component[]

// If you passed your type to the type argument const { renderCount, renderTime } = perf React; renderCount.current // Editor will suggest Text[] and Component

You 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.

Note: If you are using

ts-jest
, you need to combine it with
babel
. You can check the way to set up config here. 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.

Tips

Performance

This 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.

Anonymous Component

If 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.

React.memo(function MemoComponent() {
  return 

test

; });

// or

const MemoComponent = () =>

test

; React.memo(MemoComponent);

Setting a display name will get benefits not only from this library but also when you debug in React.

Hooks

If you are using

@testing-library/react-hooks
, you can check the number of renders with the
perf
method as bellows.
const { renderCount } = perf(React);
const { result } = renderHook(() => {
  /**
   * use some hooks
   */
});

// You can get value from the TestHook component wait(() => console.log(renderCount.current.TestHook.value));

This is because the

renderHook
method is wrapping callbacks with the
TestHook
component.

LICENSE

MIT

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.