ShallowWrapper::setState() can only be called on class components

11,808

Making original classes like StoryApp local harms the testability. Imported StoryApp is decorated with withSnackbar HOC and isn't class component.

A HOC should either expose original component that will be available, e.g. WrappedComponent property.

Or a module should export both decorated and original component:

export class StoryApp ...

export default withSnackbar(StoryApp)

This way it can be tested like:

import StoryApp, { StoryApp as OriginalStoryAppClass } from '...';
...
const wrapper = shallow(<StoryApp />);
const storyApp = wrapper.find(OriginalStoryAppClass).dive();
Share:
11,808

Related videos on Youtube

Peyman Barjoueian
Author by

Peyman Barjoueian

Updated on September 15, 2022

Comments

  • Peyman Barjoueian
    Peyman Barjoueian over 1 year

    this test was passing before i using withSnackbar. but now it fails and i really don't know how to fix that. So any help will be appreciated. Thanks.

    Here is my export in the component:

    export default withSnackbar(StoryApp)

    And here is my test:

    let story = {
      Title: "title 1",
      body: "body 1",
      UserEntityKey: "userEntityKey",
      Key: "storyKey"
    }
    
    afterEach(() => {
      // cleaning up the mess left behind the previous test
      MockAxios.reset();
    });
    
    test('Story deletes based on mocked backend response', async () => {
      window.confirm = jest.fn()
      window.confirm.mockReturnValue(1);
    
      let idToken = "asdf"
    
      MockAxios.delete.mockImplementationOnce(() =>
        Promise.resolve(story.Key)
      )
    
      const storyApp = shallow(<StoryApp />);
    
      storyApp.setState((prev) => {
        prev.data.push(story)
        return prev
      })
    
      // Test without idToken
      await storyApp.instance().deleteStory(story)
      expect(MockAxios.delete).not.toHaveBeenCalled();
      expect(storyApp.state().data.length).toEqual(1)
    
      // Test with idToken
      storyApp.setState((prev) => {
        prev.user = { idToken: idToken }
        return prev
      })
      await storyApp.instance().deleteStory(story)
      expect(MockAxios.delete).toHaveBeenCalledWith(apiUrl + '?key=' + story.Key, { headers: { 'Authorization': idToken } });
      expect(storyApp.state().data.length).toEqual(0)
    })

    And here is the output:

    ● Story deletes based on mocked backend response

    ShallowWrapper::setState() can only be called on class components
    
      101 |   const storyApp = shallow(<StoryApp />);
      102 | 
    > 103 |   storyApp.setState((prev) => {
          |            ^
      104 |     prev.data.push(story)
      105 |     return prev
      106 |   })
    
      at ShallowWrapper.setState (node_modules/enzyme/build/ShallowWrapper.js:639:17)
      at Object.setState (__tests__/App.test.js:103:12)
      at tryCatch (node_modules/regenerator-runtime/runtime.js:62:40)
      at Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:288:22)
      at Generator.prototype.(anonymous function) [as next] (node_modules/regenerator-runtime/runtime.js:114:21)
      at asyncGeneratorStep (__tests__/App.test.js:25:103)
      at _next (__tests__/App.test.js:27:194)
      at __tests__/App.test.js:27:364
      at Object.<anonymous> (__tests__/App.test.js:27:97)
    
  • Peyman Barjoueian
    Peyman Barjoueian about 5 years
    Thanks @estus but now i get something else: Method “dive” is meant to be run on 1 node. 0 found instead. What do you mean OriginalStoryAppClass? May class name is StoryApp, so i use it instead of OriginalStoryAppClass.
  • Estus Flask
    Estus Flask about 5 years
    Class name doesn't matter. OriginalStoryAppClass should be original class component. If you export it like it was suggested, import it like import { StoryApp: OriginalStoryAppClass }. I cannot say what may be possible reasons for it not work because you didn't provide the code you're testing.
  • jayanthsaikiran
    jayanthsaikiran over 2 years
    Is there any alternative for setState for modifying state variables in functional components?