Skip to main content

Automating UI Tests in Toolio

Write stable Playwright or Cypress tests against Toolio using the data-testid hooks Toolio commits to keep.

If your team runs automated browser tests against Toolio, build them on test ids: data-testid attributes that Toolio adds to the controls a test needs to click, read, or wait for. The ids listed on a module's selector page are a published contract. We don't rename or remove one without notice.

Everything else on the page can change in any release, including CSS classes, button labels, icons, and layout. Tests that depend on those may break without warning.

Use Cases

  • Regression suites that load a plan, apply filters, edit values, and save.

  • Smoke tests that run against a preprod workspace after each Toolio release.

  • AI coding agents that write or repair tests for your team.

Which Ids Are Covered

Each module that supports automation has its own selector page in this collection. Today that is Merchandise Plan Selectors, which covers the Merchandise Plan planning view.

You may find other data-testid attributes while inspecting Toolio. Those are internal: they can change in any release, so treat them like CSS classes.

💡 Playwright's page.getByTestId() reads data-testid by default, so no configuration is needed. In Cypress, use cy.get('[data-testid="load-data-button"]').

Signing In From a Test

Use an API key instead of a shared password. Your test exchanges the key for a session cookie once, then drives the browser as a signed-in user. The steps are in Toolio API Keys, under Using an API Key for Headless Regression Tests.

Writing Locators

The patterns below solve the problems most suites hit in their first week. The examples use Playwright.

Scope Shared Controls to a Container

Controls such as Load Data, Filters, and the timeframe button are shared components, so the same id can appear more than once on a page. For example, the Seed dialog in the Merchandise Plan has its own Filters button. Playwright's strict mode fails a locator that matches more than one element, hidden ones included.

Start from the container the module page lists, then find the control inside it:

await page.getByTestId("mfp-toolbar").getByTestId("filter-toolbar-button").click();
await page.getByTestId("seed-plan-dialog").getByTestId("filter-toolbar-button").click();

Pick a Row by Its Key

Repeated elements such as filter rows and scenario options carry a second attribute, data-test-key, that tells them apart. The module page says what each key holds.

const row = page.locator('[data-testid="filter-row"][data-test-key="department"]');
await row.getByTestId("filter-remove-button").click();

Type Into Inputs

Input ids sit on the field wrapper, not on the <input> itself. Target the input inside the wrapper:

await page.getByTestId("scenario-search-input").locator("input").fill("Plan");

Match the Visible Menu

Menus and popups open in a layer at the end of the page, outside the toolbar that opened them, so find them from page, not from the toolbar container. Once opened, they stay in the page, hidden, after they close. Match the visible one:

await page.locator('[data-testid="timeframe-menu"]:visible').waitFor();

Wait for Data to Load

Grids that support it set aria-busy="true" while data loads and aria-busy="false" when it is ready. Wait for that instead of a fixed timeout:

await page.getByTestId("mfp-toolbar").getByTestId("load-data-button").click();
await expect(page.getByTestId("mfp-grid")).toHaveAttribute("aria-busy", "false");

Handle the Browser's Own Confirmation

Some actions, like leaving a page with unsaved edits, open the browser's native confirmation instead of a Toolio dialog. It has no test id. Handle it with a dialog listener registered before the action:

page.once("dialog", (dialog) => dialog.accept());

Fill In Date Filters

Date filters have two parts: a mode select (for example Within or Is before) and a value. The mode select has no test id, so find it inside the filter row by its role or label. filter-value-input marks the value control that appears after you choose a mode.

Ids That Mark a Popup

A few internal ids sit on the popup a button opens, not on the button. Click the button by its role or label, then scope to the popup:

Test id

Popup

dashboard-filters

Dashboard filters

widget-query-date-range

Date range of a dashboard widget query

widget-query-filters

Filters of a dashboard widget query

assortment-edit-time-frame

Timeframe in the Assortment edit dialog

usage-filter-menu

Filters on the Change History usage page

behavior-metric-menu

Metric picker in Metric Rule Sets

These ids are not part of a module contract yet.

Keep the Intercom Messenger Out of the Way

The Toolio support messenger can open popups over the controls under test. Block its script for the test run:

await context.route(/widget\.intercom\.io|js\.intercomcdn\.com/, (route) => route.abort());

Using an AI Agent

If an AI coding agent writes or maintains your tests, give it the rules up front. Add a short section like this to your test repo's AGENTS.md or CLAUDE.md:

## Toolio selectors
- Use only data-testid values listed on the Toolio selector pages (help.toolio.com, Test Automation collection).
- Never select by CSS class, label text, or DOM position.
- Scope shared controls to their container: getByTestId("mfp-toolbar").getByTestId("load-data-button").
- Menus and popups: match the :visible one, from page, not from the toolbar.
- After Load Data, wait for aria-busy="false" on the grid.

Changes to the Contract

We add ids freely and list them on the module page. We rename or remove a listed id only with notice: the change is logged in the table below, with its date, before it ships.

Date

Module

Change

Oct 2026

Merchandise Plan

First version. The clear icon on the Filters button is now filter-clear-all-button (was toolbar-button-clear).

FAQs

Why does my locator match two elements?

The control is a shared component that appears in more than one place, such as a toolbar and a dialog. Scope it to the container listed on the module page.

Are the ids the same in preprod and production?

Yes. Test ids ship in every Toolio build, so a suite written against your preprod workspace runs unchanged in production.

Can I target individual grid cells?

Grid cells are not covered by test ids. Use the grid's column ids and row index, and expect those to follow your plan's layout.

Can I ask for a new test id?

Yes. Contact Customer Support with the screen and the action your test needs. New ids are listed on the module page once they ship.

Did this answer your question?