admin管理员组

文章数量:1415116

I'm trying to test my UsersTable page in React, but the testing library gets the elements before they have time to render. Please check my code below:

UsersTable.js

import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import Table from 'react-bootstrap/Table';
import { fetchUsers } from 'api';


function UsersTable() {
    const [users, setUsers] = useState([]);

    useEffect(() => {
        const getUsers = async () => {
            const data = await fetchUsers();
            setUsers(data);
        };

        getUsers();
    }, []);


    const renderUsers = () => users.map((user) => {
        const { id, fullName, email } = user;

        return (
            <tr key={ id } >
                <td>
                    <Link to={ `user/${id}` }>{ fullName }</Link>
                </td>
                <td>
                    <Link to={ `user/${id}/mail` }>{ email }</Link>
                </td>
            </tr>
        );
    });
    return (
        <div data-testid='userTest' className="users-table">
            <h1>Users</h1>
            <Table striped borderless>
                <thead>
                    <tr style={{
                            borderBottom: "1px solid #cccccc"
                        }}> 
                        <th>User</th>
                        <th>Email</th>
                    </tr>
                </thead>
                <tbody>
                    { renderUsers() }
                </tbody>
            </Table>
        </div>
    );
}

export default UsersTable;

userTable.test.js

import { render } from '@testing-library/react'
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import '@testing-library/jest-dom/extend-expect';
import UserTable from '../ponents/users/UserTable';




test("Test #1: Count Users", async () => {

    const ponent = render(
        <Router>
            <UserTable />
        </Router>
    );

    const users = ponent.getByTestId('userTest')
    expect(users.querySelectorAll('tr').length).toBe(193)
})

Note: <Router> prevents the error Error: Uncaught [Error: Invariant failed: You should not use <Link> outside a <Router>

Expect: Expecting to have 192 users + 1 row containing thead, but instead I get 1 row containing only the thead.

I'm trying to test my UsersTable page in React, but the testing library gets the elements before they have time to render. Please check my code below:

UsersTable.js

import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import Table from 'react-bootstrap/Table';
import { fetchUsers } from 'api';


function UsersTable() {
    const [users, setUsers] = useState([]);

    useEffect(() => {
        const getUsers = async () => {
            const data = await fetchUsers();
            setUsers(data);
        };

        getUsers();
    }, []);


    const renderUsers = () => users.map((user) => {
        const { id, fullName, email } = user;

        return (
            <tr key={ id } >
                <td>
                    <Link to={ `user/${id}` }>{ fullName }</Link>
                </td>
                <td>
                    <Link to={ `user/${id}/mail` }>{ email }</Link>
                </td>
            </tr>
        );
    });
    return (
        <div data-testid='userTest' className="users-table">
            <h1>Users</h1>
            <Table striped borderless>
                <thead>
                    <tr style={{
                            borderBottom: "1px solid #cccccc"
                        }}> 
                        <th>User</th>
                        <th>Email</th>
                    </tr>
                </thead>
                <tbody>
                    { renderUsers() }
                </tbody>
            </Table>
        </div>
    );
}

export default UsersTable;

userTable.test.js

import { render } from '@testing-library/react'
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import '@testing-library/jest-dom/extend-expect';
import UserTable from '../ponents/users/UserTable';




test("Test #1: Count Users", async () => {

    const ponent = render(
        <Router>
            <UserTable />
        </Router>
    );

    const users = ponent.getByTestId('userTest')
    expect(users.querySelectorAll('tr').length).toBe(193)
})

Note: <Router> prevents the error Error: Uncaught [Error: Invariant failed: You should not use <Link> outside a <Router>

Expect: Expecting to have 192 users + 1 row containing thead, but instead I get 1 row containing only the thead.

Share Improve this question edited Nov 21, 2024 at 11:10 DarkBee 15.5k8 gold badges72 silver badges118 bronze badges asked Jun 8, 2022 at 22:13 Gerald HoxhaGerald Hoxha 491 gold badge1 silver badge6 bronze badges 4
  • 1 See testing-library./docs/dom-testing-library/api-async – jonrsharpe Commented Jun 8, 2022 at 22:23
  • Are you mocking your fetchusers? What you need to garantee its that the ponent is rendered the table with rows and cells, not the number of td chids... Take a look in what you should avoid with testing library here. – Luis Paulo Pinto Commented Jun 8, 2022 at 23:15
  • 1 But if you want to test the number of tr, you should avoid use selectors like you did. The proper way in this case would be const trElements = screen.getAllByRole('row') and expect(trElements).toHaveLength(193) – Luis Paulo Pinto Commented Jun 8, 2022 at 23:17
  • Thank you for your advice, Luis. I ended up testing that the ponents are rendered and tested some user inputs. Thanks a lot! – Gerald Hoxha Commented Jun 11, 2022 at 8:42
Add a ment  | 

2 Answers 2

Reset to default 0
expect(getByTestId('userTest').children.length).toBe(193);

The issue Is that your test is trying to access the DOM elements before the useEffect hook in UsersTable has pleted fetching and rendering the data.

You can use reacts @testing-library's findBy or waitFor methods to wait for the ponents to render your ponent data asynchronously.

import { render, screen, waitFor } from '@testing-library/react';
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import '@testing-library/jest-dom/extend-expect';
import UsersTable from '../ponents/users/UserTable';


jest.mock('api', () => ({ // Mocking fetch user API call
    fetchUsers: jest.fn(() =>
        Promise.resolve(
            Array.from({ length: 192 }, (_, i) => ({
                id: i + 1,
                fullName: `User ${i + 1}`,
                email: `user${i + 1}@example.`,
            }))
        )
    ),
}));

test('Test #1: Count Users', async () => {
    render(
        <Router>
            <UsersTable />
        </Router>
    );

    // Waiting for the rows to rendered including the header row
    await waitFor(() => { 
        expect(screen.getAllByRole('row').length).toBe(193);
    });
});

This will guarantee asynchronous rendering and avoid querying before the data is available.

本文标签: javascriptHow to get the elements from a table after all components are renderedStack Overflow