Best practices for Scout API tests
Best practices specific to Scout API tests.
Tip
For guidance that applies to both UI and API tests, see the general Scout best practices. Scout is built on Playwright, so the official Playwright Best Practices also apply.
Use the right fixture for the right purpose:
| Fixture | Use for |
|---|---|
apiClient |
The endpoint under test (with scoped credentials from API auth) |
apiServices |
Setup/teardown and side effects |
kbnClient, esClient, etc. |
Lower-level setup when apiServices doesn’t have a suitable helper |
Prefer tests that read like “call endpoint X as role Y, assert outcome”.
Example
import { expect } from '@kbn/scout/api';
apiTest.beforeAll(async ({ requestAuth, apiServices }) => {
await apiServices.myFeature.createTestData();
viewerCredentials = await requestAuth.getApiKeyForViewer();
});
apiTest('returns data for viewer', async ({ apiClient }) => {
const response = await apiClient.get('api/my-feature/data', {
headers: { ...COMMON_HEADERS, ...viewerCredentials.apiKeyHeader },
});
expect(response).toHaveStatusCode(200);
expect(response.body.items).toHaveLength(3);
});
This pattern validates both endpoint behavior and the permission model.
Scout supports two authentication methods for API tests. Choose based on endpoint type:
| Endpoint type | Auth method | Fixture |
|---|---|---|
Public APIs (api/*) |
API key | requestAuth + apiKeyHeader |
Internal APIs (internal/*) |
Cookie-based session | samlAuth + cookieHeader |
See API authentication for details and examples.
Status code assertions are necessary but not sufficient. Also validate shape and key fields.
Examples
❌ Don’t: assert only the status code:
apiTest('returns autocomplete definitions', async ({ apiClient }) => {
const response = await apiClient.get('api/console/api_server', {
headers: { ...COMMON_HEADERS, ...viewerCredentials.apiKeyHeader },
});
expect(response).toHaveStatusCode(200);
});
✔️ Do: validate shape and key fields too:
apiTest('returns autocomplete definitions', async ({ apiClient }) => {
const response = await apiClient.get('api/console/api_server', {
headers: { ...COMMON_HEADERS, ...viewerCredentials.apiKeyHeader },
});
expect(response).toHaveStatusCode(200);
expect(response.body).toMatchObject({
es: {
endpoints: expect.any(Object),
globals: expect.any(Object),
name: 'es',
},
});
});
- General best practices — apply to both UI and API tests
- Write API tests
- API authentication
- API services
- Parallelism notes for API tests