EUI test helpers
@elastic/eui-test-helpers provides helpers for interacting with EUI components reliably in consumer tests, so you stop guessing at CSS selectors that only seem right. For Scout/Playwright consumers it ships Component Objects: semantic wrappers around a single Playwright Locator that encapsulate user-like interactions for a specific EUI component.
The package lives in the elastic/eui monorepo (packages/test-helpers) but was inspired by, and is consumed through, Scout.
Use the built-in methods your test framework provides for basic, native-like components. Reach for a Component Object only when a component is non-trivial to drive reliably (portals, virtualization, async state).
Component Objects are exposed pre-bound to the page through the page.components factory. You don't construct them yourself:
import { test } from '../fixtures';
test('selects a data view', async ({ page }) => {
const comboBox = page.components.comboBox('dataViewSelector');
await comboBox.setSelectedOptions(['logs-*']);
expect(await comboBox.getSelectedOptions()).toEqual(['logs-*']);
});
Each factory takes the component's root data-test-subj and an optional scope (a Locator or another Component Object) to target an instance inside a specific subtree:
const comboBox = page.components.comboBox('dataViewSelector', someFlyout);
- In scope: enabling consumer end-to-end tests to set up and tear down component state reliably, so the test can focus on its actual assertion instead of navigating EUI's DOM.
- Out of scope: testing EUI component behavior. EUI already has RTL unit tests, Cypress E2E tests, and Loki VRT tests for that. A method added only to exercise an EUI feature (e.g. "click the clear button to verify
onChangefires") belongs in EUI's own suite. The package's validation tests prove the helper itself works; they don't substitute for EUI's tests.
Each Component Object targets one EUI component: page.components.comboBox drives an EuiComboBox only. Pointing it at a different component that happens to share the same data-test-subj (e.g. an EuiSelectable) fails on purpose, since the helper validates the component type internally. Unlike some FTR helpers, it won't silently operate on the wrong component, something to watch for when migrating.
The full contributor journey is: prototype in Scout, validate against Kibana, port to EUI, then publish. Prototyping in Kibana first means you exercise the helper against the real DOM it must support, not a curated Storybook story.
-
Prototype the Component Object in
kbn-scoutBuild the object in Kibana, iterating against real specs, before porting it to EUI:
- Add it under
src/platform/packages/shared/kbn-scout/src/playwright/eui_components/. - Register it on the
page.componentsfactory so specs callpage.components.<name>(testSubj). - Write or convert the Scout specs that use it and run them locally.
- Add it under
-
Validate against Kibana in CI
Local runs cover only a slice. Open a draft Kibana PR and run CI to confirm the specs that use the helper pass across every stateful/serverless lane.
Read first-attempt failures, not only the final status. Scout retries a failed spec once, so a lane can be green overall while its first attempt failed. A first-attempt failure in a spec that uses your helper often points to helper flakiness (a race the retry hides). Fix it before publishing.
-
Port to EUI
Once proven, move the object into
packages/test-helpersinelastic/euiwith itsselectors.ts, validation specs, and a component README, following the package's CONTRIBUTING guide. Open the EUI PR. -
Re-validate via a snapshot and publish
See Validate against Kibana before publishing below.
When authoring the object, follow the design principles, directory structure, and spec conventions in the package CONTRIBUTING guide. It's the source of truth for how helpers are structured and kept stable against the evolving EUI DOM.
To run the published helper through Kibana CI you need a snapshot, a prerelease published to the npm registry:
- Nightly: EUI auto-publishes a snapshot on weekdays under the
snapshotdist-tag. Pin Kibana's@elastic/eui-test-helpersto that exact version. - On demand: label your EUI PR
ci:regression-integration-test-kibanato build a snapshot from the PR head and kick off the Kibana integration chain.
The on-demand label publishes an npm snapshot using EUI's trusted credentials and builds the exact commit at the PR head. Only add it to your own PRs, and only after you have reviewed and trust that exact commit. Snapshots are moving prereleases and get pruned, so never merge a Kibana PR on a snapshot pin. Repin to the official release before merging.
@elastic/eui and @elastic/eui-test-helpers are two packages in one monorepo with independent versions. Kibana pins each separately in package.json, so a helper release can ship without an EUI release and the other way round. Three checks keep the three moving parts compatible:
- On every EUI PR, the helper validation specs run against Storybook. A PR that touches an EUI component also runs the specs of the matching helper (correlated by directory path), so a DOM change that would break a helper fails the EUI PR, not a Kibana test later. See CI integration.
- Every weeknight, EUI publishes snapshots of both packages, opens a draft Kibana PR titled
[DO NOT MERGE][EUI] Nightly Buildthat bumps Kibana to them, and runs full Kibana CI. This answers "will today's EUImainbreak Kibana?" before anything is released. Source:update_kibana_dependencies.yml. - On release, an EUI maintainer opens the Kibana upgrade PR with the official versions. Because the nightly already ran against the same code, that PR is expected to be a clean version bump.
If an EUI or helper change needs a matching Kibana change (a removed export, a renamed selector key, a snapshot update), the author of the EUI change prepares it ahead of the release:
- Open a Kibana PR with the fix pinned to a snapshot that contains the EUI change, so its CI can run. Keep the code change and the version pin in separate commits.
- Add the code commit's URL under
@nextinpackages/release-cli/kibana-prep-commitsinelastic/eui, ideally in the same EUI PR. - The nightly and the release upgrade PR cherry-pick every commit in that list. On release,
@nextmoves to@previousso the nightly stays green until the upgrade PR merges.
The Kibana PR is a reference and is closed once the upgrade PR lands. Details and commit conventions: Testing EUI features in Kibana.
- Helper spec fails on an EUI PR: the component change broke the helper. Fix the helper in the same PR, or the component change is not mergeable.
- Nightly Kibana build is red: an unreleased EUI or helper change breaks Kibana. Either the change needs a prep commit (above), or the change itself needs fixing before Monday's release. The EUI team is notified in Slack.
- CI fails on the Kibana upgrade PR: the release contains something the nightly did not catch, for example a prep commit that was never registered or Kibana code that changed after the last nightly. Fix it in the upgrade PR.
Publishing is deliberately gated: merging to EUI main does not publish anything.
- Snapshots are the automated part: nightly on weekdays, plus on demand via the label above.
- Official releases are run by an EUI maintainer, roughly weekly. There is no cron. A package publishes only if it is included in the release run, so
@elastic/eui-test-helpersmust be explicitly included. If your change needs to ship, ping the EUI maintainers to include the package in the next release.
- Page objects: Kibana-app interaction wrappers (Component Objects are the EUI-component-level equivalent).
- UI testing and UI test best practices.
@elastic/eui-test-helperspackage and its CONTRIBUTING guide.- Testing EUI features in Kibana and EUI test helpers CI in the EUI wiki.