diff --git a/x-pack/solutions/observability/plugins/apm/test/scout/ui/fixtures/page_objects/service_map.ts b/x-pack/solutions/observability/plugins/apm/test/scout/ui/fixtures/page_objects/service_map.ts index e19054000db98..ca4103a6c4159 100644 --- a/x-pack/solutions/observability/plugins/apm/test/scout/ui/fixtures/page_objects/service_map.ts +++ b/x-pack/solutions/observability/plugins/apm/test/scout/ui/fixtures/page_objects/service_map.ts @@ -29,6 +29,11 @@ export class ServiceMapPage { public serviceMapEdgeExploreTracesButton: Locator; public serviceMapOptionsPanel: Locator; public serviceMapFindInPageInput: Locator; + /** + * Native search `` (`SERVICE_MAP_FIND_INPUT_ID`). Prefer this for fill/focus so React + * `onFocus` runs and find highlights sync (`service_map_find_in_page` gates on `isFocused`). + */ + public serviceMapFindInPageNativeInput: Locator; public serviceMapFindMatchSummary: Locator; constructor(private readonly page: ScoutPage, private readonly kbnUrl: KibanaUrl) { @@ -57,6 +62,7 @@ export class ServiceMapPage { ); this.serviceMapOptionsPanel = page.testSubj.locator('serviceMapOptionsPanel'); this.serviceMapFindInPageInput = page.testSubj.locator('serviceMapControlsSearch'); + this.serviceMapFindInPageNativeInput = page.locator('#serviceMapFindInPageInput'); this.serviceMapFindMatchSummary = page.testSubj.locator('serviceMapFindMatchSummary'); } @@ -206,6 +212,15 @@ export class ServiceMapPage { return this.serviceMapGraph.getByTestId(`serviceMapNode-service-${serviceName}`); } + /** + * Highlight frame around the active find-in-page match (`HighlightWrapper` when `isActiveSearchMatch`). + */ + getActiveFindMatchHighlightFrame(serviceName: string) { + return this.getServiceNodeRoot(serviceName).locator( + 'xpath=ancestor::*[@data-test-subj="serviceMapNodeSearchHighlightFrame"][1]' + ); + } + /** * The clickable/focusable service circle only. Prefer this over role+name: when shown, violated/degrading SLO * badges can also be buttons whose accessible name includes the service name, so `getByRole('button', { name })` diff --git a/x-pack/solutions/observability/plugins/apm/test/scout/ui/parallel_tests/service_map/service_map_a11y.spec.ts b/x-pack/solutions/observability/plugins/apm/test/scout/ui/parallel_tests/service_map/service_map_a11y.spec.ts index f03727d2dbabd..d6ec7aa5224e3 100644 --- a/x-pack/solutions/observability/plugins/apm/test/scout/ui/parallel_tests/service_map/service_map_a11y.spec.ts +++ b/x-pack/solutions/observability/plugins/apm/test/scout/ui/parallel_tests/service_map/service_map_a11y.spec.ts @@ -44,14 +44,31 @@ test.describe( }) => { await test.step('nodes have visible focus indicators when focused', async () => { await serviceMapPage.waitForServiceNodeToLoad(SERVICE_OPBEANS_JAVA); - await serviceMapPage.openFindInPageWithKeyboardShortcut(); - await serviceMapPage.serviceMapFindInPageInput.fill(SERVICE_OPBEANS_JAVA); - await expect(serviceMapPage.serviceMapFindMatchSummary).toHaveText(/[1-9]/); const node = serviceMapPage.getServiceNode(SERVICE_OPBEANS_JAVA); await node.focus(); await expect(node).toBeFocused(); }); + await test.step('find-in-page: highlight frame while focused, Enter centers match', async () => { + await serviceMapPage.focusBodyForMapShortcuts(); + await serviceMapPage.openFindInPageWithKeyboardShortcut(); + // Fill the real input (#serviceMapFindInPageInput) so EuiFieldSearch onFocus runs and + // highlight context updates (filling by layout test-subj alone can leave isFocused false). + await serviceMapPage.serviceMapFindInPageNativeInput.fill(SERVICE_OPBEANS_JAVA); + await expect(serviceMapPage.serviceMapFindMatchSummary).toHaveText(/[1-9]/); + + // Highlights are driven only while the find field is focused; centering the map after Enter + // can move focus and clear highlights, so assert the frame before Enter. + const highlightFrame = + serviceMapPage.getActiveFindMatchHighlightFrame(SERVICE_OPBEANS_JAVA); + await expect(highlightFrame).toBeVisible(); + await expect(highlightFrame).toHaveAttribute('data-search-active-match'); + + await serviceMapPage.serviceMapFindInPageNativeInput.press('Enter'); + await serviceMapPage.settleServiceMapLayout(); + await expect(serviceMapPage.serviceMapFindMatchSummary).toHaveText(/[1-9]/); + }); + await test.step('zoom controls are keyboard accessible', async () => { await serviceMapPage.clickFitView(); await expect(serviceMapPage.zoomInBtnControl).toBeVisible();