x-pack/solutions/security/packages/kbn-scout-security/README.md
kbn/scout-security is a test library that extends kbn/scout with test helpers specifically designed for Security Solution features in Kibana.
Its primary goal is to simplify the test development experience for teams working on Security Solution plugins by providing custom Playwright fixtures, page objects, and utilities tailored for Security Solution related testing scenarios.
kbn-scout-security extends from kbn-scout framework providing the same advantages:
The @kbn/scout-security structure includes the following key directories and files:
x-pack/solutions/security/packages/kbn-scout-security/
├── src/
│ ├── playwright/
│ │ └── constants/
│ │ └── fixtures/
│ │ │ └── test/
│ │ │ │ └── // Security Solution test-scope fixtures
| | | | └── page_objects/
| | | | └── // Security Solution pages that can be reused through the different plugins
│ │ │ └── worker/
│ │ │ │ └── // Security Solution worker-scope fixtures
│ │ │ └── single_thread_fixtures.ts
│ │ │ └── parallel_run_fixtures.ts
│ │ │ └── index.ts
| | | └── types.ts
│ └── index.ts
├── README.mk
├── index.ts
├── jest.config.js
├── kibana.jsonc
├── package.json
├── tsconfig.json
playwright directory manages the default Playwright configuration. It exports the createPlaywrightConfig function, which is used by Kibana plugins to define Scout playwright configurations and serves as the entry point to run tests.
import { createPlaywrightConfig } from '@kbn/scout';
// eslint-disable-next-line import/no-default-export
export default createPlaywrightConfig({
testDir: './tests',
workers: 2,
});
Scout relies on configuration to determine the test files and opt-in parallel test execution against the single Elastic cluster.
The Playwright configuration should only be created this way to ensure compatibility with Scout functionality. Note that config files should be used inside the plugin we want to test.
The fixtures directory contains core Security Scout capabilities required for testing the majority of Security Solution functionalities. Fixtures can be scoped to either test or worker. Scope decides when to init a new fixture instance: once per worker or for every test function. It is important to choose the correct scope to keep test execution optimally fast: if a new instance is not needed for every test, the fixture should be scoped to worker. Otherwise, it should be scoped to test.
Security Solution worker scoped fixtures:
detectionRuleApitest.beforeAll(async ({ detectionRuleApi }) => {
await detectionRuleApi.createCustomQueryRule(CUSTOM_QUERY_RULE);
});
Security Solution test scoped fixtures:
browserAuthpageObjectstest.beforeEach(async ({ browserAuth }) => {
await browserAuth.loginAsPlatformEngineer();
});
If a new fixture depends on a fixture with a test scope, it must also be test scoped.
The page_objects directory contains all the Page Objects that represent Security Solution core functionality that can be reused through different Security Solution plugins.
If a Page Object is likely to be used in more than one plugin, it should be added here. This allows other teams to reuse it, improving collaboration across teams, reducing code duplication, and simplifying support and adoption.
If a Page Object can be used outside Security Solution, it should be created in @kbn-scout.
Page Objects must be registered with the createLazyPageObject function, which guarantees its instance is lazy-initialized. This way, we can have all the page objects available in the test context, but only the ones that are called will be actually initialized:
export function extendPageObjects(pageObjects: PageObjects, page: ScoutPage): SecurityPageObjects {
return {
...pageObjects,
alertsTablePage: createLazyPageObject(AlertsTablePage, page),
alertDetailsRightPanelPage: createLazyPageObject(AlertDetailsRightPanelPage, page),
};
}
All registered Page Objects are available via the pageObjects fixture:
test.beforeEach(async ({ pageObjects }) => {
await pageObjects.alertsTablePage.navigate();
});
To start the servers without running tests, use the following command:
node scripts/scout.js start-server --arch [stateful|serverless] --domain security_complete
This is useful for manual testing or running tests via an IDE.
To start the servers and run tests, use:
node scripts/scout.js run-tests --arch [stateful|serverless] --domain security_complete --config <plugin-path>/test/scout/ui/[playwright.config.ts|parallel.playwright.config.ts]
This command starts the required servers and then automatically executes the tests using Playwright.
If the servers are already running, you can execute tests independently using either:
npx playwright test --config <plugin-path>/test/scout/ui/[playwright.config.ts|parallel.playwright.config.ts] --project local
We use project flag to define test target, where tests to be run: local servers or Elastic Cloud. Currently we only support local servers.
Any new test should be added in the x-pack/solutions/security/plugins/security_solution/test/scout/ui folder.
You have an example in: x-pack/solutions/security/plugins/security_solution/test/scout/ui/parallel_tests/flyout/alert_details_url_sync.spec.ts
export class NewPage {
constructor(private readonly page: ScoutPage) {}
// implementation
}
export function createCorePageObjects(page: ScoutPage): PageObjects {
return {
...
newPage: createLazyPageObject(NewPage, page),
};
}
Determine Fixture Scope: Decide if your fixture should apply to the test (per-test) or worker (per-worker) scope.
Implement the Fixture: Add the implementation to src/playwright/fixtures/test or src/playwright/fixtures/worker.
You can use the existing fixtures as a guide.
src/playwright/fixtures/parallel_run_fixtures.ts and/or src/playwright/fixtures/single_thread_fixture.ts