Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A library to make commited-render-to-committed-render assertions on your React components and hooks.

License

NotificationsYou must be signed in to change notification settings

testing-library/react-render-stream-testing-library

Repository files navigation

What is this library?

This library allows you to make committed-render-to-committed-render assertionson your React components and hooks. This is usually not necessary, but can behighly beneficial when testing hot code paths.

Who is this library for?

This library is intended to test libraries or library-like code. It requires youto write additional components so you can test how your components interact withother components in specific scenarios.

As such, it is not intended to be used for end-to-end testing of yourapplication.

Brought to you by Apollo

This library originally was part of the Apollo Client test suite and ismaintained by the Apollo Client team.

Usage examples:

createRenderStream with DOM snapshots

If used withsnapshotDOM, RSTL will create a snapshot of your DOM after everyrender, and you can iterate through all the intermediate states of your DOM atyour own pace, independenly of how fast these renders actually happened.

test('iterate through renders with DOM snapshots',async()=>{const{takeRender, render}=createRenderStream({snapshotDOM:true,})constutils=awaitrender(<Counter/>)constincrementButton=utils.getByText('Increment')awaituserEvent.click(incrementButton)awaituserEvent.click(incrementButton){const{withinDOM}=awaittakeRender()constinput=withinDOM().getByLabelText('Value')expect(input.value).toBe('0')}{const{withinDOM}=awaittakeRender()constinput=withinDOM().getByLabelText('Value')expect(input.value).toBe('1')}{const{withinDOM}=awaittakeRender()constinput=withinDOM().getByLabelText('Value')expect(input.value).toBe('2')}})

renderHookToSnapshotStream

Usage is very similar to RTL'srenderHook, but you get asnapshotStreamobject back that you can iterate withtakeSnapshot calls.

test('`useQuery` with `skip`',async()=>{const{takeSnapshot, rerender}=awaitrenderHookToSnapshotStream(({skip})=>useQuery(query,{skip}),{wrapper:({children})=><Providerclient={client}>{children}</Provider>,},){constresult=awaittakeSnapshot()expect(result.loading).toBe(true)expect(result.data).toBe(undefined)}{constresult=awaittakeSnapshot()expect(result.loading).toBe(false)expect(result.data).toEqual({hello:'world 1'})}awaitrerender({skip:true}){constsnapshot=awaittakeSnapshot()expect(snapshot.loading).toBe(false)expect(snapshot.data).toEqual(undefined)}})

Tracking which components rerender withuseTrackRenders

You can track if a component was rerendered during a specific render by callinguseTrackRenders within it.

test('`useTrackRenders` with suspense',async()=>{functionErrorComponent(){useTrackRenders()// return ...}functionDataComponent(){useTrackRenders()constdata=useSuspenseQuery(someQuery)// return ...}functionLoadingComponent(){useTrackRenders()// return ...}functionApp(){useTrackRenders()return(<ErrorBoundaryFallbackComponent={ErrorComponent}><React.Suspensefallback={<LoadingComponent/>}><DataComponent/></React.Suspense></ErrorBoundary>)}const{takeRender, render}=createRenderStream()awaitrender(<App/>){const{renderedComponents}=awaittakeRender()expect(renderedComponents).toEqual([App,LoadingComponent])}{const{renderedComponents}=awaittakeRender()expect(renderedComponents).toEqual([DataComponent])}})

Note

The order of components inrenderedComponents is the order of execution ofuseLayoutEffect. Keep in mind that this might not be the order you wouldexpect.

taking custom snapshots inside of helper Components withreplaceSnapshot

If you need to, you can also take custom snapshots of data in each render.

test('custom snapshots with `replaceSnapshot`',async()=>{functionCounter(){const[value,setValue]=React.useState(0)replaceSnapshot({value})// return ...}const{takeRender, replaceSnapshot, render}=createRenderStream<{value:number}>()constutils=awaitrender(<Counter/>)constincrementButton=utils.getByText('Increment')awaituserEvent.click(incrementButton){const{snapshot}=awaittakeRender()expect(snapshot).toEqual({value:0})}{const{snapshot}=awaittakeRender()expect(snapshot).toEqual({value:1})}})

Tip

replaceSnapshot can also be called with a callback that gives you access tothe last snapshot value.

Tip

You can also usemergeSnapshot, which shallowly merges the last snapshotwith the new one instead of replacing it.

Making assertions directly after a render withonRender

test('assertions in `onRender`',async()=>{functionCounter(){const[value,setValue]=React.useState(0)replaceSnapshot({value})return(<CounterFormvalue={value}onIncrement={()=>setValue(v=>v+1)}/>)}const{takeRender, replaceSnapshot, utils}=awaitrenderToRenderStream<{value:number}>({onRender(info){// you can use `expect` hereexpect(info.count).toBe(info.snapshot.value+1)},})constincrementButton=utils.getByText('Increment')awaituserEvent.click(incrementButton)awaituserEvent.click(incrementButton)awaittakeRender()awaittakeRender()awaittakeRender()})

Note

info contains thebase profiling informationpassed intoonRender of React'sProfiler component, as well assnapshot,replaceSnapshot andmergeSnapshot

expect(...)[.not].toRerender() andexpect(...)[.not].toRenderExactlyTimes(n)

This library adds to matchers toexpect that can be used like

test('basic functionality',async()=>{const{takeRender}=awaitrenderToRenderStream(<RerenderingComponent/>)awaitexpect(takeRender).toRerender()awaittakeRender()// trigger a rerender somehowawaitexpect(takeRender).toRerender()awaittakeRender()// ensure at the end of a test that no more renders will happenawaitexpect(takeRender).not.toRerender()awaitexpect(takeRender).toRenderExactlyTimes(2)})

These matchers can be used on multiple different objects:

awaitexpect(takeRender).toRerender()awaitexpect(renderStream).toRerender()awaitexpect(takeSnapshot).toRerender()awaitexpect(snapshotStream).toRerender()

Note

By default,.toRerender andtoRenderExactlyTimes will wait 100ms forrenders or to ensure no more renders happens.

You can modify that with thetimeout option:

awaitexpect(takeRender).not.toRerender({timeout:300})

Tip

If you don't want these matchers not to be automatically installed, you canimport from@testing-library/react-render-stream/pure instead.
Keep in mind that if you use the/pure import, you have to call thecleanup export manually after each test.

Usage side-by side with@testing-library/react or other tools that useact or setIS_REACT_ACT_ENVIRONMENT

This library should not be used withact, and it will throw an error ifIS_REACT_ACT_ENVIRONMENT istrue.

React Testing Library setsIS_REACT_ACT_ENVIRONMENT totrue globally, andwraps some helpers likeuserEvent.click inact calls.
To use this library side-by-side with React Testing Library, we ship thedisableActEnvironment helper to undo these changes temporarily.

It returns aDisposable and can be used together with theusing keywordto automatically clean up once the scope is left:

test('my test',()=>{  using_disabledAct=disableActEnvironment()// your test code here// as soon as this scope is left, the environment will be cleaned up})

If you cannot useusing, you can also manually call the returnedcleanupfunction. We recommend usingfinally to ensure the act environment is cleanedup if your test fails, otherwise it could leak between tests:

test('my test',()=>{const{cleanup}=disableActEnvironment()try{// your test code here}finally{cleanup()}})

About

A library to make commited-render-to-committed-render assertions on your React components and hooks.

Resources

License

Code of conduct

Stars

Watchers

Forks

Contributors87


[8]ページ先頭

©2009-2025 Movatter.jp