Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rerender does not reset state #1331

Closed
saiNaruUFL opened this issue May 24, 2024 · 6 comments
Closed

rerender does not reset state #1331

saiNaruUFL opened this issue May 24, 2024 · 6 comments

Comments

@saiNaruUFL
Copy link

  • @testing-library/react version: 14.3.1
  • Testing Framework and version: vitest v1.6.0 & vitest-vscode v0.10.7
  • DOM Environment: jsdom (23.2.0)

Relevant code or config:

Renderer Code

export const renderWithProviders = ( 
   ui: ReactElement, 
   extendedRenderOptions: ExtendedRenderOptions = {}, 
 ) => { 
   const { 
     preloadedState = {}, 
     // Automatically create a store instance if no store was passed in 
     store = makeStore(preloadedState), 
     ...renderOptions 
   } = extendedRenderOptions 
  
   const Wrapper = ({ children }: PropsWithChildren) => ( 
     <Provider store={store}>{children}</Provider> 
   ) 
  
   const rendered = render(<div>{ui}</div>, { 
     ...renderOptions, 
     wrapper: Wrapper, 
   }) 
  
   // Return an object with the store and all of RTL's query functions 
   return { 
     ...rendered, 
     store, 
     user: userEvent.setup(), 
     rerender: (ui: ReactElement) => { 
       store: makeStore(preloadedState), 
         renderWithProviders(ui, { 
           wrapper: Wrapper, 
           container: rendered.container, 
           ...renderOptions, 
         }) 
     }, 
   } 
 }

Test Code

//Search Test 
 test("Search Bar should mount, have no initial value, and re-render properly", async () => { 
   const { store, user, rerender } = renderWithProviders(<App />) 
  
   //Find search-bar and ensrue that initial value is empty 
   expect(screen.getByRole("textbox")).toBeInTheDocument() 
   expect(screen.getByRole("textbox")).toHaveValue("") 
  
   //get the ui-component and emulate user typing 
   const inputUI = screen.getByRole("textbox") 
   await user.type(inputUI, "Bowjeet is King") 
  
   //screen debug info after typing 
   screen.debug() 
   console.log(store.getState()) 
  
   // Rerender the component (issue: the store does not clear) 
   rerender(<App />) 
  
   // Screen debug after re-render 
   screen.debug() 
  
   // Ensure the value is reset (issue: the component clears but the store does not) 
   expect(screen.getByRole("textbox")).toHaveValue("") 
   console.log(store.getState()) 
 }) 

What you did:

Called rerender after initial call to renderWithProviders to test resetting redux state. renderWithProviders is a custom wrapper to include redux store

What happened:

After calling rerender, the redux store still persists state from initial render call. The screenshot below shows that the screen rerenders appropriately, but the redux store does not reset.

slkjsd

Reproduction:

https://github.com/Agriculture-Intelligence/react-test-library-redux-example/tree/master

Related to:
#218 (comment)
#950
testing-library/testing-library-docs#1156 ?

Problem description:

rerender should reset the wrapper as well. Our understanding of rerender is that it should work similar to a browser refresh.

Ultimately, we want to test our components using Gherkin syntax and reset the component for every scenario as such

describeFeature(feature, (f) => {
  let viRender = renderWithProviders(<InventoryTab />, {
        preloadedState,
      })

  f.AfterEachScenario(() => {
    viRender.rerender();
  })
  f.Scenario(...);

This Gherkin syntax testing is not included in the reproduction to simplify the issue we are having, this testing style comes from https://github.com/amiceli/vitest-cucumber

Suggested solution:

  • Make the rerender API more powerful?
@saiNaruUFL
Copy link
Author

CC:@MatanBobi

@eps1lon
Copy link
Member

eps1lon commented May 24, 2024

rerender is intended to persist state just like calling root.render() in React would persist state.

You want to call render from React Testing Library again to discard the previous Redux state.

@eps1lon eps1lon closed this as not planned Won't fix, can't repro, duplicate, stale May 24, 2024
@MatanBobi
Copy link
Member

Adding to what @eps1lon wrote, regarding what you wrote here:

Our understanding of rerender is that it should work similar to a browser refresh.

That's not a good mental model. rerender is in fact a component re-render, it's not equal to an unmount + mount again which is what a full page refresh causes.

@charlieforward9
Copy link

@MatanBobi thank you for clarifying.

@eps1lon Thank you for the response as well. Regarding our use case:

describeFeature(feature, (f) => {
  let viRender = renderWithProviders(<InventoryTab />, {
        preloadedState,
      })

  f.AfterEachScenario(() => {
    viRender.rerender();
  })
  f.Scenario(...);

Are you implying that we should call a new render within each Scenario? I was hoping to avoid repetitive calls but this seems like the only approach hat makes sense.

@charlieforward9
Copy link

@eps1lon @MatanBobi we are still having an issue with state idempotency. We found a nearly identical issue that has not been resolved on Stack Overflow.

We could open a new issue, but all of the details are here so hoping to continue on this thread.

@MatanBobi
Copy link
Member

@charlieforward9 I recommend opening a new issue with the use case you're experiencing.
As you can see, commenting on closed issues usually gets lost in the notifications mess 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants