Testing AdapTable

View as Markdown

Summary

AdapTable is a standard JavaScript / TypeScript library.

There is no AdapTable-specific test framework — use whatever your application already uses.

The fastest, most reliable tests talk to AdapTable through the API.

Reach for end-to-end browser tests only when you specifically need to exercise the UI.

Hint

  • Fork the React Vitest template if you want a runnable suite immediately
  • The rest of this page is the practice that template follows

Choosing a Test Runner

RunnerNotes
VitestFast and modern, drop-in compatible with the Jest API; the runner used in the public React testing template
JestWidely used; works equally well for unit and integration tests against the Adaptable API
Testing LibraryPairs cleanly with Vitest or Jest when rendering AdapTable inside a component test
PlaywrightRecommended for end-to-end tests that drive the actual browser UI; this is what we use internally

Hint

  • API tests are the default: apply a Layout, run a search, edit a cell, then assert through the API
  • Component tests are useful when you render AdapTable inside your own wrapper
  • End-to-end tests are for Dashboard clicks, Settings Panel, menus etc — not for proving a Filter or Layout applied

Wait for Adaptable Ready

AdapTable initialises asynchronously.

Adaptable.init (vanilla) and framework wrappers all expose the instance through Adaptable Ready Event.

Wait for that Event before asserting on Grid state or calling API methods.

Caution

Do not use AG Grid's gridReady event for this — it fires before AdapTable has initialised

Adaptable.init already returns adaptableApi.

The Ready Event is replayed if you subscribe after init has resolved, so this helper is enough:

async function createAdaptableForTest(
  adaptableOptions: AdaptableOptions,
  agGridConfig: AgGridConfig
): Promise<AdaptableApi> {
  const adaptableApi = await Adaptable.init(adaptableOptions, agGridConfig);

  await new Promise<void>(resolve => {
    adaptableApi.eventApi.on('AdaptableReady', () => resolve());
  });

  return adaptableApi;
}

Drive the Adaptable API

The Adaptable API is the primary test surface.

Anything a user can do in the UI can be done programmatically — applying Filters, switching Layouts, running Exports, editing cells.

This keeps assertions concise and avoids brittle DOM selectors.

const adaptableApi = await createAdaptableForTest(
  adaptableOptions,
  agGridConfig
);

adaptableApi.layoutApi.setLayout('Cars');
expect(adaptableApi.layoutApi.getCurrentLayoutName()).toBe('Cars');

adaptableApi.quickSearchApi.runQuickSearch('toy');
expect(adaptableApi.quickSearchApi.getQuickSearchValue()).toBe('toy');

Note

Each test still needs a valid Initial Adaptable State — including a Layout section with at least one Layout, unless autoCreateLayout is set — see Default Layouts

Isolate State

By default AdapTable persists to localStorage under adaptableStateKey (which defaults to adaptableId). Shared persistence is the usual reason tests leak into each other.

Stub both loadState and persistState (provide them together so localStorage is not used on one side):

const adaptableOptions: AdaptableOptions = {
  primaryKey: 'id',
  adaptableId: 'layout-test',
  adaptableStateKey: `layout-test-${Date.now()}`,
  initialState,
  stateOptions: {
    loadState: () => Promise.resolve({}),
    persistState: () => Promise.resolve(),
  },
};

Note

  • Returning {} from loadState means each test starts from Initial State
  • Return a fixture object from loadState when the test should start from a known User State
  • Give each test its own adaptableStateKey (or adaptableId) if anything still writes to storage

Call adaptableApi.destroy() when the test finishes so the Grid and listeners are torn down.

afterEach(() => {
  adaptableApi?.destroy();
});

Asserting Something Changed

Prefer API getters after you invoked an API method.

When the change is triggered by UI or by another async path, subscribe to the Adaptable State Changed Event instead of polling:

const layoutChanged = new Promise<void>(resolve => {
  adaptableApi.eventApi.on(
    'AdaptableStateChanged',
    (info: AdaptableStateChangedInfo) => {
      if (info.actionName === 'LAYOUT_SELECT') {
        resolve();
      }
    }
  );
});

adaptableApi.layoutApi.setLayout('Cars');
await layoutChanged;

Hint

End-to-end Tests

Use Playwright (or similar) when the thing under test is the UI: a Dashboard button, a Settings Panel page, a Column Menu item.

Keep assertions on visible outcomes, not on AdapTable internals.

Hint

Where you already have adaptableApi in the page (for example from onAdaptableReady), you can still assert through the API after the click

Test Template

The AdapTable React Vitest Template is a complete, runnable repository that shows:

  • a minimal React + AG Grid + AdapTable setup
  • a Vitest configuration that handles AdapTable's async initialisation
  • example tests that wait for Adaptable Ready and then assert against the Adaptable API

Fork it as a starting point for your own test suite.

FAQ

Do I need a special AdapTable test package? No. Use your existing runner. The Adaptable API is the test surface.

Should each test use a different adaptableId? Use a unique adaptableStateKey (or stub loadState / persistState so nothing hits localStorage). A unique adaptableId also works, and makes console output easier to read.

Why do my tests affect each other? Almost always leftover localStorage, or a vanilla instance that was not destroyed. Stub persistence and tear down each instance.

Can I query the DOM instead of using the API? You can, but selectors against AdapTable internals are brittle. Use API for behaviour; use the DOM only for UI you own (custom toolbars, your wrappers) or true end-to-end coverage.

Do tests need license keys? Yes, the same as a running app. Without an AdapTable licenseKey the Grid shows a watermark and runs with reduced functionality — which will fail assertions that depend on those features.