From 554eed884831f50b61bc391794b959ab9dc96d02 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Tue, 18 Mar 2025 12:34:25 +0100 Subject: [PATCH] [scout] add 'apiServices' fixture to group Kibana API helpers (#214470) ## Summary We decided to group `Kibana API helpers` under a single fixture: `apiServices` instead of individual fixtures. It should simplify the search of existing helpers and reduce a risk for Teams to create the same helper like we see today with FTR. Adding just `apiServices` in test context and adding dot will expand a list of all available API helpers + it can be extended for individual solution (e.g. @kbn/scout-oblt) and directly in plugin (if there is no chance to re-use it in other plugins) image Before: ``` test('should create something', async ({ fleetApi, onboardingApi, alertingApi, }) => { await fleetApi.integration.install(integrationName); await onboardingApi.updateInstallationStepStatus( onboardingId, 'ea-download', 'complete' ); await alertingApi.waitForAlert(alertId); ``` After: ``` test('should create something', async ({ apiServices, }) => { await apiServices.fleet.integration.install(integrationName); await apiServices.onboarding.updateInstallationStepStatus( onboardingId, 'ea-download', 'complete' ); await apiServices.alerting.waitForAlert(alertId); ``` (cherry picked from commit 48cd2075f75386b515e19567095c03a8ca73fe20) --- .../packages/shared/kbn-scout/README.md | 58 ++++++-- .../packages/shared/kbn-scout/index.ts | 1 + .../fixtures/parallel_run_fixtures.ts | 11 +- .../fixtures/single_thread_fixtures.ts | 11 +- .../fixtures/worker/apis/fleet/index.ts | 86 +++++------ .../playwright/fixtures/worker/apis/index.ts | 33 +++-- .../src/playwright/fixtures/worker/index.ts | 4 +- .../shared/kbn-scout/src/playwright/index.ts | 8 +- .../packages/kbn-scout-oblt/index.ts | 1 + .../fixtures/parallel_run_fixtures.ts | 22 ++- .../fixtures/single_thread_fixtures.ts | 16 ++- .../src/playwright/fixtures/types.ts | 13 +- .../ui_tests/fixtures/apis/onboarding.ts | 37 +++++ .../ui_tests/fixtures/index.ts | 33 ++++- .../ui_tests/fixtures/onboarding_api.ts | 48 ------- .../add_custom_integration.spec.ts | 4 +- .../custom_logs/error_handling.spec.ts | 8 +- .../custom_logs/install_elastic_agent.spec.ts | 136 +++++++++++++----- 18 files changed, 344 insertions(+), 186 deletions(-) create mode 100644 x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/apis/onboarding.ts delete mode 100644 x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/onboarding_api.ts diff --git a/src/platform/packages/shared/kbn-scout/README.md b/src/platform/packages/shared/kbn-scout/README.md index 7e4235e64f092..0e236e883fae4 100644 --- a/src/platform/packages/shared/kbn-scout/README.md +++ b/src/platform/packages/shared/kbn-scout/README.md @@ -211,20 +211,17 @@ Install dependencies by running the following commands: Move to the `src/platform/packages/shared/kbn-scout` directory to begin development. -#### Adding or Modifying Features +### Adding or Modifying Components -Contributions to sharable fixtures and page objects are highly encouraged to promote reusability, stability, and ease of adoption. Follow these steps: - -Create a New Page Object: Add your Page Object to the `src/playwright/page_objects` directory. For instance: +Contributions to sharable `Fixtures`, `API services` and `Page Objects` are highly encouraged to promote reusability, stability, and ease of adoption. Follow these steps: #### Adding Page Objects -1. **Create a New Page Object:** Add your Page Object to the src/playwright/page_objects directory. For instance: +1. **Create a New Page Object:** Add a new file to the `src/playwright/page_objects` directory. For instance: ```ts export class NewPage { constructor(private readonly page: ScoutPage) {} - // implementation } ``` @@ -237,7 +234,48 @@ export function createCorePageObjects(page: ScoutPage): PageObjects { }; } ``` -#### Adding Fixtures +#### Adding API service + +1. **Create a New API service:** Add your service to the `src/playwright/fixtures/worker/apis` directory. For instance: + +```ts +export interface FleetApiService { + integration: { + install: (name: string) => Promise; + delete: (name: string) => Promise; + }; +} + +export const getFleetApiHelper = (log: ScoutLogger, kbnClient: KbnClient): FleetApiService => { + return { + integration: { + install: async (name: string) => { + // implementation + }, + delete: async (name: string) => { + // implementation + }, + }, + }; +}; +``` +2. **Register the API service:** Update the index file to include the new service: +```ts +export const apiServicesFixture = coreWorkerFixtures.extend< + {}, + { apiServices: ApiServicesFixture } +>({ + apiServices: [ + async ({ kbnClient, log }, use) => { + const services = { + // add new service + fleet: getFleetApiHelper(log, kbnClient), + }; + ... + ], +}); +``` +#### Adding Fixture 1. **Determine Fixture Scope:** Decide if your fixture should apply to the `test` (per-test) or `worker` (per-worker) scope. 2. **Implement the Fixture:** Add the implementation to `src/playwright/fixtures/test` or `src/playwright/fixtures/worker`. @@ -260,7 +298,11 @@ export const scoutTestFixtures = mergeTests( ``` #### Best Practices -- **Reusable Code:** When creating Page Objects or Fixtures that apply to more than one plugin, ensure they are added to the kbn-scout package. +- **Reusable Code:** When creating Page Objects, API services or Fixtures that apply to more than one plugin, ensure they are added to the `kbn-scout` package. - **Adhere to Existing Structure:** Maintain consistency with the project's architecture. +- **Keep the Scope of Components Clear** When designing test components, keep in naming conventions, scope, maintainability and performance. + - `Page Objects` should focus exclusively on UI interactions (clicking buttons, filling forms, navigating page). They should not make API calls directly. + - `API Services` should handle server interactions, such as sending API requests and processing responses. + - `Fixtures` can combine browser interactions with API requests, but they should be used wisely, especially with the `test` scope: a new instance of the fixture is created for **every test block**. If a fixture performs expensive operations (API setup, data ingestion), excessive usage can **slow down** the test suite runtime. Consider using `worker` scope when appropriate to reuse instances across tests within a worker. - **Add Unit Tests:** Include tests for new logic where applicable, ensuring it works as expected. - **Playwright documentation:** [Official best practices](https://playwright.dev/docs/best-practices) diff --git a/src/platform/packages/shared/kbn-scout/index.ts b/src/platform/packages/shared/kbn-scout/index.ts index 7e5c521f30084..d496bb4ba6ddf 100644 --- a/src/platform/packages/shared/kbn-scout/index.ts +++ b/src/platform/packages/shared/kbn-scout/index.ts @@ -23,6 +23,7 @@ export type { ScoutTestOptions, ScoutPage, PageObjects, + ApiServicesFixture, ScoutTestFixtures, ScoutWorkerFixtures, ScoutParallelTestFixtures, diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/parallel_run_fixtures.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/parallel_run_fixtures.ts index 381d61dd501d3..47059ad8c8621 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/parallel_run_fixtures.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/parallel_run_fixtures.ts @@ -9,14 +9,14 @@ import { mergeTests } from 'playwright/test'; import { - apiFixtures, + apiServicesFixture, coreWorkerFixtures, esArchiverFixture, scoutSpaceParallelFixture, synthtraceFixture, } from './worker'; import type { - ApiParallelWorkerFixtures, + ApiServicesFixture, EsClient, KbnClient, KibanaUrl, @@ -36,7 +36,7 @@ export const scoutParallelFixtures = mergeTests( // worker scope fixtures coreWorkerFixtures, scoutSpaceParallelFixture, - apiFixtures, + apiServicesFixture, // test scope fixtures browserAuthFixture, scoutPageParallelFixture, @@ -50,18 +50,19 @@ export interface ScoutParallelTestFixtures { pageObjects: PageObjects; } -export interface ScoutParallelWorkerFixtures extends ApiParallelWorkerFixtures { +export interface ScoutParallelWorkerFixtures { log: ScoutLogger; config: ScoutTestConfig; kbnUrl: KibanaUrl; kbnClient: KbnClient; esClient: EsClient; scoutSpace: ScoutSpaceParallelFixture; + apiServices: ApiServicesFixture; } export const globalSetup = mergeTests( coreWorkerFixtures, esArchiverFixture, synthtraceFixture, - apiFixtures + apiServicesFixture ); diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/single_thread_fixtures.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/single_thread_fixtures.ts index 41683ee0c77ae..16242494961b3 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/single_thread_fixtures.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/single_thread_fixtures.ts @@ -9,8 +9,7 @@ import { mergeTests } from 'playwright/test'; import { - ApiFixtures, - apiFixtures, + apiServicesFixture, coreWorkerFixtures, esArchiverFixture, uiSettingsFixture, @@ -18,6 +17,7 @@ import { lighthouseFixture, } from './worker'; import type { + ApiServicesFixture, EsArchiverFixture, EsClient, KbnClient, @@ -37,7 +37,7 @@ import { } from './test'; import type { BrowserAuthFixture, ScoutPage, PageObjects, PerfTrackerFixture } from './test'; export type { ScoutPage, PageObjects } from './test'; -export type { LighthouseAuditOptions } from './worker'; +export type { ApiServicesFixture, LighthouseAuditOptions } from './worker'; export const scoutFixtures = mergeTests( // worker scope fixtures @@ -46,7 +46,7 @@ export const scoutFixtures = mergeTests( uiSettingsFixture, synthtraceFixture, // api fixtures - apiFixtures, + apiServicesFixture, // test scope fixtures browserAuthFixture, scoutPageFixture, @@ -63,7 +63,7 @@ export interface ScoutTestFixtures { perfTracker: PerfTrackerFixture; } -export interface ScoutWorkerFixtures extends ApiFixtures { +export interface ScoutWorkerFixtures extends ApiServicesFixture { log: ScoutLogger; config: ScoutTestConfig; kbnUrl: KibanaUrl; @@ -71,6 +71,7 @@ export interface ScoutWorkerFixtures extends ApiFixtures { esClient: EsClient; esArchiver: EsArchiverFixture; uiSettings: UiSettingsFixture; + apiServices: ApiServicesFixture; apmSynthtraceEsClient: SynthtraceFixture['apmSynthtraceEsClient']; infraSynthtraceEsClient: SynthtraceFixture['infraSynthtraceEsClient']; otelSynthtraceEsClient: SynthtraceFixture['otelSynthtraceEsClient']; diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/apis/fleet/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/apis/fleet/index.ts index b645cf1933673..8db955bc27cbb 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/apis/fleet/index.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/apis/fleet/index.ts @@ -7,65 +7,45 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { measurePerformanceAsync } from '../../../../../common'; -import { coreWorkerFixtures } from '../../core_fixtures'; +import { KbnClient, ScoutLogger, measurePerformanceAsync } from '../../../../../common'; -export interface FleetApiFixture { +export interface FleetApiService { integration: { install: (name: string) => Promise; delete: (name: string) => Promise; }; } -/** - * This fixture provides a helper to interact with the Fleet API. - */ -export const fleetApiFixture = coreWorkerFixtures.extend<{}, { fleetApi: FleetApiFixture }>({ - fleetApi: [ - async ({ kbnClient, log }, use) => { - const fleetApiHelper = { - integration: { - install: async (name: string) => { - await measurePerformanceAsync( - log, - `fleetApi.integration.install [${name}]`, - async () => { - await kbnClient.request({ - method: 'POST', - path: `/api/fleet/epm/custom_integrations`, - body: { - force: true, - integrationName: name, - datasets: [ - { name: `${name}.access`, type: 'logs' }, - { name: `${name}.error`, type: 'metrics' }, - { name: `${name}.warning`, type: 'logs' }, - ], - }, - }); - } - ); - }, - - delete: async (name: string) => { - await measurePerformanceAsync( - log, - `fleetApi.integration.delete [${name}]`, - async () => { - await kbnClient.request({ - method: 'DELETE', - path: `/api/fleet/epm/packages/${name}`, - ignoreErrors: [400], - }); - } - ); - }, - }, - }; +export const getFleetApiHelper = (log: ScoutLogger, kbnClient: KbnClient): FleetApiService => { + return { + integration: { + install: async (name: string) => { + await measurePerformanceAsync(log, `fleetApi.integration.install [${name}]`, async () => { + await kbnClient.request({ + method: 'POST', + path: `/api/fleet/epm/custom_integrations`, + body: { + force: true, + integrationName: name, + datasets: [ + { name: `${name}.access`, type: 'logs' }, + { name: `${name}.error`, type: 'metrics' }, + { name: `${name}.warning`, type: 'logs' }, + ], + }, + }); + }); + }, - log.serviceLoaded('fleetApi'); - await use(fleetApiHelper); + delete: async (name: string) => { + await measurePerformanceAsync(log, `fleetApi.integration.delete [${name}]`, async () => { + await kbnClient.request({ + method: 'DELETE', + path: `/api/fleet/epm/packages/${name}`, + ignoreErrors: [400], + }); + }); + }, }, - { scope: 'worker' }, - ], -}); + }; +}; diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/apis/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/apis/index.ts index ab3b50a2e4bd4..888fe4fa0ce0c 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/apis/index.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/apis/index.ts @@ -7,15 +7,30 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { mergeTests } from 'playwright/test'; -import { FleetApiFixture, fleetApiFixture } from './fleet'; +import { coreWorkerFixtures } from '../core_fixtures'; +import { FleetApiService, getFleetApiHelper } from './fleet'; -export const apiFixtures = mergeTests(fleetApiFixture); - -export interface ApiFixtures { - fleetApi: FleetApiFixture; +export interface ApiServicesFixture { + fleet: FleetApiService; + // add more services here } -export interface ApiParallelWorkerFixtures { - fleetApi: FleetApiFixture; -} +/** + * This fixture provides a helper to interact with the Kibana APIs like Fleet, Spaces, Alerting, etc. + */ +export const apiServicesFixture = coreWorkerFixtures.extend< + {}, + { apiServices: ApiServicesFixture } +>({ + apiServices: [ + async ({ kbnClient, log }, use) => { + const services = { + fleet: getFleetApiHelper(log, kbnClient), + }; + + log.serviceLoaded('apiServices'); + await use(services); + }, + { scope: 'worker' }, + ], +}); diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/index.ts index e23c802f3e812..a8655c8642d58 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/index.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/index.ts @@ -26,8 +26,8 @@ export type { UiSettingsFixture } from './ui_settings'; export { scoutSpaceParallelFixture } from './scout_space'; export type { ScoutSpaceParallelFixture } from './scout_space'; -export { apiFixtures } from './apis'; -export type { ApiFixtures, ApiParallelWorkerFixtures } from './apis'; +export { apiServicesFixture } from './apis'; +export type { ApiServicesFixture } from './apis'; export { synthtraceFixture } from './synthtrace'; export type { SynthtraceFixture } from './synthtrace'; diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/index.ts index 92212592740cb..6dd726c5ddb4d 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/index.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/index.ts @@ -25,15 +25,17 @@ export { expect } from './expect'; export type { ScoutPlaywrightOptions, ScoutTestOptions } from './types'; export type { + ScoutPage, + // can be extended with solution specific fixtures ScoutTestFixtures, ScoutWorkerFixtures, ScoutParallelTestFixtures, ScoutParallelWorkerFixtures, - ScoutPage, + // can be extended with solution specific API services + ApiServicesFixture, + // can be extended with solution specific Page Objects PageObjects, } from './fixtures'; // use to tag tests export { tags } from './tags'; - -export { ingestTestDataHook, ingestSynthtraceDataHook } from './global_hooks'; diff --git a/x-pack/solutions/observability/packages/kbn-scout-oblt/index.ts b/x-pack/solutions/observability/packages/kbn-scout-oblt/index.ts index 02f539439b5f6..057cf957ba13f 100644 --- a/x-pack/solutions/observability/packages/kbn-scout-oblt/index.ts +++ b/x-pack/solutions/observability/packages/kbn-scout-oblt/index.ts @@ -7,6 +7,7 @@ export { test, spaceTest } from './src/playwright'; export type { + ObltApiServicesFixture, ObltPageObjects, ObltTestFixtures, ObltWorkerFixtures, diff --git a/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/parallel_run_fixtures.ts b/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/parallel_run_fixtures.ts index 09501b5231749..995b092268eb2 100644 --- a/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/parallel_run_fixtures.ts +++ b/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/parallel_run_fixtures.ts @@ -6,9 +6,14 @@ */ import { spaceTest as spaceBase } from '@kbn/scout'; - +import type { ApiServicesFixture, KbnClient } from '@kbn/scout'; import { extendPageObjects } from '../page_objects'; -import { ObltParallelTestFixtures, ObltParallelWorkerFixtures } from './types'; + +import { + ObltApiServicesFixture, + ObltParallelTestFixtures, + ObltParallelWorkerFixtures, +} from './types'; /** * Should be used test spec files, running in parallel in isolated spaces agaist the same Kibana instance. @@ -27,4 +32,17 @@ export const spaceTest = spaceBase.extend Promise + ) => { + const extendedApiServices = apiServices as ObltApiServicesFixture; + // extend with Observability specific API services + // extendedApiServices. = getServiceApiHelper(kbnClient); + + await use(extendedApiServices); + }, + { scope: 'worker' }, + ], }); diff --git a/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/single_thread_fixtures.ts b/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/single_thread_fixtures.ts index 24497b4f414be..6155500a9f2bb 100644 --- a/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/single_thread_fixtures.ts +++ b/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/single_thread_fixtures.ts @@ -6,9 +6,10 @@ */ import { test as base } from '@kbn/scout'; +import type { ApiServicesFixture, KbnClient } from '@kbn/scout'; import { extendPageObjects } from '../page_objects'; -import { ObltTestFixtures, ObltWorkerFixtures } from './types'; +import { ObltApiServicesFixture, ObltTestFixtures, ObltWorkerFixtures } from './types'; /** * Should be used for the test spec files executed seqentially. @@ -27,4 +28,17 @@ export const test = base.extend({ const extendedPageObjects = extendPageObjects(pageObjects, page); await use(extendedPageObjects); }, + apiServices: [ + async ( + { apiServices, kbnClient }: { apiServices: ApiServicesFixture; kbnClient: KbnClient }, + use: (extendedApiServices: ObltApiServicesFixture) => Promise + ) => { + const extendedApiServices = apiServices as ObltApiServicesFixture; + // extend with Observability specific API services + // extendedApiServices. = getServiceApiHelper(kbnClient); + + await use(extendedApiServices); + }, + { scope: 'worker' }, + ], }); diff --git a/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/types.ts b/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/types.ts index ca432dfb4820f..54e79c7e5c727 100644 --- a/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/types.ts +++ b/x-pack/solutions/observability/packages/kbn-scout-oblt/src/playwright/fixtures/types.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { +import type { + ApiServicesFixture, ScoutParallelTestFixtures, ScoutParallelWorkerFixtures, ScoutTestFixtures, @@ -17,10 +18,16 @@ export interface ObltTestFixtures extends ScoutTestFixtures { pageObjects: ObltPageObjects; } -export type ObltWorkerFixtures = ScoutWorkerFixtures; +export type ObltApiServicesFixture = ApiServicesFixture; + +export interface ObltWorkerFixtures extends ScoutWorkerFixtures { + apiServices: ObltApiServicesFixture; +} export interface ObltParallelTestFixtures extends ScoutParallelTestFixtures { pageObjects: ObltPageObjects; } -export type ObltParallelWorkerFixtures = ScoutParallelWorkerFixtures; +export interface ObltParallelWorkerFixtures extends ScoutParallelWorkerFixtures { + apiServices: ObltApiServicesFixture; +} diff --git a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/apis/onboarding.ts b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/apis/onboarding.ts new file mode 100644 index 0000000000000..641918a803e44 --- /dev/null +++ b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/apis/onboarding.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KbnClient } from '@kbn/scout-oblt'; + +export interface OnboardingApiService { + updateInstallationStepStatus: ( + onboardingId: string, + step: string, + status: string, + payload?: object + ) => Promise; +} + +export const getOnboardingApiHelper = (kbnClient: KbnClient) => { + return { + updateInstallationStepStatus: async ( + onboardingId: string, + step: string, + status: string, + payload?: object + ) => { + await kbnClient.request({ + method: 'POST', + path: `/internal/observability_onboarding/flow/${onboardingId}/step/${step}`, + body: { + status, + payload, + }, + }); + }, + }; +}; diff --git a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/index.ts b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/index.ts index c14be56108e85..fde2398269cd8 100644 --- a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/index.ts +++ b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/index.ts @@ -6,18 +6,25 @@ */ import { v4 as uuidv4 } from 'uuid'; -import { test as base, ObltTestFixtures, ObltWorkerFixtures } from '@kbn/scout-oblt'; -import { mergeTests } from 'playwright/test'; -import { onboardingApiFixture, OnboardingApiFixture } from './onboarding_api'; +import { test as base } from '@kbn/scout-oblt'; +import type { + KbnClient, + ObltApiServicesFixture, + ObltTestFixtures, + ObltWorkerFixtures, +} from '@kbn/scout-oblt'; +import { getOnboardingApiHelper, OnboardingApiService } from './apis/onboarding'; export type ExtendedScoutTestFixtures = ObltTestFixtures; + +export interface ExtendedApiServicesFixture extends ObltApiServicesFixture { + onboarding: OnboardingApiService; +} export interface ExtendedScoutWorkerFixtures extends ObltWorkerFixtures { - onboardingApi: OnboardingApiFixture; + apiServices: ExtendedApiServicesFixture; } -const testFixtures = mergeTests(base, onboardingApiFixture); - -export const test = testFixtures.extend({ +export const test = base.extend({ pageObjects: async ( { pageObjects, @@ -32,6 +39,18 @@ export const test = testFixtures.extend Promise + ) => { + const extendedApiServices = apiServices as ExtendedApiServicesFixture; + extendedApiServices.onboarding = getOnboardingApiHelper(kbnClient); + + await use(extendedApiServices); + }, + { scope: 'worker' }, + ], }); export const generateIntegrationName = (name: string) => `${name}_${uuidv4().slice(0, 5)}`; diff --git a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/onboarding_api.ts b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/onboarding_api.ts deleted file mode 100644 index 9309229f1fd1c..0000000000000 --- a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/fixtures/onboarding_api.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { test as base } from '@kbn/scout-oblt'; - -export interface OnboardingApiFixture { - updateInstallationStepStatus: ( - onboardingId: string, - step: string, - status: string, - payload?: object - ) => Promise; -} - -/** - * This fixture provides a helper to interact with the Observability Onboarding API. - */ -export const onboardingApiFixture = base.extend<{}, { onboardingApi: OnboardingApiFixture }>({ - onboardingApi: [ - async ({ kbnClient, log }, use) => { - const onboardingApiHelper: OnboardingApiFixture = { - updateInstallationStepStatus: async ( - onboardingId: string, - step: string, - status: string, - payload?: object - ) => { - await kbnClient.request({ - method: 'POST', - path: `/internal/observability_onboarding/flow/${onboardingId}/step/${step}`, - body: { - status, - payload, - }, - }); - }, - }; - - log.serviceLoaded('onboardingApi'); - await use(onboardingApiHelper); - }, - { scope: 'worker' }, - ], -}); diff --git a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/add_custom_integration.spec.ts b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/add_custom_integration.spec.ts index e04abdec5e5cf..f09f9be11f919 100644 --- a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/add_custom_integration.spec.ts +++ b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/add_custom_integration.spec.ts @@ -20,8 +20,8 @@ test.describe( await customLogs.goto(); }); - test.afterEach(async ({ fleetApi }) => { - await fleetApi.integration.delete(integrationName); + test.afterEach(async ({ apiServices }) => { + await apiServices.fleet.integration.delete(integrationName); }); test('should be installed, show API Key and correct instructions', async ({ diff --git a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/error_handling.spec.ts b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/error_handling.spec.ts index c056d8b8109f9..9bd775521dfb5 100644 --- a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/error_handling.spec.ts +++ b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/error_handling.spec.ts @@ -15,8 +15,8 @@ test.describe( const integrationName = generateIntegrationName('mylogs'); const logsFilePath = `${integrationName}.log`; - test.afterEach(async ({ fleetApi }) => { - await fleetApi.integration.delete(integrationName); + test.afterEach(async ({ apiServices }) => { + await apiServices.fleet.integration.delete(integrationName); }); test('should be displayed when user has no previleges', async ({ @@ -92,10 +92,10 @@ test.describe( test('should be displayed when integration with the same name exists', async ({ browserAuth, pageObjects: { customLogs }, - fleetApi, + apiServices, page, }) => { - await fleetApi.integration.install(integrationName); + await apiServices.fleet.integration.install(integrationName); await browserAuth.loginAsAdmin(); await customLogs.goto(); diff --git a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/install_elastic_agent.spec.ts b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/install_elastic_agent.spec.ts index 4f3ca2aae077c..68c299371ea12 100644 --- a/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/install_elastic_agent.spec.ts +++ b/x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel_tests/custom_logs/install_elastic_agent.spec.ts @@ -34,58 +34,79 @@ test.describe('Observability Onboarding - Elastic Agent', { tag: ['@ess', '@svlO await pageObjects.customLogs.apiKeyCreatedCallout.waitFor({ state: 'visible' }); }); - test.afterEach(async ({ fleetApi }) => { - await fleetApi.integration.delete(integrationName); + test.afterEach(async ({ apiServices }) => { + await apiServices.fleet.integration.delete(integrationName); }); - test('should be installed sucessfully', async ({ - pageObjects: { customLogs }, - onboardingApi, - }) => { + test('should be installed sucessfully', async ({ pageObjects: { customLogs }, apiServices }) => { // downloading agent - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-download', 'loading'); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'loading' + ); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('loading'), 'Downloading Elastic Agent' ); // downloading agent failed - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-download', 'danger'); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'danger' + ); await expect(customLogs.getStepStatusLocator('danger'), 'Download Elastic Agent').toBeVisible(); // downloading agent completed - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-download', 'complete'); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('complete'), 'Elastic Agent downloaded' ); // extracting agent - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-extract', 'loading'); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'loading' + ); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('loading'), 'Extracting Elastic Agent' ); // extracting agent completed - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-extract', 'complete'); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'complete' + ); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('complete'), 'Elastic Agent extracted' ); // installing agent failed - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-install', 'danger'); + await apiServices.onboarding.updateInstallationStepStatus(onboardingId, 'ea-install', 'danger'); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('danger'), 'Install Elastic Agent' ); // installing agent completed - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-install', 'complete'); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-install', + 'complete' + ); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('complete'), 'Elastic Agent installed' ); // agent connecting - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-status', 'loading'); + await apiServices.onboarding.updateInstallationStepStatus(onboardingId, 'ea-status', 'loading'); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('loading'), 'Connecting to the Elastic Agent' @@ -93,9 +114,14 @@ test.describe('Observability Onboarding - Elastic Agent', { tag: ['@ess', '@svlO await expect(customLogs.getCheckLogsStepLocator('incomplete')).toBeVisible(); await expect(customLogs.checkLogsStepMessage).toHaveText('Ship logs to Elastic Observability'); // agent connected - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-status', 'complete', { - agentId: 'test-agent-id', - }); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-status', + 'complete', + { + agentId: 'test-agent-id', + } + ); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('complete'), 'Connected to the Elastic Agent' @@ -104,24 +130,45 @@ test.describe('Observability Onboarding - Elastic Agent', { tag: ['@ess', '@svlO test('should be configured sucessfully for Linux and wait for logs', async ({ pageObjects: { customLogs }, - onboardingApi, + apiServices, }) => { // install and connect agent for linux await customLogs.autoDownloadConfigurationToggle.click(); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-download', 'complete'); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-extract', 'complete'); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-install', 'complete'); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-status', 'complete', { - agentId: 'test-agent-id', - }); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'complete' + ); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-install', + 'complete' + ); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-status', + 'complete', + { + agentId: 'test-agent-id', + } + ); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-config', 'loading'); + await apiServices.onboarding.updateInstallationStepStatus(onboardingId, 'ea-config', 'loading'); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('loading'), 'Downloading Elastic Agent config' ); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-config', 'complete'); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-config', + 'complete' + ); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('complete'), 'Elastic Agent config written to /opt/Elastic/Agent/elastic-agent.yml' @@ -133,19 +180,40 @@ test.describe('Observability Onboarding - Elastic Agent', { tag: ['@ess', '@svlO test('should be configured sucessfully for MacOS and wait for logs', async ({ pageObjects: { customLogs }, - onboardingApi, + apiServices, }) => { // install and connect agent for macos await customLogs.selectPlatform('macos'); await customLogs.autoDownloadConfigurationToggle.click(); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-download', 'complete'); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-extract', 'complete'); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-install', 'complete'); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-status', 'complete', { - agentId: 'test-agent-id', - }); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'complete' + ); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-install', + 'complete' + ); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-status', + 'complete', + { + agentId: 'test-agent-id', + } + ); - await onboardingApi.updateInstallationStepStatus(onboardingId, 'ea-config', 'complete'); + await apiServices.onboarding.updateInstallationStepStatus( + onboardingId, + 'ea-config', + 'complete' + ); await checkAgentStatusUpdated( customLogs.getStepStatusLocator('complete'), 'Elastic Agent config written to /Library/Elastic/Agent/elastic-agent.yml'