Vue Data GridTesting AG Grid

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

End to End (e2e) Testing Copy Link

We recommend using 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. Mocked browser environments (such as jsdom) can be used for simple unit testing cases, but their limitations can lead to confusing test results.

End to End (e2e) Testing Examples Copy Link

There are a number of end-to-end test examples available in the AG Grid repo which demonstrate how to use Test Ids to test AG Grid. While these tests use Playwright, we do not necessarily recommend one e2e framework over another.

Test IDs Copy Link

Enabling Test IDs Copy Link

Many testing libraries allow targeting the data-testid attribute to locate elements on the page to use for assertions or actions. AG Grid provides support for attaching this attribute to many of the interactive elements in the grid. This is achieved by calling the setupAgTestIds function. This should only be used in a test or development environment, not in production.

// Application code
import { setupAgTestIds } from 'ag-grid-community'

if(process.env.NODE_ENV !== "production"){
    // Setup test IDs for all instances of AG Grid that are created after this call.
    setupAgTestIds();
}

By default the test ID attribute will be data-testid but this can be customised via the testIdAttribute option. This is useful if you want to use a different attribute name, for example data-customattr.

// Application code
setupAgTestIds({ testIdAttribute: 'data-customattr' })

Using Test IDs Copy Link

WIth Test IDs enabled on your application's grids it is then possible to query elements via the agTestIdFor helper methods.

// Test code
import { agTestIdFor } from 'ag-grid-community';

// in your test case 
const rowId = 'toyota';
const colId = 'make';
const cellTestId = agTestIdFor.cell(rowId, colId);

// Using Playwright
const checkbox = page.getByTestId(cellTestId);

// Testing Library 
const checkbox = findByTestId(cellTestId);

Using Test Id Wrapper Copy Link

When writing tests using Test IDs, the code can become verbose. To reduce boilerplate use the wrapAgTestIdFor function to create a wrapper around the agTestIdFor methods for the given test context.

// Test code
import { agTestIdFor, wrapAgTestIdFor } from 'ag-grid-community';   

 // Before
 await expect(page.getByTestId(agTestIdFor.headerCell('toyota'))).toBeVisible();
 await expect(page.getByTestId(agTestIdFor.cell('toyota', 'make'))).toBeVisible();

 const agIdFor = wrapAgTestIdFor((testId) => page.getByTestId(testId));
 // After
 await expect(agIdFor.headerCell('toyota')).toBeVisible();
 await expect(agIdFor.cell('toyota', 'make')).toBeVisible();

Testing your Vue Application in NodeJS Copy Link

We will walk through how you can test AG Grid as part of your Vue application, using default build tools provided when using the Vue CLI utility.

Waiting for the Grid to be Initialised Copy Link

Due to the asynchronous nature of AG Grid we cannot simply mount the Grid and assume it'll be ready for testing in the next step - we need to wait for the Grid to be ready before testing it.

We can do this in one of two ways - wait for the gridReady event to be fired, or wait for the Grid API to be set.

The first requires a code change and can be tricky to hook into - the latter is unobtrusive and easier to use.

We can create a utility function that will wait for the Grid API to be set for a set amount of time/attempts:

const ensureGridApiHasBeenSet = vm => new Promise(function (resolve, reject) {
    let timeout = 3000;
    (function waitForGridReady() {
        if (timeout === 0) {
            reject(new Error('Timeout while waiting for AG Grid to initialise'))
        }

        // we need to wait for the gridReady event before we can start interacting with the grid
        // in this case we're looking at the api property in our App component,
        // but it could be anything (ie a boolean flag)
        if (vm.$data.api) {
            // once our condition has been met we can start the tests
            return resolve();
        }

        // not set - wait a bit longer
        timeout =- 10;
        setTimeout(waitForGridReady, 10);
    })();
});

We can now use this utility method before each test or in the beforeEach to ensure the Grid is fully ready before continuing with out test:

