FreeGridv1.15.1한국어

Testing your grid

@freegridjs/testing reads cells, edits, sorts and presses keys like a user in jsdom, happy-dom or a real browser; mockLayout makes jsdom draw rows; selectors serve Playwright and Cypress.

Tests of a screen with a grid tend to break on the grid's inner DOM, or show no rows at all in jsdom. @freegridjs/testing drives the grid the way a user does — double-click, type, Enter, click a header — and reads back what is on screen.

npm i -D @freegridjs/testing

Unit tests (Vitest, Jest)

import { beforeAll, expect, it } from 'vitest';
import { createGrid } from '@freegridjs/core';
import { gridHarness, mockLayout } from '@freegridjs/testing';

// jsdom has no layout: without this every element is 0 × 0 and no rows are drawn
beforeAll(() => { mockLayout(); });

it('refuses a quantity over 99 and saves a good one', async () => {
  const host = document.createElement('div');
  document.body.append(host);
  const api = createGrid(host, { columns, data });
  const grid = gridHarness(host);
  await grid.waitForRows();

  expect(grid.headers()).toEqual(['Name', 'Qty', 'City']);
  expect(grid.edit(0, 'qty', '500').ok).toBe(false);   // the editor stays open with the message
  grid.press('Escape');

  expect(grid.edit(0, 'qty', '42')).toEqual({ ok: true });
  await grid.settle();
  expect(grid.cellText(0, 'qty')).toBe('42');
  expect(api.getModifiedRows().updated).toHaveLength(1);

  grid.clickHeader('qty');                           // sort
  await grid.settle();
  expect(grid.column('qty')).toEqual(['1', '2', '42']);
});
NameTypeDescription
mockLayout({ width?, height? })() => voidGive elements a size in jsdom / happy-dom (default 1024 × 600, about 20 rows) and silence the missing canvas. Returns a function that undoes it.
gridHarness(container)GridHarnessHelpers for the grid inside an element: the one given to createGrid, a component's host, or the grid root.
cell(r, colId) / cellText(r, colId)HTMLElement | null / stringA drawn cell and its text; null / empty when it is not on screen.
rows(colIds?) / column(colId)string[][] / string[]Texts of the drawn rows in display order.
headers() / columnIds() / rowCount()string[] / string[] / numberHeader labels and ids of the shown columns; number of drawn rows.
click / dblclick / clickHeader / pressvoidPointer and key events like a user; press goes to the grid as if it had the focus.
edit(r, colId, text, finish?){ ok, message? }Double-click, replace the text, then Enter (or 'Tab', 'Escape'). ok is true only when the value was saved: false after 'Escape', and false with the message when a rule refuses the value. For text, number, date and mask editors.
waitForRows(count?, timeout?) / settle()Promise<void>Wait for rows to be drawn, or for the next paint.

With React, Vue, Svelte or Angular

Render the component as usual and give gridHarness the element around it.

import { render } from '@testing-library/react';
import { FreeGrid } from '@freegridjs/react';
import { gridHarness, mockLayout } from '@freegridjs/testing';

beforeAll(() => { mockLayout(); });

it('shows the orders', async () => {
  const { container } = render(<FreeGrid columns={columns} data={orders} />);
  const grid = gridHarness(container);
  await grid.waitForRows(3);
  expect(grid.column('customer.name')).toEqual(['Kim', 'Lee', 'Park']);
});

Browser tests (Playwright, Cypress)

In a real browser use the selectors, which follow the grid if its inner structure changes:

import { selectors } from '@freegridjs/testing';

await page.locator(selectors.cell(0, 'qty')).dblclick();
await page.keyboard.type('42');
await page.keyboard.press('Enter');
await expect(page.locator(selectors.cell(0, 'qty'))).toHaveText('42');
await page.locator(selectors.header('qty')).click();     // sort

// Cypress
cy.get(selectors.cell(0, 'name')).should('have.text', 'Kim');
selectors.Matches
rootThe grid root
cell(rowIndex, colId) / row(rowIndex)A body cell / row; rowIndex is the display position
header(colId) / headerLabelA header cell / the label inside it
editor / editorMessageThe open editor box / its message
filterInput(colId) / overlayA filter row box / the "no rows" and loading layer

Only rows on screen are drawn, also in tests. To check data further down, read it from the API (getDisplayedRows, getCellValue) or scroll with scrollToRow first. Picker editors (select, combo, calendar) are easiest to set with api.setCellValue in unit tests; in a browser, click their options.

Questions about this page

Why does my grid show no rows in a Jest or Vitest test?

jsdom has no layout, so every element is 0 pixels high and the grid draws no rows. Call mockLayout() from @freegridjs/testing before the test (or give elements a size yourself), then wait for the rows with gridHarness(el).waitForRows().

How do I find a cell in Playwright or Cypress?

Use selectors.cell(rowIndex, colId) from @freegridjs/testing, for example page.locator(selectors.cell(0, 'name')). Row indexes are display positions, after sorting and filtering.