diff --git a/.agent/skills/ftr-testing/SKILL.md b/.agent/skills/ftr-testing/SKILL.md new file mode 100644 index 0000000000000..f683065778dc7 --- /dev/null +++ b/.agent/skills/ftr-testing/SKILL.md @@ -0,0 +1,75 @@ +--- +name: FTR Testing +description: Use when creating, updating, debugging, or reviewing Kibana Functional Test Runner (FTR) tests, including test structure, services/page objects, loadTestFile patterns, tags, and how to run FTR locally. +--- + +# FTR Testing + +## Overview +FTR (FunctionalTestRunner) runs Kibana UI functional tests written in mocha with `@kbn/expect`. Core principle: use FTR services/page objects for interactions, keep tests organized by config, and understand loadTestFile-driven suites. + +## Core workflow + +1. Identify the FTR config and test file location. + - FTR suites live under `test/**` or `x-pack/**/test/**` with config files. +2. Understand the test structure. + - Tests export a provider function that defines a mocha suite. + - Use `describe/it/before/beforeEach/after/afterEach`. +3. Use services and page objects. + - Services provide shared capabilities (browser, testSubjects, retry, esArchiver). + - Services are named singletons created from `FtrService` subclasses. + - Page objects wrap UI interactions. +4. Watch for `loadTestFile` usage. + - Index files can load multiple suites with shared setup. +5. Use tags in `describe()` to control CI grouping and skips. +6. If unfamiliar with a page, run the existing FTR tests to learn the flow before migrating. + +## Quick reference + +- Run all-in-one: `node scripts/functional_tests` +- Run server + tests: + - `node scripts/functional_tests_server` + - `node scripts/functional_test_runner --config ` +- Common services: `browser`, `testSubjects`, `retry`, `esArchiver`, `kibanaServer`. +- Page objects and services are fetched via `getPageObjects()` / `getService()`. + +## Common patterns + +### loadTestFile + +```ts +export default ({ loadTestFile }: FtrProviderContext) => { + describe('suite', () => { + loadTestFile(require.resolve('./pages/rules_page')); + }); +}; +``` + +Notes: +- Index files often include shared setup/teardown; it applies to every loaded suite. +- When migrating, each `loadTestFile` target becomes its own Scout spec and shared setup + must be duplicated or refactored into fixtures/helpers. + +### Services and page objects + +```ts +export default ({ getService, getPageObjects }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + const pageObjects = getPageObjects(['header', 'common']); + + describe('My suite', () => { + it('does something', async () => { + await pageObjects.common.navigateToApp('home'); + await testSubjects.existOrFail('homeApp'); + expect(await browser.getCurrentUrl()).toContain('home'); + }); + }); +}; +``` + +## Common mistakes + +- Adding UI logic directly in tests instead of using services/page objects. +- Ignoring `loadTestFile` shared setup in index files. +- Running with the wrong config file (stateful vs serverless). diff --git a/.agent/skills/scout-api-testing/SKILL.md b/.agent/skills/scout-api-testing/SKILL.md new file mode 100644 index 0000000000000..a686d9fed4fce --- /dev/null +++ b/.agent/skills/scout-api-testing/SKILL.md @@ -0,0 +1,107 @@ +--- +name: Scout API Testing +description: 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. +--- + +# Scout API Testing + +## Core rules (API) + +- API specs live in `/test/scout*/api/{tests,parallel_tests}/**/*.spec.ts` (examples: `test/scout/api/...`, `test/scout_uiam_local/api/...`). +- Use the Scout package that matches the module root: +- `src/platform/**` or `x-pack/platform/**` -> `@kbn/scout` +- `x-pack/solutions/observability/**` -> `@kbn/scout-oblt` +- `x-pack/solutions/search/**` -> `@kbn/scout-search` +- `x-pack/solutions/security/**` -> `@kbn/scout-security` +- Prefer a single top-level `apiTest.describe(...)` per file and avoid nested `describe` blocks; multiple top-level `describe`s are supported, but files get hard to read quickly. +- Tags: add `{ tag: ... }` on the suite (or individual tests) so CI/discovery can select the right deployment target (for example `tags.DEPLOYMENT_AGNOSTIC` or `['@ess']`). Unlike UI tests, API tests don’t currently validate tags at runtime. +- If the module provides Scout fixtures, import `apiTest` from `/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. +- Browser fixtures are disabled for `apiTest` (no `page`, `browserAuth`, `pageObjects`). + +## Imports + +- Test framework + tags: `import { apiTest, tags } from '@kbn/scout';` (or the module's Scout package, e.g. `@kbn/scout-oblt`) +- Assertions: `import { expect } from '@kbn/scout/api';` (or `@kbn/scout-oblt/api`, etc.) — **not** from the main entry +- Types: `import type { RoleApiCredentials } from '@kbn/scout';` +- `expect` is **not** exported from the main `@kbn/scout` entry. Use the `/api` subpath for API tests. + +## Auth: pick based on endpoint + +- `api/*` endpoints: use **API keys** via `requestAuth` (`getApiKey`, `getApiKeyForCustomRole`). +- `internal/*` endpoints: use **cookies** via `samlAuth.asInteractiveUser(...)`. + +## Recommended test shape + +1. **Prepare** environment (optional): `apiServices`/`kbnClient`/`esArchiver` in `beforeAll`. +2. **Authenticate** (least privilege): generate credentials in `beforeAll` and reuse. +3. **Request**: call the endpoint with `apiClient` and the right headers. +4. **Assert**: verify `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: +- State-changing requests usually need `kbn-xsrf`. +- Prefer sending `x-elastic-internal-origin: kibana` for Kibana APIs. +- Include `elastic-api-version` for versioned public APIs (e.g. `'2023-10-31'`) or internal APIs (e.g. `'1'`). + +## Assertions + +- `apiClient` methods (`get`, `post`, `put`, `delete`, `patch`, `head`) return `{ statusCode, body, headers }`. +- Use the custom matchers from `@kbn/scout/api`: + - `expect(response).toHaveStatusCode(200)` + - `expect(response).toHaveStatusText('OK')` + - `expect(response).toHaveHeaders({ 'content-type': 'application/json' })` +- Standard matchers (`toBe`, `toStrictEqual`, `toMatchObject`, etc.) and asymmetric matchers (`expect.objectContaining(...)`, `expect.any(String)`) are also available. + +## API services + +- Put reusable server-side helpers behind `apiServices` (no UI interactions). Use it for setup/teardown and verifying side effects, not for RBAC validation. +- **Module-local service**: create it under `/test/scout*/api/services/_api_service.ts` (or similar). Register it by extending the module's `apiServices` fixture in `/test/scout*/api/fixtures/index.ts` (prefer `{ scope: 'worker' }` when the helper doesn't need per-test state). +- **Shared service** (reused across modules): consider contributing it to the Scout packages under `src/platform/packages/shared/kbn-scout/src/playwright/fixtures/scope/worker/apis/`. + +## Extending fixtures + +When tests need custom auth helpers or API services, extend `apiTest` in the module's `fixtures/index.ts`: + +```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 }; +} + +export const apiTest = base.extend({ + 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';` + +## Parallelism + +- Treat Scout API tests as sequential by default. Parallel API runs require manual isolation (spaces, indices, saved objects) and are uncommon. + +## Run / debug quickly + +- Use either `--config` or `--testFiles` (they are mutually exclusive). +- Run by config: `node scripts/scout.js run-tests --stateful --config /test/scout*/api/playwright.config.ts` (or `.../api/parallel.playwright.config.ts` for parallel API runs) +- Run by file/dir (Scout derives the right `playwright.config.ts` vs `parallel.playwright.config.ts`): `node scripts/scout.js run-tests --stateful --testFiles /test/scout*/api/tests/my.spec.ts` +- For faster iteration, start servers once in another terminal: `node scripts/scout.js start-server --stateful [--config-dir ]`, then run Playwright directly: `npx playwright test --config <...> --project local --grep `. +- `--config-dir` notes: +- `run-tests` auto-detects the custom config dir from `.../test/scout_/...` paths (override with `--config-dir ` if needed). +- `start-server` has no Playwright config to inspect, so pass `--config-dir ` when your tests require a custom server config. +- Debug: `SCOUT_LOG_LEVEL=debug` + +## References + +Open only what you need: + +- requestAuth vs samlAuth, headers, and least-privilege auth tips: `references/scout-api-auth.md` +- Creating and registering `apiServices` helpers (kbnClient + retries + logging): `references/scout-api-services.md` diff --git a/.agent/skills/scout-api-testing/references/scout-api-auth.md b/.agent/skills/scout-api-testing/references/scout-api-auth.md new file mode 100644 index 0000000000000..df44610b992bf --- /dev/null +++ b/.agent/skills/scout-api-testing/references/scout-api-auth.md @@ -0,0 +1,87 @@ +# Scout API Test Authentication (requestAuth vs samlAuth) + +Use this when writing API tests with `apiTest`/`apiClient`, especially when validating RBAC. + +## Pick an auth method + +- `api/*` endpoints: use API keys via `requestAuth`. +- `internal/*` endpoints: use cookies via `samlAuth.asInteractiveUser(...)`. + +Both methods return headers you spread into `apiClient` requests. + +## API key auth (requestAuth) + +- `requestAuth.getApiKey(roleName)` +- `requestAuth.getApiKeyForCustomRole(roleDescriptor)` + +```ts +import type { RoleApiCredentials } from '@kbn/scout'; // or the module's Scout package (e.g. @kbn/scout-oblt) +import { apiTest, tags } from '@kbn/scout'; // or the module's Scout package +import { expect } from '@kbn/scout/api'; // or '@kbn/scout-oblt/api', etc. + +const COMMON_HEADERS = { + 'kbn-xsrf': 'scout', + 'x-elastic-internal-origin': 'kibana', + 'elastic-api-version': '2023-10-31', // include for versioned public APIs +}; + +apiTest.describe('GET /api/my_plugin/foo', { tag: tags.DEPLOYMENT_AGNOSTIC }, () => { + let viewer: RoleApiCredentials; + + apiTest.beforeAll(async ({ requestAuth }) => { + viewer = await requestAuth.getApiKey('viewer'); + }); + + apiTest('works', async ({ apiClient }) => { + const response = await apiClient.get('api/my_plugin/foo', { + headers: { ...COMMON_HEADERS, ...viewer.apiKeyHeader }, + responseType: 'json', + }); + + expect(response).toHaveStatusCode(200); + expect(response.body).toStrictEqual(expect.objectContaining({ id: expect.any(String) })); + }); +}); +``` + +## Cookie auth (samlAuth) for internal endpoints + +```ts +import { apiTest, tags } from '@kbn/scout'; // or the module's Scout package +import { expect } from '@kbn/scout/api'; // or '@kbn/scout-oblt/api', etc. + +const INTERNAL_HEADERS = { + 'kbn-xsrf': 'scout', + 'x-elastic-internal-origin': 'kibana', +}; + +apiTest.describe('GET /internal/my_plugin/foo', { tag: tags.DEPLOYMENT_AGNOSTIC }, () => { + apiTest('calls internal endpoint', async ({ apiClient, samlAuth }) => { + const { cookieHeader } = await samlAuth.asInteractiveUser('viewer'); + + const response = await apiClient.get('internal/my_plugin/foo', { + headers: { ...INTERNAL_HEADERS, ...cookieHeader }, + responseType: 'json', + }); + + expect(response).toHaveStatusCode(200); + }); +}); +``` + +## API assertions (`@kbn/scout/api`) + +Import `expect` from `@kbn/scout/api` (or `@kbn/scout-/api`). It provides custom matchers on top of standard ones: + +- `expect(response).toHaveStatusCode(200)` — assert HTTP status code. +- `expect(response).toHaveStatusText('OK')` — assert HTTP status text. +- `expect(response).toHaveHeaders({ 'content-type': 'application/json' })` — assert response headers. +- Standard matchers like `toBe`, `toStrictEqual`, `toBeDefined`, `toMatchObject` are also available. +- Asymmetric matchers: `expect.objectContaining(...)`, `expect.any(String)`, `expect.toBeGreaterThan(0)`, etc. + +`apiClient` methods (`get`, `post`, `put`, `delete`, `patch`, `head`) return `{ statusCode, body, headers }`. + +## Tips + +- Generate credentials in `beforeAll` if reused across tests. +- Prefer custom roles for permission-boundary tests instead of `admin`. diff --git a/.agent/skills/scout-api-testing/references/scout-api-services.md b/.agent/skills/scout-api-testing/references/scout-api-services.md new file mode 100644 index 0000000000000..5c5cc333354c1 --- /dev/null +++ b/.agent/skills/scout-api-testing/references/scout-api-services.md @@ -0,0 +1,66 @@ +# Scout API Services + +API services provide server-side helpers through the `apiServices` fixture. +Keep API services strictly server-side (no UI interactions). +Import helper utilities (like `measurePerformanceAsync`) from the Scout package used by the module (`@kbn/scout` or the relevant solution package). + +## Create a new API service (summary) + +1. Add a new service file under the API fixtures directory. +2. Add a `types.ts` file for request/response types when the API is non-trivial. +3. Export a helper function that accepts `log` and `kbnClient` and uses + `kbnClient.request` with retries (and `ignoreErrors` when needed). +4. Wrap calls with `measurePerformanceAsync` for consistent logging. +5. Register the service in the API fixtures index so it appears under + `apiServices.`. + +## Minimal sketch + +```ts +import type { KbnClient, ScoutLogger } from '@kbn/scout'; // or the module's Scout package (e.g. @kbn/scout-security) +import { measurePerformanceAsync } from '@kbn/scout'; // or the module's Scout package + +export interface MyApiService { + enable: () => Promise; +} + +export const getMyApiService = ({ + log, + kbnClient, +}: { + log: ScoutLogger; + kbnClient: KbnClient; +}): MyApiService => { + return { + enable: async () => { + await measurePerformanceAsync(log, 'myService.enable', async () => { + await kbnClient.request({ + method: 'POST', + path: '/api/my/endpoint', + retries: 3, + }); + }); + }, + }; +}; +``` + +Register it in the fixture so tests can call: + +```ts +await apiServices.myService.enable(); +``` + +When adding a module-local API service, extend the `apiServices` fixture (prefer worker scope) and merge in the new +service: + +```ts +apiServices: async ({ apiServices, kbnClient, log }, use) => { + const extended = { + ...apiServices, + myService: getMyApiService({ kbnClient, log }), + }; + + await use(extended); +} +``` diff --git a/.agent/skills/scout-best-practices-reviewer/SKILL.md b/.agent/skills/scout-best-practices-reviewer/SKILL.md new file mode 100644 index 0000000000000..b64e8aa5acd30 --- /dev/null +++ b/.agent/skills/scout-best-practices-reviewer/SKILL.md @@ -0,0 +1,18 @@ +--- +name: Scout Best Practices Reviewer +description: Use when writing and reviewing Scout UI and API test files. +--- + +# Scout Best Practices Reviewer + +## Overview + +- Identify whether the spec is **UI** (`test`/`spaceTest`) or **API** (`apiTest`) and review against the relevant best practices. +- Keep feedback concise and actionable: focus on correctness, flake risk, and CI/runtime impact. +- Report findings ordered by severity and include the matching best-practice heading (from the reference) next to each finding. + +## References + +Open only what you need: + +- Review checklist (tagging, structure, auth, flake control): `references/scout-best-practices.md` diff --git a/.agent/skills/scout-best-practices-reviewer/references/scout-best-practices.md b/.agent/skills/scout-best-practices-reviewer/references/scout-best-practices.md new file mode 100644 index 0000000000000..87ca830c0b4a8 --- /dev/null +++ b/.agent/skills/scout-best-practices-reviewer/references/scout-best-practices.md @@ -0,0 +1,108 @@ +# Scout Best Practices + +## Decide UI vs API + +- **UI tests** validate user-visible behavior and critical interactions. +- **API tests** validate response contracts and backend side effects. +- Avoid asserting detailed data correctness via the UI. Prefer an API test (and keep UI tests thin). + +## File Structure (Applies to UI + API) + +- Prefer one top-level `*.describe(...)` per file and keep nesting shallow. Multiple `describe` blocks are supported, but large/deep suites get hard to debug and maintain. +- Keep suites independent. Do not rely on file execution order. +- Organize by **role** and **user flow** (not by feature area alone). + +## Tagging (Applies to UI + API) + +- UI tests: tags are required and validated at runtime. Ensure each test has at least one supported tag (typically by tagging the top-level `test.describe(...)` / `spaceTest.describe(...)`). +- API tests: tags aren’t currently validated at runtime, but add `{ tag: ... }` to suites/tests so CI/discovery can select the right deployment target (stateful vs serverless). +- Prefer using `tags.*` constants (for example `tags.DEPLOYMENT_AGNOSTIC`, `tags.ESS_ONLY`) to avoid typos and to align with Scout’s supported tags. + +## Setup / Teardown (Applies to UI + API) + +- Put cleanup in `afterEach/afterAll`, not the test body. +- Prefer API-based setup/teardown (`apiServices`/`kbnClient`/`esArchiver`) over clicking through the UI. + +### Global Setup Hook + +- Use `global.setup.ts` + `globalSetupHook(...)` for one-time setup shared across many files. +- Only **worker-scoped** fixtures are available in global setup (no `page`, `browserAuth`, `pageObjects`). + +## Auth + Least Privilege + +### UI auth + +- Use `browserAuth` (no manual UI login flows). +- Prefer least privilege (`viewer`, `loginAsPrivilegedUser`, `loginWithCustomRole`). +- Avoid `admin` unless the test is explicitly about admin-only behavior. + +### API auth + +- `api/*` endpoints: `requestAuth` (API key) via `getApiKey()` / `getApiKeyForCustomRole()`. +- `internal/*` endpoints: `samlAuth.asInteractiveUser(...)` (cookie auth). + +## UI Tests + +### Page Objects + +- Put selectors + UI actions in page objects; keep assertions in the spec. +- No API calls from page objects. +- Prefer extending the existing Scout/solution page objects over creating a new ad-hoc one. + +### Imports + +- Import `expect` from the `/ui` subpath (`@kbn/scout/ui` or `@kbn/scout-/ui`), never from the main entry. + +### Locators + Selectors + +- Prefer `page.testSubj.locator(...)`, role/label locators. +- Add `data-test-subj` to product code when a selector is unstable. + +### Waiting + Flake Control + +- Don’t use `waitForTimeout`. +- Wait on stable readiness signals: loading indicator hidden, key container visible, render-complete markers, or `expect.poll` on element counts. +- Use `test.step(...)` to make multi-step flows debuggable without splitting into many small tests. + +### Skip Onboarding/Tours + +- Use `page.addInitScript(...)` **before** navigation to set localStorage/cookies that suppress onboarding. + +### Parallel UI (spaceTest + scoutSpace) + +- Parallelism is **file-level**. Keep each file isolated. +- Use `spaceTest` so you can use `scoutSpace` (one Kibana space per worker). +- Ingest shared ES data in `parallel_tests/global.setup.ts`. +- Don’t mutate shared indices inside parallel tests. +- Clean up space-scoped changes in `afterAll` (saved objects + UI settings). + +## API Tests + +### Shape + +1. Prepare environment with `apiServices`/`kbnClient`/`esArchiver`. +2. Generate least-privilege credentials in `beforeAll`. +3. Call the endpoint under test with `apiClient` using those credentials. +4. Assert `statusCode` and response body; verify side effects via `apiServices`/`kbnClient`. + +Important: `apiServices`/`kbnClient` run with elevated privileges. Don’t use them to validate the endpoint under test or its RBAC. + +### Imports + +- Import `expect` from the `/api` subpath (`@kbn/scout/api` or `@kbn/scout-/api`), never from the main entry. +- Use custom matchers: `expect(response).toHaveStatusCode(200)` instead of `expect(response.statusCode).toBe(200)`. + +### Assertions + +- Don't stop at `statusCode`. Assert the response body shape and critical fields. + +## Flakiness Workflow + +- Fix the source of flakiness (selectors/readiness) instead of adding manual retry loops. +- Use the Flaky Test Runner when adding new tests or fixing flaky tests (see `dev_docs/operations/flaky_test_runner.mdx`). + +## Debugging Cheatsheet + +- Enable Scout debug logs: `SCOUT_LOG_LEVEL=debug`. +- Prefer Playwright UI mode for local iteration: `npx playwright test --ui`. +- Use the generated Playwright HTML report to inspect failure screenshots/traces. diff --git a/.agent/skills/scout-create-scaffold/SKILL.md b/.agent/skills/scout-create-scaffold/SKILL.md new file mode 100644 index 0000000000000..3c47705666be0 --- /dev/null +++ b/.agent/skills/scout-create-scaffold/SKILL.md @@ -0,0 +1,123 @@ +--- +name: Scout Create Scaffold +description: Use when creating, relocating, or reviewing Scout test scaffolds for a Kibana module and you must choose the correct test/scout path, ui/api split, or file naming conventions. +--- + +# Create Scout Scaffold + +## Overview + +Place Scout tests next to the module under test using the repo's Scout path conventions. Core principle: derive the test root from the target module path first, then choose the ui/api split and naming rules. + +## Core workflow + +1. Determine the module root. + - Walk up from the target file path until you find `kibana.jsonc` (preferred). + - If none, use the directory that represents the module boundary (plugin/package root). +2. Choose test type. + - UI test: uses Playwright page or page objects. + - API test: uses HTTP clients only (no browser). +3. Choose the Scout root. + - Default: `/test/scout`. + - If a custom Scout root exists (for example `test/scout_cspm_agentless`, `test/scout_uiam_local`), place new tests under the same root. +4. Prefer scaffolding via the Scout CLI when starting from scratch. + - `node scripts/scout.js generate` (also picks the correct Scout package import for the module) +5. Place files using Scout path conventions. +6. Create the minimal scaffold (see checklist below). + +## Quick reference + +| Purpose | Path pattern | +| -------------------- | ---------------------------------------------------------------------- | +| UI tests (sequential) | `test/scout{_}/ui/tests/**/*.spec.ts` | +| UI tests (parallel) | `test/scout{_}/ui/parallel_tests/**/*.spec.ts` | +| API tests (sequential) | `test/scout{_}/api/tests/**/*.spec.ts` | +| API tests (parallel) | `test/scout{_}/api/parallel_tests/**/*.spec.ts` | +| Global setup | `test/scout{_}/{ui,api}/{tests,parallel_tests}/global.setup.ts` | + +## Path conventions + +Scout test files must match: + +UI: +``` +/test/scout{_}/ui/{tests,parallel_tests}/**/*.spec.ts +``` + +API: +``` +/test/scout{_}/api/{tests,parallel_tests}/**/*.spec.ts +``` + +Notes: + +- `{_}` is optional. Examples: `test/scout` (default), `test/scout_cspm_agentless`, `test/scout_uiam_local`. +- UI test files live in `ui/tests/` or `ui/parallel_tests/`. +- API test files live in `api/tests/` (sequential) or `api/parallel_tests/` (parallel). Parallel API runs are supported but require careful isolation (indices, saved objects, etc.). +- `global.setup.ts` lives under the configured `testDir` and uses worker-scoped fixtures only. +- Non-test helpers can live under `test/scout*/ui/helpers/` or `test/scout*/common/` (shared UI+API). + +## Scaffold checklist + +### UI tests + +- `test/scout*/ui/playwright.config.ts` + - If missing, copy from a similar Scout-enabled plugin in the same solution. + - Filename must be exactly `playwright.config.ts` (tooling discovery). +- Optional: `test/scout*/ui/parallel.playwright.config.ts` (plus `ui/parallel_tests/`) + - Filename must be exactly `parallel.playwright.config.ts` (tooling discovery). +- `test/scout*/ui/fixtures/index.ts` + - Provide the `test` fixture export used by UI tests. +- `test/scout*/ui/tests/` + - Place UI `.spec.ts` files here. +- Optional: `test/scout*/ui/parallel_tests/` +- Optional: `test/scout*/ui/tests/global.setup.ts` or `parallel_tests/global.setup.ts` +- Optional: `test/scout*/ui/tsconfig.json` (follow existing pattern in the module). + +### API tests + +- `test/scout*/api/playwright.config.ts` + - If missing, copy from a similar Scout-enabled plugin in the same solution. + - Filename must be exactly `playwright.config.ts` (tooling discovery). +- Optional: `test/scout*/api/parallel.playwright.config.ts` (plus `api/parallel_tests/`) + - Filename must be exactly `parallel.playwright.config.ts` (tooling discovery). +- `test/scout*/api/fixtures/index.ts` + - Provide the `apiTest` fixture export used by API tests. +- `test/scout*/api/tests/` + - Place API `.spec.ts` files here. +- Optional: `test/scout*/api/parallel_tests/` +- Optional: `test/scout*/api/tests/global.setup.ts` or `parallel_tests/global.setup.ts` +- Optional: `test/scout*/api/tsconfig.json` (follow existing pattern in the module). + +## Example + +Request: "Create a new scout test for x-pack/solutions/observability/plugins/apm/public/components/service_overview.tsx" + +Outcome: + +- Module root: `x-pack/solutions/observability/plugins/apm` +- UI tests path: `x-pack/solutions/observability/plugins/apm/test/scout/ui/tests/service_overview.spec.ts` +- Ensure `x-pack/solutions/observability/plugins/apm/test/scout/ui/playwright.config.ts` exists +- Ensure `x-pack/solutions/observability/plugins/apm/test/scout/ui/fixtures/index.ts` exists + +## Common mistakes + +- Put test files directly under `test/scout*/ui` instead of `test/scout*/ui/tests`. +- Forget `{ tag: ... }` on UI suites/tests (Scout validates UI tags at runtime). API tests should also be tagged so CI/discovery can select the right deployment target. +- Use `.test.ts` or `.ts` instead of `.spec.ts` for Scout tests. +- Place UI tests under `api` (or API tests under `ui`). +- Create a new `test/scout_*` root when a module already uses `test/scout` (or vice versa). + +## Red flags + +- Unsure where the module root is. +- No `tests/` or `parallel_tests/` directory in the target path. +- Using `.test.ts` or `.ts` for a Scout test file. +- Creating a new `test/scout_*` root without a corresponding server config set or an existing precedent in the module. + +## Discovery / manifests + +- Scout config discovery and CI rely on `.meta` manifests under `/test/scout*/.meta/...`. +- After adding or moving Scout tests (or changing Playwright configs), run `node scripts/scout.js update-test-config-manifests` to refresh manifests. +- If you add a new custom Scout root like `test/scout_`, you typically also need a matching server config set under `src/platform/packages/shared/kbn-scout/src/servers/configs/custom/`. +- `run-tests` auto-detects the custom config dir from the Playwright config path; `start-server` requires `--config-dir `. diff --git a/.agent/skills/scout-migrate-from-ftr/SKILL.md b/.agent/skills/scout-migrate-from-ftr/SKILL.md new file mode 100644 index 0000000000000..2cc9a272890b5 --- /dev/null +++ b/.agent/skills/scout-migrate-from-ftr/SKILL.md @@ -0,0 +1,89 @@ +--- +name: Scout Migrate From FTR +description: Use when migrating Kibana Functional Test Runner (FTR) tests to Scout, including decisions about UI vs API tests, mapping FTR services/page objects/hooks to Scout fixtures, and splitting loadTestFile patterns. +--- + +# Migrate FTR to Scout + +## Overview + +Migrate FTR tests to Scout by deciding whether a test should be UI or API, mapping FTR concepts to Scout fixtures, and rewriting loadTestFile-based suites into standalone Scout specs. Core principle: keep UI tests focused on user interactions and move data validation to API tests. + +## Required sub-skills + +- **REQUIRED SUB-SKILL:** scout-create-scaffold (place tests under the correct `test/scout` path). +- **REQUIRED SUB-SKILL:** scout-ui-testing (page objects, browser auth, parallel UI patterns). +- **REQUIRED SUB-SKILL:** scout-api-testing (apiClient/auth, apiServices patterns). +- **REQUIRED SUB-SKILL:** ftr-testing (understand FTR structure, loadTestFile, and configs). + +## Core workflow + +1. Decide whether the test should be Scout UI or Scout API. + - UI tests: verify user flows and rendering. + - API tests: validate server responses, data setup, or backend behaviors. +2. Identify the module root and target Scout path. + - Place tests under `/test/scout*/{ui,api}/{tests,parallel_tests}`. + - UI: use `ui/parallel_tests/` + `spaceTest` when the flow can be isolated by a Kibana space and should run in parallel; otherwise use `ui/tests/` + `test`. + - API: default to `api/tests/` (sequential). Use `api/parallel_tests/` + `parallel.playwright.config.ts` only when the test is safe to run in parallel (no shared state) and you need the speedup. +3. Translate FTR suites into Scout specs. + - Split `loadTestFile` suites into standalone Scout spec files. + - If a single FTR file contains multiple top-level `describe` blocks, split into multiple Scout specs (one describe per file). +4. Replace FTR-only patterns. + - Replace `supertest` calls with Scout `apiClient` (endpoint under test) + `requestAuth`/`samlAuth` (auth). + - Use `apiServices`/`kbnClient` for setup/teardown and verifying side effects. + - Replace webdriver waits with Playwright/page object methods. +5. Move UI selectors/actions into page objects. + - Create a page object for the page under test and register it in plugin fixtures. + - Keep test-subject constants in fixtures (for reuse across tests and page objects). +6. Port data ingestion to Scout fixtures/global setup (when needed). + - For parallel tests, prefer a `parallel_tests/global.setup.ts` that loads data once. + - If using synthtrace generators, add `@kbn/synthtrace-client` to the test tsconfig references. +7. Move isolated UI logic to component/unit tests when possible. + - If a feature can be tested in isolation (dropdowns, sorting, small components), prefer RTL/unit tests instead of Scout e2e. +8. Clean up FTR wiring. + - Remove the `loadTestFile` entry from the FTR index. + - If the test exists in both stateful and serverless FTR suites, remove from all relevant config/index files. + - Delete the old FTR test file once Scout coverage is in place. + - For staged migrations, mark the remaining FTR suite as `describe.skip` to avoid duplicate coverage. +9. Update Scout manifests (discovery/CI). + - Run `node scripts/scout.js update-test-config-manifests` so `.meta` manifests reflect the new/changed tests and configs. +10. Verify in both stateful and serverless when applicable. + - Use `node scripts/scout.js run-tests --stateful --testFiles ` and + `node scripts/scout.js run-tests --serverless=oblt --testFiles ` (adjust serverless target). + - If the tests are under `test/scout_/...`, `run-tests` auto-detects the server config dir from the Playwright config path (use `--config-dir ` only to override, or when using `start-server`). + +## Common patterns + +- Create a dedicated page object for the page under test and register it in the plugin page objects index. +- Extract shared helpers into `test/scout*/ui/fixtures/helpers.ts` (e.g., look up rule IDs via `apiServices`). +- Use `kbnClient` for saved object setup/cleanup inside tests. +- Add/extend `apiServices` to create and delete saved views or other API resources in `beforeAll/afterAll`. +- Place tests under `test/scout*/ui/parallel_tests/...` when using the parallel Scout config. +- Add test-subject constants to fixtures for reuse in tests and page objects. +- If a feature is tested in both stateful and serverless FTR suites, migrate both and delete both FTR suites. +- Use `globalSetupHook` to load data once for parallel tests; keep isolation tests in `tests/`. +- Add synthtrace generators under `test/scout*/ui/fixtures/synthtrace/` when porting data ingestion. +- Prefer component/unit tests for isolated UI behaviors rather than Scout e2e. +- Use `page.addInitScript` helpers to set localStorage before navigation when tours or flyouts interfere. +- Split large FTR suites into focused Scout specs when different state/reset behavior is required + (for example, a dedicated spec for a UI tour flow). +- Add `data-test-subj` attributes to UI components when Scout needs stable selectors. +- When FTR used rison-encoded query params, replicate with `@kbn/rison` and add it to + `test/scout*/ui/tsconfig.json` `kbn_references`. +- Use a dedicated page object for deep-linkable pages (node details) and centralize URL building + and page-ready waits there. +- For large chart sets, use `expect.soft` and `expect.poll` to reduce flakiness and collect more signal. + +## Common mistakes + +- Migrating data validation UI tests instead of converting to API tests. +- Forgetting to split `loadTestFile` suites into separate Scout specs. +- Forgetting UI tags (required; Scout validates UI tags at runtime). API tests should also be tagged so CI/discovery can select the right deployment target. +- Placing Scout tests outside `test/scout*/{ui,api}/{tests,parallel_tests}`. +- Ignoring existing parallel Scout config (mixing `tests/` with `parallel_tests/`). + +## References + +Open only what you need: + +- Migration checklist (UI vs API, paths, fixtures mapping, manifests): `references/migration-workflow.md` diff --git a/.agent/skills/scout-migrate-from-ftr/references/migration-workflow.md b/.agent/skills/scout-migrate-from-ftr/references/migration-workflow.md new file mode 100644 index 0000000000000..df1b34a9dd1c9 --- /dev/null +++ b/.agent/skills/scout-migrate-from-ftr/references/migration-workflow.md @@ -0,0 +1,63 @@ +# Migration Workflow (Condensed) + +Use this as a checklist when migrating FTR tests to Scout. + +## 1) Decide UI vs API + +- UI tests should validate user interactions and rendering. +- Data validation belongs in API tests. + +## 2) Place files correctly + +- UI: `/test/scout*/ui/{tests,parallel_tests}/**/*.spec.ts` +- API: `/test/scout*/api/{tests,parallel_tests}/**/*.spec.ts` +- UI: use `ui/parallel_tests/` + `spaceTest` when the flow can be space-isolated and should run in parallel; otherwise use `ui/tests/` + `test`. +- API: default to `api/tests/` (sequential). Use `api/parallel_tests/` only when it’s safe to run in parallel and you need the speedup. + +## 3) Translate the test structure + +- `describe/it` -> `test.describe/test` or `apiTest.describe/apiTest`. +- `before/after` -> `test.beforeAll/test.afterAll`. +- `beforeEach/afterEach` -> `test.beforeEach/test.afterEach`. + +## 4) Replace FTR dependencies + +- Replace FTR services with Scout fixtures (`pageObjects`, `browserAuth`, `apiClient`, `apiServices`, `kbnClient`, `esArchiver`, `requestAuth`, `samlAuth`). +- Move UI selectors/actions into Scout page objects. +- Register new page objects in the plugin fixtures index. +- If the test needs API setup/cleanup, add a scoped API service and use it in `beforeAll/afterAll`. +- If the test needs rison-encoded query params, use `@kbn/rison` and add it to + `test/scout*/ui/tsconfig.json` `kbn_references`. + +## 5) Split loadTestFile suites + +- Each `loadTestFile` target becomes its own Scout spec. +- Move shared setup into each spec (or a shared fixture/helper). +- Split flows with different state requirements (localStorage, tour visibility) into dedicated specs. + +## 6) Add helpers and constants + +- Put shared helpers in `test/scout*/ui/fixtures/helpers.ts` (or API helpers in API fixtures). +- Add test-subject constants in `fixtures/constants.ts` for reuse. +- For large data ingestion, use `parallel_tests/global.setup.ts` to load once. +- If using synthtrace generators, add `@kbn/synthtrace-client` to the test tsconfig references. + +## 7) Prefer component/unit tests for isolated UI + +- If functionality can be tested in isolation (dropdown constraints, sorting, small UI components), add RTL/unit tests instead of e2e. +- Consider unit tests for tab configuration, feature-flagged tabs, and hook logic. + +## 8) Clean up FTR wiring + +- Remove `loadTestFile` entries from any stateful and serverless FTR configs. +- Delete old FTR test files once Scout coverage is verified. +- For staged migrations, mark remaining FTR suites as `describe.skip` to avoid duplicate coverage. + +## 9) Verify expectations + +- Each test must include assertions. +- UI tests must have at least one supported tag (Scout validates UI tags at runtime). API tests should also be tagged so discovery/CI can select the right deployment target. +- Avoid checking raw data in UI tests. +- Prefer page object methods over direct selectors. +- Preserve or update tags for deployment targets when needed. +- Run Scout tests in both stateful and serverless if the plugin supports both. diff --git a/.agent/skills/scout-ui-testing/SKILL.md b/.agent/skills/scout-ui-testing/SKILL.md new file mode 100644 index 0000000000000..6a3aa442d0f08 --- /dev/null +++ b/.agent/skills/scout-ui-testing/SKILL.md @@ -0,0 +1,121 @@ +--- +name: Scout UI Testing +description: 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. +--- + +# Scout UI Testing + +## Pick the right test mode + +- **Sequential UI**: `/test/scout*/ui/tests/**/*.spec.ts`. +- **Parallel UI**: `/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. +- Use the Scout package that matches the module root: +- `src/platform/**` or `x-pack/platform/**` -> `@kbn/scout` +- `x-pack/solutions/observability/**` -> `@kbn/scout-oblt` +- `x-pack/solutions/search/**` -> `@kbn/scout-search` +- `x-pack/solutions/security/**` -> `@kbn/scout-security` + +## Imports + +- Test framework + tags: `import { tags } from '@kbn/scout';` (or the module's Scout package) +- Test fixture: `import { test } from '../fixtures';` (or `import { test } from '@kbn/scout';` when not extending) +- Assertions: `import { expect } from '@kbn/scout/ui';` (or `@kbn/scout-oblt/ui`, etc.) — **not** from the main entry +- `expect` is **not** exported from the main `@kbn/scout` entry. Use the `/ui` subpath for UI tests. + +## Non-negotiable conventions + +- **Tags are required**: Scout validates UI test tags at runtime. Ensure each test has at least one supported tag (typically by tagging the top-level `test.describe(...)` / `spaceTest.describe(...)`, e.g. `tags.DEPLOYMENT_AGNOSTIC`, `tags.ESS_ONLY`, or `tags.PERFORMANCE`). +- **Prefer one suite per file**: keep a single top-level `test.describe(...)` (sequential) or `spaceTest.describe(...)` (parallel) and avoid nested `describe` blocks where possible. +- **UI actions live in page objects**; assertions stay in the spec. +- **Use APIs for setup/teardown**: prefer `apiServices`/`kbnClient`/`esArchiver` in hooks over clicking through the UI. + +## Auth (UI) + +- Use `browserAuth` — available methods: `loginAsAdmin()`, `loginAsPrivilegedUser()`, `loginAsViewer()`, `loginAs(role)`, `loginWithCustomRole(role)`. +- Prefer least privilege: use `loginAsViewer()` or `loginWithCustomRole()` over `loginAsAdmin()`. +- Avoid `loginAsAdmin()` unless the test is explicitly about admin-only behavior. + +## Page objects (UI) + +- Prefer `page.testSubj.locator(...)`, role/label locators; avoid brittle CSS. +- Keep selectors + interactions inside the page object class. +- Don't make API calls from page objects (use `apiServices`/`kbnClient` in hooks instead). +- Register plugin page objects by extending the `pageObjects` fixture in `test/scout*/ui/fixtures/index.ts`. +- Scout provides EUI component wrappers for stable interactions with common EUI widgets: `EuiComboBoxWrapper`, `EuiDataGridWrapper`, `EuiSelectableWrapper`, `EuiCheckBoxWrapper`, `EuiFieldTextWrapper`, `EuiCodeBlockWrapper`, `EuiSuperSelectWrapper`, `EuiToastWrapper`. Import them from `@kbn/scout` and use them as class members in page objects. + +## Parallel UI specifics (spaceTest) + +- Use `spaceTest` so you can access `scoutSpace` for worker-isolated saved objects + UI settings. +- Pre-ingest shared ES data in `parallel_tests/global.setup.ts` via `globalSetupHook(...)`. + - Only **worker** fixtures are available there (no `page`, `browserAuth`, `pageObjects`). +- Cleanup space-scoped mutations in `afterAll` (`scoutSpace.savedObjects.cleanStandardList()`, unset UI settings you set). + +## Extending fixtures + +Most modules extend the base `test` (or `spaceTest`) in `test/scout*/ui/fixtures/index.ts` to add custom page objects and auth helpers: + +```ts +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({ + pageObjects: async ({ pageObjects, page }, use) => { + await use({ ...pageObjects, myPlugin: new MyPluginPage(page) }); + }, +}); +``` + +Tests then import from local fixtures: `import { test } from '../fixtures';` + +## Multi-step flows with `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: + +```ts +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'); + }); +}); +``` + +## Waiting + flake control + +- Don’t use `page.waitForTimeout`. Wait on a page-ready signal (loading indicator hidden, container visible, `expect.poll` on element counts). +- If selectors aren’t stable, add `data-test-subj` (Scout uses it as the `testIdAttribute`). + +## A11y checks (optional, high value) + +- Use `page.checkA11y()` at a few stable checkpoints (landing pages, modals/flyouts). +- Prefer `include` scoped checks; assert `violations` is empty. + +## Run / debug quickly + +- Use either `--config` or `--testFiles` (they are mutually exclusive). +- Run by config: `node scripts/scout.js run-tests --stateful --config /test/scout*/ui/playwright.config.ts` (or `.../ui/parallel.playwright.config.ts` for parallel UI) +- Run by file/dir (Scout derives the right `playwright.config.ts` vs `parallel.playwright.config.ts`): `node scripts/scout.js run-tests --stateful --testFiles /test/scout*/ui/tests/my.spec.ts` +- For faster iteration, start servers once in another terminal: `node scripts/scout.js start-server --stateful [--config-dir ]`, then run Playwright directly: `npx playwright test --config <...> --project local --grep --headed`. +- `--config-dir` notes: +- `run-tests` auto-detects the custom config dir from `.../test/scout_/...` paths (override with `--config-dir ` if needed). +- `start-server` has no Playwright config to inspect, so pass `--config-dir ` when your tests require a custom server config. +- Debug: `SCOUT_LOG_LEVEL=debug`, or `npx playwright test --config <...> --project local --ui` + +## References + +Open only what you need: + +- Browser authentication helpers and patterns: `references/scout-browser-auth.md` +- Parallel UI (`spaceTest` + `scoutSpace`) isolation + global setup rules: `references/scout-ui-parallelism.md` +- API services patterns (setup/teardown helpers shared with UI): `../scout-api-testing/references/scout-api-services.md` diff --git a/.agent/skills/scout-ui-testing/references/scout-browser-auth.md b/.agent/skills/scout-ui-testing/references/scout-browser-auth.md new file mode 100644 index 0000000000000..25d31ccbfaab6 --- /dev/null +++ b/.agent/skills/scout-ui-testing/references/scout-browser-auth.md @@ -0,0 +1,37 @@ +# Scout Browser Authentication + +Use the `browserAuth` fixture to authenticate UI tests without manual UI logins. + +## Common methods + +- `loginAsAdmin()` +- `loginAsPrivilegedUser()` +- `loginAsViewer()` +- `loginAs(role: string)` +- `loginWithCustomRole(role: KibanaRole)` + +These methods are async and must be awaited. + +## Basic usage + +```ts +import { tags } from '@kbn/scout'; // or the module's Scout package (e.g. @kbn/scout-search) +import { expect } from '@kbn/scout/ui'; // or '@kbn/scout-search/ui', etc. +import { test } from '../fixtures'; + +test.describe('my suite', { tag: tags.DEPLOYMENT_AGNOSTIC }, () => { + test.beforeEach(async ({ browserAuth }) => { + await browserAuth.loginAsViewer(); + }); + + test('does something', async ({ page }) => { + await expect(page.testSubj.locator('someElement')).toBeVisible(); + }); +}); +``` + +## Custom roles + +Use `loginWithCustomRole()` for one-off permission sets. If a custom role is +used across multiple tests, extend the `browserAuth` fixture in the plugin's +`test/scout*/ui/fixtures` and add a helper like `loginAsMyRole()`. diff --git a/.agent/skills/scout-ui-testing/references/scout-ui-parallelism.md b/.agent/skills/scout-ui-testing/references/scout-ui-parallelism.md new file mode 100644 index 0000000000000..1bfcc77ad5885 --- /dev/null +++ b/.agent/skills/scout-ui-testing/references/scout-ui-parallelism.md @@ -0,0 +1,46 @@ +# Parallel UI Tests (spaceTest + scoutSpace) + +Use this when working under `.../test/scout*/ui/parallel_tests/` or a `parallel.playwright.config.ts`. + +## Key rules + +- Parallelism is file-level. Tests within one file still run sequentially. +- Use `spaceTest` (not `test`) so you can access `scoutSpace`. +- Tags are required: every `spaceTest.describe(...)` must include `{ tag: ... }`. +- Each worker gets a dedicated Kibana space; the fixture creates and deletes it automatically. +- Pre-ingest shared Elasticsearch data before workers start (global setup hook). Avoid ingesting or cleaning shared indices inside individual parallel tests. + +## Minimal config + layout + +- `ui/parallel.playwright.config.ts`: `testDir: './parallel_tests'`, `workers: 2..3`, optional `runGlobalSetup: true`. +- `ui/parallel_tests/global.setup.ts`: define `globalSetupHook(...)` (runs once total). + +## Minimal pattern + +```ts +import { spaceTest, tags } from '@kbn/scout'; // or the module's Scout package +import { expect } from '@kbn/scout/ui'; // or '@kbn/scout-oblt/ui', etc. + +spaceTest.describe('my feature', { tag: tags.DEPLOYMENT_AGNOSTIC }, () => { + spaceTest.beforeAll(async ({ scoutSpace }) => { + // Worker-scoped setup in the isolated space. + await scoutSpace.savedObjects.cleanStandardList(); + }); + + spaceTest.afterAll(async ({ scoutSpace }) => { + await scoutSpace.savedObjects.cleanStandardList(); + }); + + spaceTest('does something', async ({ browserAuth, pageObjects, page }) => { + await browserAuth.loginAsViewer(); + await pageObjects.somePage.goto(); + await expect(page.testSubj.locator('someElement')).toBeVisible(); + }); +}); +``` + +## Global setup hook gotchas + +- Global setup runs once total (executed by the first worker); other workers wait for it to finish. +- Only worker-scoped fixtures are available (for example `esArchiver`, `apiServices`, `kbnClient`, `esClient`, `log`). +- No `page`, `browserAuth`, or `pageObjects` in `global.setup.ts`. diff --git a/.codex/skills b/.codex/skills new file mode 120000 index 0000000000000..9b058317d1363 --- /dev/null +++ b/.codex/skills @@ -0,0 +1 @@ +../.agent/skills \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f2fa6f1db60fe..17cbd90057649 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3263,10 +3263,21 @@ x-pack/platform/test/moon.yml @elastic/kibana-operations x-pack/solutions/observability/test/moon.yml @elastic/kibana-operations x-pack/solutions/security/test/moon.yml @elastic/kibana-operations -# Leads approval +# These files influence agent behavior and are loaded into every new agent session. +# Changes here can have repo-wide impact (what instructions/tools/context an agent sees), so require +# tech lead review by default. /AGENTS.md @elastic/kibana-tech-leads .cursorignore @elastic/kibana-tech-leads /.claude/ @elastic/kibana-tech-leads +/.agent/skills/ @elastic/kibana-tech-leads + +# Delegate day-to-day edits of currently-existing skills to the QA team without requiring tech lead +# codeowner review. Any new skill directory will fall back to the `/.agent/skills/` rule above. +/.agent/skills/ftr-testing/** @elastic/appex-qa +/.agent/skills/scout-best-practices-reviewer/** @elastic/appex-qa +/.agent/skills/scout-create-scaffold/** @elastic/appex-qa +/.agent/skills/scout-migrate-from-ftr/** @elastic/appex-qa +/.agent/skills/scout-testing/** @elastic/appex-qa #### ## These rules are always last so they take ultimate priority over everything else