简体   繁体   中英

Testing async method using React testing library

I have button in component:

<button
    type="button"
    title="Logout"
    data-testid="logout"
    onClick={logout}
>

and method logout :

const logout = async () => {
    try {
        await authLogout()
    } catch (error) {
        console.error(error)
    } finally {
        props.history.push('/login')
    }
}

Now I trying testing logout method by click on button:

describe('UserMenuComponent', () => {
  it('go to login page after click on logout', async () => {
    const history = createMemoryHistory()

    const { getByTestId } = render(
      <Router history={history}>
        <UserMenuComponent />,
      </Router>,
      {
        initialState: { reducersAuth: initialState },
      },
    )

    fireEvent.click(getByTestId('logout'))
    expect(history.location.pathname).toBe('/login')
  })
})

Inside method logout in finally block I have props.history.push('/login') and I check this in my test: expect(history.location.pathname).toBe('/login') but test return error:

expect(received).toBe(expected) // Object.is equality

Expected: "/login"
Received: "/"

You should use useHistory() hook to get history object inside your SFC.

Besides, since the logout function is an async function, you should use waitFor method to wait for your expectations to pass.

Eg

UserMenuComponent.tsx :

import React from 'react';
import { useHistory } from 'react-router-dom';

async function authLogout() {}

export function UserMenuComponent() {
  const history = useHistory();
  const logout = async () => {
    try {
      await authLogout();
    } catch (error) {
      console.error(error);
    } finally {
      history.push('/login');
    }
  };

  return <button type="button" title="Logout" data-testid="logout" onClick={logout}></button>;
}

UserMenuComponent.test.tsx :

import { fireEvent, render, waitFor } from '@testing-library/react';
import React from 'react';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { UserMenuComponent } from './UserMenuComponent';

describe('UserMenuComponent', () => {
  it('go to login page after click on logout', async () => {
    const history = createMemoryHistory();
    const pushSpy = jest.spyOn(history, 'push');

    const { getByTestId } = render(
      <Router history={history}>
        <UserMenuComponent />,
      </Router>
    );

    fireEvent.click(getByTestId('logout'));
    await waitFor(() => {
      expect(pushSpy).toBeCalledWith('/login');
      expect(history.location.pathname).toBe('/login');
    });
  });
});

test result:

 PASS  examples/66571376/UserMenuComponent.test.tsx
  UserMenuComponent
    ✓ go to login page after click on logout (82 ms)

-----------------------|---------|----------|---------|---------|-------------------
File                   | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------------------|---------|----------|---------|---------|-------------------
All files              |   91.67 |      100 |     100 |   90.91 |                   
 UserMenuComponent.tsx |   91.67 |      100 |     100 |   90.91 | 12                
-----------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.881 s, estimated 4 s

You can use waitFor to wait for your expectation to pass.

await waitFor(() => expect(history.location.pathname).toBe('/login'))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM