Skip to content

Commit 404f1fd

Browse files
dmlemeshkokibanamachine
authored andcommitted
migrate som / ml / monitoring ui tests to scout (elastic#271394)
### Migration Summary 1. ML: `x-pack/platform/test/functional/apps/ml/short_tests/feature_controls` FTR file | Scout spec | Layer -- | -- | -- ml_security.ts (5 role/navlink scenarios) | x-pack/platform/plugins/shared/ml/test/scout/api/tests/feature_controls.spec.ts | API (capabilities) ml_spaces.ts (enabled space → app renders; disabled → 404) | x-pack/platform/plugins/shared/ml/test/scout/ui/tests/feature_controls.spec.ts + same API spec (per-space capabilities) | UI + API Parity: **full**. Browser-only smoke (mlAppPageOverview render + raw 404 JSON on disabled space) kept in UI; capabilities/navlink contracts moved to API. 2. Stack Monitoring: `x-pack/platform/test/functional/apps/monitoring/feature_controls` FTR file | Scout spec | Layer -- | -- | -- monitoring_security.ts (admin sees app, base:all no navlink) | x-pack/platform/plugins/private/monitoring/test/scout/ui/tests/feature_controls.spec.ts | UI monitoring_spaces.ts (enabled/disabled space) | same UI spec | UI Parity: **partial** — documented in the spec header. Migrated: monitoringAppContainer renders for admin (default + enabled space), 404 JSON in disabled space, base:all user does NOT see sidebar link. Not migrated (intentional gap): `monitoring_user` alone → forbidden and `monitoring_user + kibana_admin` → enable denied. Both require the reserved_monitoring ES application privilege, which Scout's setCustomRole cannot provision (the second case was already skipCloud in FTR). 3. Saved Objects Management: `x-pack/platform/test/functional/apps/saved_objects_management/feature_controls` FTR file | Scout spec | Layer -- | -- | -- security.ts (5 role/capability scenarios) | src/platform/plugins/shared/saved_objects_management/test/scout/api/tests/feature_controls.spec.ts | API Same file (browser-only button visibility + appNotFound routing) | src/platform/plugins/shared/saved_objects_management/test/scout/ui/tests/feature_controls.spec.ts | UI Parity: **full**. Pure capability/_find contracts at API, per-role button visibility & appNotFound routing at UI. 4. OSS Saved Objects Management: `src/platform/test/functional/apps/saved_objects_management` FTR file | Scout spec | Layer -- | -- | -- inspect_saved_objects.ts > "renders the envelope" | covered by ui/tests/spaces_integration.spec.ts + existing api/tests/bulk_get.spec.ts | UI + API inspect_saved_objects.ts > "allows to delete a saved object" | src/platform/plugins/shared/saved_objects_management/test/scout/ui/tests/inspect.spec.ts | UI (only confirm-modal flow) show_relationships.ts (invalid relationships) | covered by existing api/tests/relationships_invalid.spec.ts (no new spec needed) | API spaces_integration.ts | src/platform/plugins/shared/saved_objects_management/test/scout/ui/tests/spaces_integration.spec.ts | UI 5. x-pack SOM: `x-pack/platform/test/functional/apps/saved_objects_management` FTR file | Scout spec | Layer -- | -- | -- import_saved_objects_between_versions.ts (3 imports: 7.13, 7.14, 8.0) | API spec for counts + UI render-smoke | API + UI multi_space_import.ts (default-space + non-default-space import) | merged into same api/tests/imports.spec.ts | API Copy-to-space flow | src/platform/plugins/shared/saved_objects_management/test/scout/ui/tests/imports.spec.ts (merged with 7.13 render-smoke) | UI Parity: **full**. Import counts moved to API (no browser); browser-only checks (rendered dashboard, copy flyout summary counters) stay in UI. ### Net CI impact 2 dedicated FTR configs removed (no more per-suite server starts): - x-pack/platform/test/functional/apps/ml/short_tests no longer loads feature_controls. - x-pack/platform/test/functional/apps/monitoring/index.group1.js no longer loads feature_controls. - x-pack/platform/test/functional/apps/saved_objects_management/config.ts — entirely removed. - src/platform/test/functional/apps/saved_objects_management/config.ts — entirely removed. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
1 parent 3214a8e commit 404f1fd

53 files changed

Lines changed: 1421 additions & 1508 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.buildkite/ftr-manifests/ftr_platform_stateful_configs.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ enabled:
123123
- src/platform/test/functional/apps/management/group2/config.ts
124124
- src/platform/test/functional/apps/management/group3/config.ts
125125
- src/platform/test/functional/apps/management/group4/config.ts
126-
- src/platform/test/functional/apps/saved_objects_management/config.ts
127126
- src/platform/test/functional/apps/status_page/config.ts
128127
- src/platform/test/functional/apps/visualize/group1/config.ts
129128
- src/platform/test/functional/apps/visualize/group2/config.ts
@@ -319,7 +318,6 @@ enabled:
319318
- x-pack/platform/test/functional/apps/remote_clusters/config.ts
320319
- x-pack/platform/test/functional/apps/reporting_management/config.ts
321320
- x-pack/platform/test/functional/apps/rollup_job/config.ts
322-
- x-pack/platform/test/functional/apps/saved_objects_management/config.ts
323321
- x-pack/platform/test/functional/apps/security/config.ts
324322
- x-pack/platform/test/functional/apps/snapshot_restore/config.ts
325323
- x-pack/platform/test/functional/apps/spaces/config.ts

.buildkite/scout_ci_config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ plugins:
4040
- logstash
4141
- maps
4242
- ml
43+
- monitoring
4344
- navigation
4445
- observability
4546
- observability_onboarding

.github/CODEOWNERS

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2290,9 +2290,7 @@ x-pack/platform/plugins/shared/ml/server/models/data_recognizer/modules/security
22902290
# Core
22912291
/src/platform/test/api_integration/fixtures/kbn_archiver/management/saved_objects/relationships.json @elastic/kibana-core @elastic/kibana-data-discovery
22922292
/src/platform/test/functional/fixtures/kbn_archiver/saved_search.json @elastic/kibana-core # Assigned per only use: https://github.com/elastic/kibana/blob/main/test/interpreter_functional/test_suites/run_pipeline/esaggs.ts#L100
2293-
/src/platform/test/functional/fixtures/kbn_archiver/saved_objects_management/show_relationships.json @elastic/kibana-core # Assigned per only use: https://github.com/elastic/kibana/blob/main/test/functional/apps/saved_objects_management/show_relationships.ts#L20
22942293
/src/platform/test/functional/fixtures/kbn_archiver/saved_objects_management/hidden_from_http_apis.json @elastic/kibana-core
2295-
/src/platform/test/functional/fixtures/kbn_archiver/saved_objects_management/edit_saved_object.json @elastic/kibana-core # Assigned per only use: https://github.com/elastic/kibana/blob/main/test/functional/apps/saved_objects_management/inspect_saved_objects.ts#L40
22962294
/src/platform/test/functional/fixtures/es_archiver/saved_objects_management @elastic/kibana-core
22972295
/src/platform/test/api_integration/fixtures/es_archiver/saved_objects @elastic/kibana-core
22982296
/src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects @elastic/kibana-core
@@ -2363,7 +2361,6 @@ x-pack/platform/test/plugin_api_integration/test_suites/platform/ @elastic/kiban
23632361
/src/platform/test/api_integration/apis/stats @elastic/kibana-core # Assigned per: https://github.com/elastic/kibana/pull/20577
23642362
/src/platform/test/api_integration/apis/saved_objects* @elastic/kibana-core
23652363
/src/platform/test/api_integration/apis/core/*.ts @elastic/kibana-core
2366-
/x-pack/platform/test/functional/apps/saved_objects_management @elastic/kibana-core
23672364
/x-pack/platform/test/usage_collection @elastic/kibana-core
23682365
/x-pack/platform/test/licensing_plugin @elastic/kibana-core
23692366
/x-pack/platform/test/functional_execution_context @elastic/kibana-core
@@ -2712,7 +2709,6 @@ x-pack/platform/test/functional/page_objects/search_profiler_page.ts @elastic/se
27122709
/src/platform/test/functional/page_objects/embedded_console.ts @elastic/kibana-management
27132710
/src/platform/test/functional/page_objects/console_page.ts @elastic/kibana-management
27142711
/src/platform/test/functional/firefox/console.config.ts @elastic/kibana-management
2715-
/src/platform/test/functional/apps/saved_objects_management @elastic/kibana-management
27162712
/src/platform/test/functional/apps/console/*.ts @elastic/kibana-management
27172713
/src/platform/test/api_integration/apis/console/*.ts @elastic/kibana-management
27182714
/src/platform/test/accessibility/apps/management.ts @elastic/kibana-management

src/platform/packages/shared/kbn-scout/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,12 @@ export * from './src/playwright/ui_components';
4646
// Page-object wrappers and helpers for shared Kibana surfaces.
4747
export {
4848
ContentListWrapper,
49+
CopySavedObjectsToSpaceFlyout,
4950
buildContentListSearch,
5051
buildContentListUrlRegex,
5152
DataViewsManagementPage,
5253
ListingTable,
54+
SavedObjectsManagementPage,
5355
} from './src/playwright/page_objects';
5456
export type { ContentListUrlState } from './src/playwright/page_objects';
5557

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
import type { Locator } from 'playwright/test';
11+
import type { ScoutPage } from '..';
12+
13+
export interface CopyToSpaceSetupOptions {
14+
destinationSpaceId: string;
15+
createNewCopies?: boolean;
16+
overwrite?: boolean;
17+
}
18+
19+
export interface CopyToSpaceSummary {
20+
success: number;
21+
pending: number;
22+
skipped: number;
23+
errors: number;
24+
}
25+
26+
// EuiStat renders as "<label>\n<count>" — take the trailing number.
27+
const parseStat = (text: string): number => {
28+
const parts = text.trim().split('\n');
29+
const last = parts[parts.length - 1];
30+
const parsed = Number.parseInt(last, 10);
31+
if (Number.isNaN(parsed)) {
32+
throw new Error(`Could not parse a number from stat text '${text}'`);
33+
}
34+
return parsed;
35+
};
36+
37+
export class CopySavedObjectsToSpaceFlyout {
38+
public readonly flyout: Locator;
39+
public readonly form: Locator;
40+
public readonly initiateButton: Locator;
41+
public readonly finishButton: Locator;
42+
public readonly summarySuccessCount: Locator;
43+
public readonly summaryPendingCount: Locator;
44+
public readonly summarySkippedCount: Locator;
45+
public readonly summaryErrorCount: Locator;
46+
47+
constructor(private readonly page: ScoutPage) {
48+
this.flyout = this.page.testSubj.locator('copy-to-space-flyout');
49+
this.form = this.page.testSubj.locator('copy-to-space-form');
50+
this.initiateButton = this.page.testSubj.locator('cts-initiate-button');
51+
this.finishButton = this.page.testSubj.locator('cts-finish-button');
52+
this.summarySuccessCount = this.page.testSubj.locator('cts-summary-success-count');
53+
this.summaryPendingCount = this.page.testSubj.locator('cts-summary-pending-count');
54+
this.summarySkippedCount = this.page.testSubj.locator('cts-summary-skipped-count');
55+
this.summaryErrorCount = this.page.testSubj.locator('cts-summary-error-count');
56+
}
57+
58+
/** Asserts the flyout is open. */
59+
async waitForOpen(): Promise<void> {
60+
await this.flyout.waitFor({ state: 'visible' });
61+
}
62+
63+
/**
64+
* Configures the flyout form prior to initiating the copy. When
65+
* `createNewCopies` is `false`, toggles the matching radio; if `overwrite`
66+
* is also `false`, picks the "do not overwrite" radio. Selects the
67+
* destination space via `cts-space-selector-row-${spaceId}`.
68+
*/
69+
async setupForm({
70+
createNewCopies = true,
71+
overwrite = false,
72+
destinationSpaceId,
73+
}: CopyToSpaceSetupOptions): Promise<void> {
74+
if (createNewCopies && overwrite) {
75+
throw new Error('createNewCopies and overwrite options cannot be used together');
76+
}
77+
78+
if (!createNewCopies) {
79+
await this.form.locator('label[for="createNewCopiesDisabled"]').click();
80+
if (!overwrite) {
81+
await this.page.testSubj
82+
.locator('cts-copyModeControl-overwriteRadioGroup')
83+
.locator('label[for="overwriteDisabled"]')
84+
.click();
85+
}
86+
}
87+
88+
await this.page.testSubj.locator(`cts-space-selector-row-${destinationSpaceId}`).click();
89+
}
90+
91+
async startCopy(): Promise<void> {
92+
await this.initiateButton.click();
93+
}
94+
95+
/**
96+
* Waits for the per-space loading indicator to disappear and the success
97+
* indicator to appear for the supplied destination space.
98+
*/
99+
async waitForCopyToFinish(destinationSpaceId: string): Promise<void> {
100+
const loading = this.page.testSubj.locator(
101+
`cts-summary-indicator-loading-${destinationSpaceId}`
102+
);
103+
// Fast copies may skip the loading indicator entirely; swallow the wait.
104+
await loading.waitFor({ state: 'detached', timeout: 30_000 }).catch(() => {});
105+
await this.page.testSubj
106+
.locator(`cts-summary-indicator-success-${destinationSpaceId}`)
107+
.waitFor({ state: 'visible', timeout: 30_000 });
108+
}
109+
110+
/** Reads the four EuiStat counters in the flyout summary. */
111+
async getSummaryCounts(): Promise<CopyToSpaceSummary> {
112+
return {
113+
success: parseStat(await this.summarySuccessCount.innerText()),
114+
pending: parseStat(await this.summaryPendingCount.innerText()),
115+
skipped: parseStat(await this.summarySkippedCount.innerText()),
116+
errors: parseStat(await this.summaryErrorCount.innerText()),
117+
};
118+
}
119+
120+
/** Closes the flyout and waits for it to disappear. */
121+
async finishCopy(): Promise<void> {
122+
await this.finishButton.click();
123+
await this.flyout.waitFor({ state: 'detached' });
124+
}
125+
}

