jestjsreact-testing-libraryvitesttesting-library

How to test if the rows are filtered in a table with testing library


I have a component which uses react-table to show some data. Now I'm trying to write a test which will test whether if typing in search field filters the row in the table or not? But test is not triggering the onchange event hence the search is not performed. Below is the example code(not actual implementation) of my component and the test snippets. How can I test this scenario? Can there be better approach to test this?

Here is the repo of code

data-table.tsx

import {
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getSortedRowModel,
  useReactTable,
  ColumnDef,
} from '@tanstack/react-table';
import { useMemo, useState } from 'react';
import { DebouncedInput } from './debounced-input';
import { Data, data } from './data';
export function DataTable() {
  const columns: Array<ColumnDef<Data>> = useMemo(
    () => [
      {
        accessorKey: 'id',
      },
      {
        accessorKey: 'name',
        cell({ row }) {
          return (
            <div className="border-0 rounded-md">
              <div className="p-3">
                <p className="break-all">{row.getValue('name')}</p>
              </div>
            </div>
          );
        },
      },
    ],
    []
  );
  const getRowId = (row: Data) => row.id ?? '';
  const [searchTerm, setSearchTerm] = useState('');
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    enableMultiRowSelection: false,
    getRowId,
    state: {
      globalFilter: searchTerm,
    },
  });

  return (
    <>
      <DebouncedInput
        data-testid="debounced-input"
        type="text"
        className="p-1 mr-2 mb-2"
        value={searchTerm}
        onChange={setSearchTerm}
        placeholder="Search"
      />
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>Name</th>
          </tr>
        </thead>
        <tbody>
          {table.getRowModel().rows?.length ? (
            table.getRowModel().rows.map((row) => (
              <tr className="cursor-pointer" key={row.id}>
                {row.getVisibleCells().map((cell) => (
                  <td key={cell.id}>
                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                  </td>
                ))}
              </tr>
            ))
          ) : (
            <tr>
              <td colSpan={columns.length} className="h-24 text-center">
                No Data
              </td>
            </tr>
          )}
        </tbody>
      </table>
    </>
  );
}

data-table.spec.tsx

import { render, screen, act } from '@testing-library/react';
import { DataTable } from './data-table';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';

describe('Tests', () => {
  it('should have searched license in the grid when user type a term', async () => {
    const user = userEvent.setup();
    render(<DataTable />);
    await act(async () => {
      await user.type(screen.getByTestId('debounced-input'), 'john');
    });

    expect(screen.getByText(/john doe/i)).toBeInTheDocument();
    expect(screen.getByText(/jane doe/i)).not.toBeInTheDocument();
    //
  });
});


Solution

  • Since your input is debounced, you should be waiting proper amount of time to changes to be applied. For instance if you are debouncing with 600 ms, wait more than 600 ms to table to be updated. You can use the code below after you make your changes in the input:

    await new Promise((resolve) => setTimeout(resolve, 2000));