JavaScript 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.

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 DOM Testing Library

In the following example we test a simple configuration of AG Grid with the DOM Testing Library.

import { getByText } from '@testing-library/dom';
import '@testing-library/jest-dom';

import { createGrid, GridOptions } from 'ag-grid-community';

function createAgGrid() {
    const div = document.createElement('div');

    const gridOptions: GridOptions = {
        columnDefs: [
            { headerName: 'Make', field: 'make' },
            { headerName: 'Model', field: 'model' },
            { field: 'price', valueFormatter: (params) => '$' + params.value.toLocaleString() },
        ],
        rowData: [
            { make: 'Toyota', model: 'Celica', price: 35000 },
            { make: 'Ford', model: 'Mondeo', price: 32000 },
            { make: 'Porsche', model: 'Boxster', price: 72000 },
        ],
    };

    const api = createGrid(div, gridOptions);

    return { div, api };
}

test('examples of some things', async () => {
    const { div, api } = createAgGrid();

    // Get a cell value
    expect(getByText(div, 'Ford')).toHaveTextContent('Ford');

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

    // Test via the api even though this is not a recommended approach
    expect(api.getDisplayedRowCount()).toBe(3);
});

The test above can be found in the following GitHub Repo.

End to End (e2e) Recipes

These recipes below are suggestions - there are many ways to do End to End testing, what we document below is just one example.

We do not document how to use either Protractor and Jasmine in depth here - please see the documentation for either Protractor or Jasmine.

We only describe how these tools can be used to test AG Grid below.

Testing Dependencies

npm install protractor webdriver-manager --save-dev

# optional dependencies - if you're using TypeScript
npm install @types/jasmine @types/selenium-webdriver --save-dev

Note you can install protractor and webdriver-manager globally if you'd prefer, which would allow for shorter commands when executing either of these tools.

We now need to update the webdriver:

./node_modules/.bin/webdriver-manager update

This can be added to your package.json for easier packaging and repeatability:

"scripts": {
    "postinstall": "webdriver-manager update"
}

Selenium Server

You can either start & stop your tests in a script, or start the Selenium server separately, running your tests against it.

Remember that the interaction between your tests and the browser is as follows:

[Test Scripts] < ------------ > [Selenium Server] < ------------ > [Browser Drivers]

We'll run the server separately to begin with here:

./node_modules/.bin/webdriver-manager start

Sample Configuration

// conf.js
exports.config = {
    framework: 'jasmine',
    specs: ['spec.js']
}

// Here we specify the Jasmine testing framework as well as our test to run.

Sample Test

If you're testing against a non-Angular application then you need to tell Protractor not to wait for Angular by adding this to either your configuration or your tests: browser.ignoreSynchronization = true;

For this sample test we'll be testing this simple example:

Checking Headers

Let's start off by checking the headers are the ones we're expecting. We can do this by retrieving all div's that have the ag-header-cell-text class:

// spec.js
describe('AG Grid Protractor Test', function () {
    // not an angular application
    browser.ignoreSynchronization = true;

    beforeEach(() => {
        browser.get('https://www.ag-grid.com/examples/testing/hello-world/index.html');
    });

    it('should have expected column headers', () => {
        element.all(by.css(".ag-header-cell-text"))
            .map(function (header) {
                return header.getText()
            }).then(function (headers) {
                expect(headers).toEqual(['Make', 'Model', 'Price']);
            });
    });
});

We can now run our test by executing the following command:

./node_modules/.bin/protractor conf.js

# or if protractor is installed globally protractor conf.js

Checking Grid Data

We can match grid data by looking for rows by matching div[row="<row id>"] and then column values within these rows by looking for div's with a class of .ag-cell-value:

it('first row should have expected grid data', () => {
    element.all(by.css('div[row="0"] div.ag-cell-value'))
        .map(function (cell) {
            return cell.getText();
        })
        .then(function (cellValues) {
            expect(cellValues).toEqual(["Toyota", "Celica", "35000"]);
        });
});

We can add this to spec.js and run the tests as before.

AG Grid Testing Utilities

These utilities scripts should still be considered beta and are subject to change.

Here at AG Grid we use a number of utility functions that make it easier for us to test AG Grid functionality.

The utilities can be installed & imported as follows:

Installing:

npm install ag-grid-testing --save-dev

Importing:

let ag_grid_utils = require("ag-grid-testing");

verifyRowDataMatchesGridData

Compares Grid data to provided data. The order of the data provided should correspond to the order within the grid. The property names should correspond to the colId's of the columns.

ag_grid_utils.verifyRowDataMatchesGridData(
    [
        {
            // first row
            "name": "Amelia Braxton",
            "proficiency": "42%",
            "country": "Germany",
            "mobile": "+960 018 686 075",
            "landline": "+743 1027 698 318"
        },
        // more rows...
    ]
);

verifyCellContentAttributesContains

Useful when there is an array of data within a cell, each of which is writing an attribute (for example an image).

ag_grid_utils.verifyCellContentAttributesContains(1, "3", "src", ['android', 'mac', 'css'], "img");

allElementsTextMatch

Verifies that all elements text (ie the cell value) matches the provided data. Usf

ag_grid_utils.allElementsTextMatch(by.css(".ag-header-cell-text"),
    ['#', 'Name', 'Country', 'Skills', 'Proficiency', 'Mobile', 'Land-line']
);

clickOnHeader

Clicks on a header with the provided headerName.

ag_grid_utils.clickOnHeader("Name");

getLocatorForCell

Provides a CSS Locator for a grid cell, by row & id and optionally a further CSS selector.

ag_grid_utils.getLocatorForCell(0, "make")
ag_grid_utils.getLocatorForCell(0, "make", "div.myClass")

getCellContentsAsText

Returns the cell value (as text) for by row & id and optionally a further CSS selector.

ag_grid_utils.getCellContentsAsText(0, "make")
    .then(function(cellValue) {
        // do something with cellValue
    });

ag_grid_utils.getCellContentsAsText(0, "make", "div.myClass")
    .then(function(cellValue) {
        // do something with cellValue
    });