Use when creating, updating, debugging, or reviewing Scout API tests in Kibana (apiTest/apiClient/requestAuth/samlAuth/apiServices), including auth choices, response assertions, and API service patterns.
<module-root>/test/scout*/api/{tests,parallel_tests}/**/*.spec.ts (examples: test/scout/api/..., test/scout_uiam_local/api/...).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-securityapiTest.describe(...) per file and avoid nested describe blocks; multiple top-level describes are supported, but files get hard to read quickly.{ tag: ... } on the suite (or individual tests) so CI/discovery can select the right test target. For solution modules, prefer explicit targets (e.g. [...tags.stateful.classic, ...tags.serverless.observability.complete] in Observability); reserve mainly for specs that truly need every deployment-agnostic target (see ). Unlike UI tests, API tests don’t currently validate tags at runtime.tags.deploymentAgnosticscout-migrate-from-ftr@ 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). Rephrase the title instead (e.g., use timestamp field instead of @timestamp).apiTest from <module-root>/test/scout*/api/fixtures to get module-specific extensions. Importing directly from the module’s Scout package is also fine when you don’t need extensions.apiTest (no page, browserAuth, pageObjects).import { apiTest, tags } from '@kbn/scout'; (or the module's Scout package, e.g. @kbn/scout-oblt)import { expect } from '@kbn/scout/api'; (or @kbn/scout-oblt/api, etc.) — not from the main entryimport type { RoleApiCredentials } from '@kbn/scout';expect is not exported from the main @kbn/scout entry. Use the /api subpath for API tests.api/* endpoints: use API keys via requestAuth (getApiKey, getApiKeyForCustomRole).internal/* endpoints: use cookies via samlAuth.asInteractiveUser(...).apiServices/kbnClient/esArchiver in beforeAll.beforeAll and reuse.apiClient and the right headers.statusCode and response body; verify side effects via apiServices/kbnClient when needed.Important: apiServices/kbnClient run with elevated privileges. Don’t use them to validate the endpoint under test (use apiClient + scoped auth).
Header reminders:
kbn-xsrf.x-elastic-internal-origin: kibana for Kibana APIs.elastic-api-version for versioned public APIs (e.g. '2023-10-31') or internal APIs (e.g. '1').apiClient methods (get, post, put, delete, patch, head) return { statusCode, body, headers }.@kbn/scout/api:
expect(response).toHaveStatusCode(200)expect(response).toHaveStatusText('OK')expect(response).toHaveHeaders({ 'content-type': 'application/json' })toBe, toStrictEqual, toMatchObject, etc.) and asymmetric matchers (expect.objectContaining(...), expect.any(String)) are also available.apiServices (no UI interactions). Use it for setup/teardown and verifying side effects, not for RBAC validation.<module-root>/test/scout*/api/services/<service>_api_service.ts (or similar). Register it by extending the module's apiServices fixture in <module-root>/test/scout*/api/fixtures/index.ts (prefer { scope: 'worker' } when the helper doesn't need per-test state).src/platform/packages/shared/kbn-scout/src/playwright/fixtures/scope/worker/apis/.When tests need custom auth helpers or API services, extend apiTest in the module's fixtures/index.ts:
import { apiTest as base } from '@kbn/scout'; // or the module's Scout package
import type { RequestAuthFixture } from '@kbn/scout';
interface MyApiFixtures {
requestAuth: RequestAuthFixture & { getMyPluginApiKey: () => Promise<RoleApiCredentials> };
}
export const apiTest = base.extend<MyApiFixtures>({
requestAuth: async ({ requestAuth }, use) => {
const getMyPluginApiKey = async () =>
requestAuth.getApiKeyForCustomRole({
kibana: [{ base: [], feature: { myPlugin: ['all'] }, spaces: ['*'] }],
});
await use({ ...requestAuth, getMyPluginApiKey });
},
});
Tests then import apiTest from the local fixtures: import { apiTest } from '../fixtures';
--config or --testFiles (they are mutually exclusive).node scripts/scout.js run-tests --arch stateful --domain classic --config <module-root>/test/scout*/api/playwright.config.ts (or .../api/parallel.playwright.config.ts for parallel API runs)playwright.config.ts vs parallel.playwright.config.ts): node scripts/scout.js run-tests --arch stateful --domain classic --testFiles <module-root>/test/scout*/api/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>.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=debugplugins.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-api-auth.mdapiServices helpers (kbnClient + retries + logging): references/scout-api-services.md