Page objects
Page objects wrap UI interactions (navigation, clicking, filling forms) so tests read like user workflows and stay maintainable as the UI evolves.
Keep page objects focused on UI interactions. Don’t hide API setup/teardown inside page objects—use API services or fixtures instead.
For practical tips, see best practices.
Page objects are exposed through the pageObjects fixture and are lazy-initialized:
import { tags } from '@kbn/scout';
import { test } from '../fixtures';
test.describe('My suite', { tag: tags.deploymentAgnostic }, () => {
test.beforeEach(async ({ browserAuth, pageObjects }) => {
await browserAuth.loginAsViewer();
await pageObjects.discover.goto();
});
});
- Core page objects:
@kbn/scout(available aspageObjects.<name>) - Solution Scout packages may provide additional page objects (their internal folder layout varies—search within the package for
page_objectsif you need the source). - Plugin-local page objects:
<plugin-root>/test/scout/ui/fixtures/page_objects
To make your page object available as pageObjects.newPage, register it in your plugin fixtures.
-
Create a plugin page object
Create a class that takes
ScoutPageand exposes locators + actions:import { ScoutPage } from '@kbn/scout'; export class NewPage { constructor(private readonly page: ScoutPage) {} async goto() { await this.page.gotoApp('myPlugin'); } }- replace with your app id
-
Register a plugin page object
Register it in
fixtures/page_objects/index.tsimport type { PageObjects, ScoutPage } from '@kbn/scout'; import { createLazyPageObject } from '@kbn/scout'; import { NewPage } from './new_page'; export type MyPluginPageObjects = PageObjects & { newPage: NewPage; }; export function extendPageObjects(pageObjects: PageObjects, page: ScoutPage): MyPluginPageObjects { return { ...pageObjects, newPage: createLazyPageObject(NewPage, page), }; } -
Wire it into your plugin
testfixtureIn
<plugin-root>/test/scout/ui/fixtures/index.ts, extend Scout’stestsopageObjectshas your extended type:import { test as base } from '@kbn/scout'; import type { MyPluginPageObjects } from './page_objects'; import { extendPageObjects } from './page_objects'; export const test = base.extend<{ pageObjects: MyPluginPageObjects }>({ pageObjects: async ({ pageObjects, page }, use) => { await use(extendPageObjects(pageObjects, page)); }, });Now your specs can use
pageObjects.newPagewithout importing the page object class directly.NoteIf your page object constructor needs extra arguments, pass them after
page:createLazyPageObject(NewPage, page, extraArg1, extraArg2).If you use
spaceTest(parallel UI suites), extend it the same way: importspaceTest as basefrom@kbn/scout, thenexport const spaceTest = base.extend<{ pageObjects: MyPluginPageObjects }>(...).