keajs / kea

Batteries Included State Management for React

Home Page:https://keajs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Still having issues to unit test connected components

danielmariz opened this issue · comments

So I was following the hooks test examples
but sill don't get the proper approach to write unit test for connected components.
On logic's unit test everything works fine but inside the connected component the values just won't change based on action/listeners calls.

my current code is in Typescript but here's a simple example for what I'm trying to achieve:

const logic = kea({
    path: ['containers', 'user', 'main'],
    actions: {
        requestUserData: ()  => null,
        setUserData: (data) => ({ data }),
        userDataFailed : (message) => ({ message }),
    },
    reducers: {
        isLoading: [false, {
            requestUserData: () => true,
            setUserData: () => false,
            userDataFailed: () => false,
        }]
    },
    listeners: ({ actions }) => ({
        requestUserData: async () => {
            try {
                const {payload} = await getUser() //api call
                actions.setUserData(payload)
            } catch (error) {
                actions.userDataFailed(error.message)
            }
        },
    })
})

const MyComponent = () => {
    const {isLoading} = useValues(logic)
    const {requestUserData} = useActions(logic)

    return <>
        {isLoading && <Loader  data-testid='loader' />}
        <button onClick={() => requestUserData()}>click</button>
    </>
}

beforeEach(() => {
        resetContext({     
            // createStore: true,
            createStore: {
                paths: ['kea', 'pages', 'containers'],
            },
            plugins: [
                waitForPlugin,
            ]
        })
    })

test('should show a loader when user clicks de button', async () => {
       const getUserMock = getUser as jest.Mock
       getUserMock.mockImplementationOnce(() => Promise.resolve({payload: {...something}}))

        render(<Provider store={getContext().store}>
            <MyComponent />
        </Provider>)
        
       fireEvent.click(getByText('click'))
       
        await waitFor(async () => {
           // EXPECT THIS TO HAPPEN
           expect(screen.getByTestId('loader')).toBeInTheDocument()
           await waitForElementToBeRemoved(() => screen.getByTestId('loader'))
        })
})

So this test triggers the listeners but won't change the reducer value so the loader will never been shown in the test render

Any help how to get this working?
I'm keen to write an exemple for the documentation and do a PR later

Cheers

Hey, finally coming back to this... and I'm having trouble understanding your code. There's no waitFor function the way you have it in your code sample. There's waitForAction, which could be used instead, but in this case, I assume since your mock returns immediately, there's just no time to show the loader.

Is this an issue you're still struggling with?