Use when creating, updating, debugging, or reviewing Scout UI tests in Kibana (Playwright + Scout fixtures), including page objects, browser authentication, parallel UI tests (spaceTest/scoutSpace), a11y checks, and flake control.
<module-root>/test/scout*/ui/tests/**/*.spec.ts.<module-root>/test/scout*/ui/parallel_tests/**/*.spec.ts and (recommended) use spaceTest + scoutSpace (one Kibana space per worker). If you run with workers > 1 but keep using test, you won't get space isolation.src/platform/** or x-pack/platform/** -> @kbn/scoutx-pack/solutions/observability/** -> @kbn/scout-obltx-pack/solutions/search/** -> @kbn/scout-searchx-pack/solutions/security/** -> @kbn/scout-securityimport { tags } from '@kbn/scout'; (or the module's Scout package)import { test } from '../fixtures'; (or import { test } from '@kbn/scout'; when not extending)import { expect } from '@kbn/scout/ui'; (or @kbn/scout-oblt/ui, etc.) — not from the main entryexpect is not exported from the main @kbn/scout entry. Use the /ui subpath for UI tests.test.describe(...) / spaceTest.describe(...), e.g. tags.deploymentAgnostic, tags.stateful.classic, or tags.performance).@ in test titles: Playwright treats @word in test/describe titles as tags. Do not use @ followed by word characters in titles (e.g., @timestamp, @elastic). This causes Scout tag validation to fail with "Unsupported tag(s) found". Rephrase the title instead (e.g., use timestamp field instead of @timestamp).test.describe(...) (sequential) or spaceTest.describe(...) (parallel) and avoid nested describe blocks where possible.apiServices/kbnClient/esArchiver in hooks over clicking through the UI.browserAuth — available methods: loginAsAdmin(), loginAsPrivilegedUser(), loginAsViewer(), loginAs(role), loginWithCustomRole(role).loginAsViewer() or loginWithCustomRole() over loginAsAdmin().loginAsAdmin() unless the test is explicitly about admin-only behavior.page.testSubj.locator(...), role/label locators; avoid brittle CSS.expect assertions in page objects — use waitForSelector for waiting on elements. Assertions belong in test specs only.page.route() mocks in a dedicated fixtures/mocks.ts file as standalone functions that accept page as a parameter. See cloud_security_posture/test/scout_cspm_agentless/ui/fixtures/mocks.ts for the reference pattern.apiServices/kbnClient in hooks instead).pageObjects fixture in test/scout*/ui/fixtures/index.ts.readonly class fields for static locators — assign them in the constructor, not as getter methods. Use methods only for parameterized locators/actions. See DashboardApp in kbn-scout for the reference pattern.EuiComboBoxWrapper, EuiDataGridWrapper, EuiSelectableWrapper, EuiCheckBoxWrapper, EuiFieldTextWrapper, EuiCodeBlockWrapper, EuiSuperSelectWrapper, EuiToastWrapper. Import them from @kbn/scout and use them as class members in page objects..first(), .nth(), .last() — the playwright/no-nth-methods lint rule flags these. Instead, use data-test-subj attributes or other targeted selectors. If the component lacks a data-test-subj, add one rather than disabling the rule.eslint-disable comments in test files. Fix the underlying issue (e.g., use targeted selectors instead of positional ones, add data-test-subj to the components) rather than suppressing the lint rule.spaceTest so you can access scoutSpace for worker-isolated saved objects + UI settings.parallel_tests/global.setup.ts via globalSetupHook(...).
page, browserAuth, pageObjects).afterAll (scoutSpace.savedObjects.cleanStandardList(), unset UI settings you set).Most modules extend the base test (or spaceTest) in test/scout*/ui/fixtures/index.ts to add custom page objects and auth helpers:
import { test as baseTest } from '@kbn/scout'; // or the module's Scout package
import type { ScoutTestFixtures, ScoutWorkerFixtures, ScoutPage } from '@kbn/scout';
class MyPluginPage {
constructor(private readonly page: ScoutPage) {}
async goto() { await this.page.gotoApp('myPlugin'); }
}
interface ExtendedFixtures extends ScoutTestFixtures {
pageObjects: ScoutTestFixtures['pageObjects'] & { myPlugin: MyPluginPage };
}
export const test = baseTest.extend<ExtendedFixtures, ScoutWorkerFixtures>({
pageObjects: async ({ pageObjects, page }, use) => {
await use({ ...pageObjects, myPlugin: new MyPluginPage(page) });
},
});
Tests then import from local fixtures: import { test } from '../fixtures';
test.step()Use test.step(...) to group related actions within a single test. Steps appear in Playwright's trace viewer and HTML report, making failures easier to debug without splitting into many small tests:
test('creates and verifies a dashboard', async ({ pageObjects, page }) => {
await test.step('create dashboard', async () => {
await pageObjects.dashboard.create('My Dashboard');
});
await test.step('verify dashboard appears in list', async () => {
await expect(page.testSubj.locator('dashboardTitle')).toHaveText('My Dashboard');
});
});
page.waitForTimeout. Wait on a page-ready signal (loading indicator hidden, container visible, expect.poll on element counts).data-test-subj (Scout uses it as the testIdAttribute).@kbn/eslint/scout_no_locators (e.g. globalLoadingIndicator). Don’t use them in tests or page objects for app loading state management; rely on Playwright auto-waiting and page-ready signals instead.page.checkA11y() at a few stable checkpoints (landing pages, modals/flyouts).include scoped checks; assert violations is empty.--config or --testFiles (they are mutually exclusive).node scripts/scout.js run-tests --arch stateful --domain classic --config <module-root>/test/scout*/ui/playwright.config.ts (or .../ui/parallel.playwright.config.ts for parallel UI)playwright.config.ts vs parallel.playwright.config.ts): node scripts/scout.js run-tests --arch stateful --domain classic --testFiles <module-root>/test/scout*/ui/tests/my.spec.tsnode scripts/scout.js start-server --arch stateful --domain classic [--serverConfigSet <configSet>], then run Playwright directly: npx playwright test --config <...> --project local --grep <tag> --headed.run-tests auto-detects custom config sets from .../test/scout_<name>/... paths.start-server has no Playwright config to inspect, so pass --serverConfigSet <name> when your tests require a custom config set.SCOUT_LOG_LEVEL=debug, or npx playwright test --config <...> --project local --uiplugins.enabled / packages.enabled in .buildkite/scout_ci_config.yml.node scripts/scout.js generate registers the module under enabled so the new configs run in CI.Open only what you need:
references/scout-browser-auth.mdspaceTest + scoutSpace) isolation + global setup rules: references/scout-ui-parallelism.md../scout-api-testing/references/scout-api-services.md