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();
Related videos on Youtube
Author by
Peyman Barjoueian
Updated on September 15, 2022Comments
-
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 about 5 yearsThanks @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 about 5 yearsClass name doesn't matter.
OriginalStoryAppClass
should be original class component. If you export it like it was suggested, import it likeimport { 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 over 2 yearsIs there any alternative for setState for modifying state variables in functional components?