beforeEach((done) => {
    wrapper = mount(GridExample, {});

    // don't start our tests until the grid is ready
    // it doesn't take long for the grid to initialise, but it is some finite amount of time
    // after the component is ready
    ensureGridApiHasBeenSet(wrapper.vm).then(() => done());
});

Vue Testing Library Copy Link

An alternative approach would be to use the Vue Testing Library to test AG Grid. This comes with built in support for handling asynchronous behaviour which you may find easier to work with.

Testing User Supplied Components Copy Link

For example, let us suppose a user provides a custom Editor Component and wants to test this within the context of the Grid.

// Editor Component - Editor.vue
<template>
    <input v-model="value" type="number" style="width: 100%">
</template>

<script>
    export default {
        name: 'Editor',
        data() {
            return {
                value: null
            }
        },
        beforeMount() {
            this.value = this.params.value;
        },
        methods: {
            getValue() {
                return this.value;
            },

            // for testing
            setValue(newValue) {
                this.value = newValue;
            },

            isCancelBeforeStart() {
                return false;
            },

            isCancelAfterEnd() {
                return false;
            }
        }
    }
</script>

<template>
    <ag-grid-vue style="width: 500px; height: 500px;"
                 @grid-ready="onGridReady"
                 :columnDefs="columnDefs"
                 :rowData="rowData">
    </ag-grid-vue>
</template>

<script>
    import {AgGridVue} from "ag-grid-vue3";
    import Editor from './Editor.vue';

    export default {
        name: 'App',
        data() {
            return {
                columnDefs: null,
                rowData: null,
                api: null
            }
        },
        components: {
            AgGridVue,
            Editor
        },
        beforeMount() {
            this.columnDefs = [
                {field: 'make'},
                {
                    field: 'price',
                    editable: true,
                    cellEditor: 'Editor'
                }
            ];

            this.rowData = [
                {make: 'Toyota', price: '35000'},
            ];
        },
        methods: {
            onGridReady(params) {
                this.api = params.api;
            }
        }
    }
</script>

We can test the interaction between the Grid and the Editor component via the Grid API:

it('grid renders as expected', () => {
    const cells = wrapper.findAll('.ag-cell-value');
    expect(cells.length).toEqual(2);

    expect(cells.at(0).text()).toEqual('Toyota');
    expect(cells.at(1).text()).toEqual('70000');
});

it('cell should be editable and editor component usable', () => {
    // wait for the api to be set before continuing
    const componentInstance = wrapper.vm;

    const api = componentInstance.$data.api;

    // we use the API to start and stop editing - in a real e2e test we could actually
    // double click on the cell etc
    api.startEditingCell({
        rowIndex: 0,
        colKey: 'price'
    });

    // update the editor input
    const textInput = wrapper.find('input[type="number"]');
    textInput.setValue(100000);

    // stop editing
    api.stopEditing();

    // test the resulting values in the grid (the edited cell value should have changed)
    const cells = wrapper.findAll('.ag-cell-value');
    expect(cells.length).toEqual(2);

    expect(cells.at(0).text()).toEqual('Toyota');
    expect(cells.at(1).text()).toEqual('200000');
});

We use the Grid API to initiate and end testing as we're can't readily perform double clicks in a unit testing environment (but could if doing e2e with something like Protractor for example).

jsdom Limitations Copy Link

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.

Retrieving References to Grid API and Grid Container Element Copy Link

The following two utility functions are made available for convenience during testing:

import { getGridApi, getGridElement } from 'ag-grid-community'

// Retrieve a GridApi instance from a DOM node/selector
const api = getGridApi('#myGrid');

// Retrieve a Grid `Element` instance from a GridApi instance
const element = getGridElement(api);

The getGridApi function returns a GridApi instance that is associated with the grid rendered in gridElement. The gridElement argument can be one of the following: the grid ID as determined by the gridId grid option, a DOM node, or a CSS selector string.

It is recommended to use the gridId as the argument.

The getGridElement function returns the Element instance associated with the grid instance referred to by GridApi.