React Data GridTesting AG Grid

Here we give some hints on testing AG Grid as part of your application.

End to End (e2e) Testing

We recommend using e2e tests to validate AG Grid as part of your application.

It is recommended to use e2e tests to validate AG Grid as part of your application. There are a number of tools available to help with this, such as Playwright, Cypress or Selenium.

e2e tests are recommended so that AG Grid is run inside a real browser. Fake browser environments (such as jsdom) can be used for simple unit testing cases, but their limitations can lead to confusing test results.

A few examples of how to use Playwright with AG Grid can be found in this GitHub Repo.

Alternatively see Writing E2E Tests for AG Grid React Tables with Playwright.

jsdom Limitations

Test tools such as vitest, Dom Testing Library and Jest often rely on jsdom to mock the browser.

jsdom is a pure JavaScript implementation of many web standards with the goal to emulate enough of a subset of a web browser to be useful for testing. However, there are some limitations to be aware of when using jsdom.

If you are using jsdom for testing, you may encounter issues that suggest the grid is not rendering correctly. However, this is likely caused by jsdom not supporting all the features of a real browser.

The main limitations that can affect AG Grid are:

  • No support for CSS layout - impacts column / row virtualisation
  • No support for innerText property Issue #1245 - impacts some grid components

If you wish to use jsdom for your tests you may find the following polyfill useful if you encounter issues with missing content due to the use of innerText:

// Override the innerText setter to use textContent instead within jsdom based tests
Object.defineProperty(Element.prototype, 'innerText', {
    set(value) {
        this.textContent = value;
    },
});

Where you implement this polyfill may vary depending on your testing setup.

Testing with React Testing Library

The following examples demonstrate using React Testing Library to test AG Grid despite the limitations listed above. Each example will share a common App starting point that is defined below.


const App = () => {
    const [rowData] = useState([
        { make: 'Toyota', model: 'Celica', price: 35000 },
        { make: 'Ford', model: 'Mondeo', price: 32000 },
        { make: 'Porsche', model: 'Boxster', price: 72000 }
    ]);
    const [colDefs, setColDefs] = useState<ColDef[]>([
        { field: 'make' },
        { field: 'model' },
        { field: 'price' },
    ]);

    return (
        <div style={{ height: 400, width: 600 }}>
            <AgGridReact
                rowData={rowData}
                columnDefs={colDefs} />
        </div>
    );
};

Testing Cell Contents

The following example shows how to validate the grid is displaying the expected values including those cells using a custom cell renderer.

// Custom Cell Renderer
const BuyCellRenderer = (props: CustomCellRendererProps) => {
    const buttonClick = () => props.node.setDataValue('bought', true);

    return (
        <>
            {props.data?.bought ?
                <span>Bought a {props.data?.make}</span> :
                <button onClick={buttonClick}>Buy: {props.data?.make}</button>
            }
        </>
    );
};

// Column Definitions with value formatter and cellRenderer
const [colDefs, setColDefs] = useState<ColDef[]>([
    { field: 'make' },
    { field: 'model' },
    { field: 'price', valueFormatter: (params) => "$" + params.value.toLocaleString()},
    { field: 'bought', cellRenderer: BuyCellRenderer }
]);

The code to test the valueFormatter and cellRenderer is as follows.

test('value formatter and cell renderer', async () => {
    // First render the App component we wish to tests
    render(<App />);

    // Test the value formatter by searching for the correct price string
    expect(screen.getByText('$72,000')).toBeDefined();

    // Now find the expected content of the cell renderer
    const porscheButton = await screen.findByText('Buy: Porsche');
    expect(porscheButton).toBeDefined();

    // Click the cell renderer to test it changes correctly
    act(() => porscheButton.click());
    expect(screen.findByText('Bought a Porsche')).toBeDefined();
});

Clicking Rows

To test clicking rows it is recommend to use userEvent from testing-library/user-event to trigger row click event handlers. The following test displays the last clicked row above the grid.

<div data-testid="rowClicked">Row Clicked: {rowClicked?.make}</div>
<div style={{ height: 400, width: 600 }}>
  <AgGridReact
      rowData={rowData}
      columnDefs={colDefs}
      onRowClicked={onRowClicked} />
</div>
test('render grid and click a row', async () => {
  render(<App />);

  const row = await screen.findByText('Ford');
  expect(row).toBeDefined();

  await userEvent.click(row);

  const rowClicked = await screen.findByTestId('rowClicked');
  expect(rowClicked.textContent).toBe('Row Clicked: Ford');
});

Cell Editing

The following example shows how to mimic a user editing a cell's value.

test('double click cell to edit', async () => {
  render(<App />);

  const porschePrice = await screen.findByText('$72,000')
  expect(porschePrice).toBeDefined();

  // double click to enter edit mode       
  await userEvent.dblClick(porschePrice);

  // Find the input within the cell.
  const input: HTMLInputElement = within(porschePrice).getByLabelText('Input Editor');
  // Type the new price value
  await userEvent.keyboard('100000');

  // Press enter to save
  fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });

  expect(screen.findByText('$100,000')).toBeDefined();

});

All the tests above and more can be found in the following GitHub Repo.