src/platform/packages/shared/kbn-scout/src/playwright/page_objects/index.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type { ScoutPage } from '..';
1111
import type { ScoutLogger } from '../../common';
1212
import type { ScoutTestConfig } from '../../types';
1313
import { CollapsibleNav } from './collapsible_nav';
14+
import { CopySavedObjectsToSpaceFlyout } from './copy_saved_objects_to_space_flyout';
1415
import { DashboardApp } from './dashboard_app';
1516
import { DataViewsManagementPage } from './data_views_management_page';
1617
import { DashboardLinks } from './dashboard_links';
@@ -20,6 +21,7 @@ import { FilterBar } from './filter_bar';
2021
import { MapsPage } from './maps_page';
2122
import { QueryBar } from './query_bar';
2223
import { RenderablePage } from './renderable_page';
24+
import { SavedObjectsManagementPage } from './saved_objects_management_page';
2325
import { SavedQueryManagementMenu } from './saved_query_management_menu';
2426
import { Toasts } from './toasts';
2527
import { createLazyPageObject } from './utils';
@@ -40,8 +42,10 @@ import type { KibanaUrl } from '../../common/services/kibana_url';
4042

4143
export {
4244
ContentListWrapper,
45+
CopySavedObjectsToSpaceFlyout,
4346
DataViewsManagementPage,
4447
ListingTable,
48+
SavedObjectsManagementPage,
4549
buildContentListSearch,
4650
buildContentListUrlRegex,
4751
};
@@ -66,6 +70,8 @@ export interface PageObjects {
6670
maps: MapsPage;
6771
queryBar: QueryBar;
6872
renderable: RenderablePage;
73+
savedObjectsManagement: SavedObjectsManagementPage;
74+
copySavedObjectsToSpaceFlyout: CopySavedObjectsToSpaceFlyout;
6975
savedQueryManagementMenu: SavedQueryManagementMenu;
7076
collapsibleNav: CollapsibleNav;
7177
toasts: Toasts;
@@ -95,6 +101,15 @@ export function createCorePageObjects(fixtures: PageObjectsFixtures): PageObject
95101
maps: createLazyPageObject(MapsPage, fixtures.page),
96102
queryBar: createLazyPageObject(QueryBar, fixtures.page),
97103
renderable: createLazyPageObject(RenderablePage, fixtures.page),
104+
savedObjectsManagement: createLazyPageObject(
105+
SavedObjectsManagementPage,
106+
fixtures.page,
107+
fixtures.kbnUrl
108+
),
109+
copySavedObjectsToSpaceFlyout: createLazyPageObject(
110+
CopySavedObjectsToSpaceFlyout,
111+
fixtures.page
112+
),
98113
savedQueryManagementMenu: createLazyPageObject(SavedQueryManagementMenu, fixtures.page),
99114
collapsibleNav: createLazyPageObject(CollapsibleNav, fixtures.page, fixtures.config),
100115
toasts: createLazyPageObject(Toasts, fixtures.page),
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
import type { Locator } from 'playwright/test';
11+
import { expect, type ScoutPage } from '..';
12+
import type { KibanaUrl } from '../../common/services/kibana_url';
13+
import { KibanaCodeEditorWrapper } from '../ui_components';
14+
15+
const spacePrefix = (spaceId?: string) => (spaceId && spaceId !== 'default' ? `/s/${spaceId}` : '');
16+
17+
/** Page object for the Saved Objects Management UI. */
18+
export class SavedObjectsManagementPage {
19+
public readonly table: Locator;
20+
public readonly selectAllCheckbox: Locator;
21+
public readonly deleteListButton: Locator;
22+
public readonly inspectDeleteButton: Locator;
23+
public readonly inspectSaveButton: Locator;
24+
public readonly codeEditor: Locator;
25+
public readonly appNotFoundPageContent: Locator;
26+
public readonly searchBar: Locator;
27+
public readonly importTrigger: Locator;
28+
public readonly importSubmit: Locator;
29+
public readonly importSuccess: Locator;
30+
public readonly importDone: Locator;
31+
public readonly codeEditorWrapper: KibanaCodeEditorWrapper;
32+
33+
constructor(private readonly page: ScoutPage, private readonly kbnUrl: KibanaUrl) {
34+
this.table = this.page.testSubj.locator('savedObjectsTable');
35+
this.selectAllCheckbox = this.page.testSubj.locator('checkboxSelectAll');
36+
this.deleteListButton = this.page.testSubj.locator('savedObjectsManagementDelete');
37+
this.inspectDeleteButton = this.page.testSubj.locator('savedObjectEditDelete');
38+
this.inspectSaveButton = this.page.testSubj.locator('savedObjectEditSave');
39+
this.codeEditor = this.page.testSubj.locator('kibanaCodeEditor');
40+
this.appNotFoundPageContent = this.page.testSubj.locator('appNotFoundPageContent');
41+
this.searchBar = this.page.testSubj.locator('savedObjectSearchBar');
42+
this.importTrigger = this.page.testSubj.locator('importObjects');
43+
this.importSubmit = this.page.testSubj.locator('importSavedObjectsImportBtn');
44+
this.importSuccess = this.page.testSubj.locator('importSavedObjectsSuccess');
45+
this.importDone = this.page.testSubj.locator('importSavedObjectsDoneBtn');
46+
this.codeEditorWrapper = new KibanaCodeEditorWrapper(this.page);
47+
}
48+
49+
/**
50+
* Navigates to the SOM listing page. Does NOT wait for the table so the
51+
* caller can also use it for negative tests (app-not-found / 404).
52+
*/
53+
async gotoListing(spaceId?: string): Promise<void> {
54+
await this.page.goto(this.kbnUrl.get(`${spacePrefix(spaceId)}/app/management/kibana/objects`));
55+
}
56+
57+
/** Waits for the saved-objects table to render at least one row. */
58+
async waitForTableLoaded(): Promise<void> {
59+
await this.table.waitFor({ state: 'visible' });
60+
await expect(this.page.testSubj.locator('savedObjectsTableRowTitle')).not.toHaveCount(0);
61+
}
62+
63+
/** Navigates directly to the SOM inspect view for a specific saved object. */
64+
async gotoInspect(type: string, id: string, spaceId?: string): Promise<void> {
65+
await this.page.goto(
66+
this.kbnUrl.get(`${spacePrefix(spaceId)}/app/management/kibana/objects/${type}/${id}`)
67+
);
68+
}
69+
70+
/** Reads the full Monaco editor model (bypasses viewport virtualisation). */
71+
async getCodeEditorValue(): Promise<string> {
72+
await this.codeEditor.waitFor({ state: 'visible' });
73+
return this.codeEditorWrapper.getCodeEditorValue();
74+
}
75+
76+
/** Visible row titles in the table, stripped of EuiLink trailing glyphs. */
77+
async getRowTitles(): Promise<string[]> {
78+
await this.waitForTableLoaded();
79+
const texts = await this.page.testSubj.locator('savedObjectsTableRowTitle').allInnerTexts();
80+
return texts.map((text) => text.split('\n')[0].trim());
81+
}
82+
83+
/** Types into the search bar and waits for the table to refilter. */
84+
async searchFor(query: string): Promise<void> {
85+
await this.searchBar.fill('');
86+
await this.searchBar.fill(query);
87+
await this.searchBar.press('Enter');
88+
await this.waitForTableLoaded();
89+
}
90+
91+
/** Imports an .ndjson file via the SOM "Import" flow with overwrite enabled. */
92+
async importFile(absoluteFilePath: string): Promise<void> {
93+
await this.importTrigger.click();
94+
// EuiFilePicker has no stable test-subj; drive its underlying input directly.
95+
await this.page.locator('input[type="file"][accept=".ndjson"]').setInputFiles(absoluteFilePath);
96+
await this.importSubmit.click();
97+
await this.importSuccess.waitFor({ state: 'visible', timeout: 30_000 });
98+
await this.importDone.click();
99+
await this.table.waitFor({ state: 'visible' });
100+
}
101+
102+
/** Opens the row context menu for the given title and clicks "Inspect". */
103+
async clickInspectByTitle(title: string): Promise<void> {
104+
const menu = await this.openRowContextMenu(title);
105+
await menu.locator('[data-test-subj="savedObjectsTableAction-inspect"]').click();
106+
}
107+
108+
/** Opens the row context menu for the given title and clicks "Copy to space". */
109+
async clickCopyToSpaceByTitle(title: string): Promise<void> {
110+
const menu = await this.openRowContextMenu(title);
111+
await menu
112+
.locator('[data-test-subj="savedObjectsTableAction-copy_saved_objects_to_space"]')
113+
.click();
114+
}
115+
116+
/** Clicks the inspect-view delete button and confirms the modal. */
117+
async deleteFromInspect(): Promise<void> {
118+
await this.inspectDeleteButton.waitFor({ state: 'visible' });
119+
await this.inspectDeleteButton.click();
120+
const confirmTitle = this.page.testSubj.locator('confirmModalTitleText');
121+
await confirmTitle.waitFor({ state: 'visible' });
122+
await this.page.testSubj.locator('confirmModalConfirmButton').click();
123+
await confirmTitle.waitFor({ state: 'hidden' });
124+
}
125+
126+
private async openRowContextMenu(title: string): Promise<Locator> {
127+
// `filter({ hasText })` keeps titles with punctuation matchable.
128+
const titleLocator = this.page.testSubj
129+
.locator('savedObjectsTableRowTitle')
130+
.filter({ hasText: title });
131+
const row = this.page
132+
.locator('[data-test-subj~="savedObjectsTableRow"]')
133+
.filter({ has: titleLocator });
134+
await row.waitFor({ state: 'visible' });
135+
await row.locator('[data-test-subj="euiCollapsedItemActionsButton"]').click();
136+
const menuPanel = this.page.locator('.euiContextMenuPanel');
137+
await menuPanel.waitFor({ state: 'visible' });
138+
return menuPanel;
139+
}
140+
}

src/platform/plugins/shared/saved_objects_management/moon.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ dependsOn:
4444
- '@kbn/css-utils'
4545
- '@kbn/content-management-plugin'
4646
- '@kbn/scout'
47+
- '@kbn/repo-info'
4748
tags:
4849
- plugin
4950
- prod

0 commit comments

Comments
 (0)