[8.x] [Scout] add maps test (#204607) (#211350)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Scout] add maps test
(#204607)](https://github.com/elastic/kibana/pull/204607)

<!--- Backport version: 9.6.4 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT
[{"author":{"name":"Tre","email":"wayne.seymour@elastic.co"},"sourceCommit":{"committedDate":"2025-01-30T11:55:35Z","message":"[Scout]
add maps test (#204607)\n\n## Summary\r\n\r\nAdd MapsPage to the scout
core to be re-used by others.\r\nAdd rudimentary docs to show how to run
these tests.\r\nAdded a `waitForRender` method.\r\nAdd test
id.\r\n\r\n---------\r\n\r\nCo-authored-by: Robert Oskamp
<traeluki@gmail.com>\r\nCo-authored-by: Nick Partridge
<nicholas.partridge@elastic.co>\r\nCo-authored-by: Nick Partridge
<nick.ryan.partridge@gmail.com>\r\nCo-authored-by: Elastic Machine
<elasticmachine@users.noreply.github.com>\r\nCo-authored-by: Dzmitry
Lemechko
<dzmitry.lemechko@elastic.co>","sha":"ce1904533d46e3b1e02d0d177fe4503ad0e495df","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:version","test:scout","v9.1.0","v8.19.0"],"title":"[Scout]
add maps
test","number":204607,"url":"https://github.com/elastic/kibana/pull/204607","mergeCommit":{"message":"[Scout]
add maps test (#204607)\n\n## Summary\r\n\r\nAdd MapsPage to the scout
core to be re-used by others.\r\nAdd rudimentary docs to show how to run
these tests.\r\nAdded a `waitForRender` method.\r\nAdd test
id.\r\n\r\n---------\r\n\r\nCo-authored-by: Robert Oskamp
<traeluki@gmail.com>\r\nCo-authored-by: Nick Partridge
<nicholas.partridge@elastic.co>\r\nCo-authored-by: Nick Partridge
<nick.ryan.partridge@gmail.com>\r\nCo-authored-by: Elastic Machine
<elasticmachine@users.noreply.github.com>\r\nCo-authored-by: Dzmitry
Lemechko
<dzmitry.lemechko@elastic.co>","sha":"ce1904533d46e3b1e02d0d177fe4503ad0e495df"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/204607","number":204607,"mergeCommit":{"message":"[Scout]
add maps test (#204607)\n\n## Summary\r\n\r\nAdd MapsPage to the scout
core to be re-used by others.\r\nAdd rudimentary docs to show how to run
these tests.\r\nAdded a `waitForRender` method.\r\nAdd test
id.\r\n\r\n---------\r\n\r\nCo-authored-by: Robert Oskamp
<traeluki@gmail.com>\r\nCo-authored-by: Nick Partridge
<nicholas.partridge@elastic.co>\r\nCo-authored-by: Nick Partridge
<nick.ryan.partridge@gmail.com>\r\nCo-authored-by: Elastic Machine
<elasticmachine@users.noreply.github.com>\r\nCo-authored-by: Dzmitry
Lemechko
<dzmitry.lemechko@elastic.co>","sha":"ce1904533d46e3b1e02d0d177fe4503ad0e495df"}},{"branch":"9.1","label":"v9.1.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Tre <wayne.seymour@elastic.co>
This commit is contained in:
Dzmitry Lemechko 2025-02-17 13:51:34 +01:00 committed by GitHub
parent 66ee361fd1
commit a4e5dabf7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 179 additions and 7 deletions

View file

@ -24,10 +24,11 @@ run_tests() {
EXIT_CODE=0
# Discovery Enhanced
# Discovery Enhanced && Maps
for run_mode in "--stateful"; do
run_tests "Discovery Enhanced: Parallel Workers" "x-pack/platform/plugins/private/discover_enhanced/ui_tests/parallel.playwright.config.ts" "$run_mode"
run_tests "Discovery Enhanced" "x-pack/platform/plugins/private/discover_enhanced/ui_tests/playwright.config.ts" "$run_mode"
run_tests "Maps" "x-pack/platform/plugins/shared/maps/ui_tests/playwright.config.ts" "$run_mode"
done
exit $EXIT_CODE

View file

@ -50,6 +50,7 @@ describe('createPlaywrightConfig', () => {
serversConfigDir: SCOUT_SERVERS_ROOT,
[VALID_CONFIG_MARKER]: true,
screenshot: 'only-on-failure',
testIdAttribute: 'data-test-subj',
trace: 'on-first-retry',
});
expect(config.globalSetup).toBeUndefined();

View file

@ -47,6 +47,7 @@ export function createPlaywrightConfig(options: ScoutPlaywrightOptions): Playwri
],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
testIdAttribute: 'data-test-subj',
serversConfigDir: SCOUT_SERVERS_ROOT,
[VALID_CONFIG_MARKER]: true,
/* Base URL to use in actions like `await page.goto('/')`. */

View file

@ -12,6 +12,8 @@ import { DashboardApp } from './dashboard_app';
import { DatePicker } from './date_picker';
import { DiscoverApp } from './discover_app';
import { FilterBar } from './fiter_bar';
import { MapsPage } from './maps_page';
import { RenderablePage } from './renderable_page';
import { createLazyPageObject } from './utils';
export interface PageObjects {
@ -19,6 +21,8 @@ export interface PageObjects {
discover: DiscoverApp;
dashboard: DashboardApp;
filterBar: FilterBar;
maps: MapsPage;
renderable: RenderablePage;
}
/**
@ -33,6 +37,8 @@ export function createCorePageObjects(page: ScoutPage): PageObjects {
dashboard: createLazyPageObject(DashboardApp, page),
discover: createLazyPageObject(DiscoverApp, page),
filterBar: createLazyPageObject(FilterBar, page),
maps: createLazyPageObject(MapsPage, page),
renderable: createLazyPageObject(RenderablePage, page),
// Add new page objects here
};
}

View file

@ -0,0 +1,18 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { ScoutPage } from '..';
export class MapsPage {
constructor(private readonly page: ScoutPage) {}
async gotoNewMap() {
await this.page.gotoApp('maps/map');
}
}

View file

@ -0,0 +1,43 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { ScoutPage, expect } from '..';
export class RenderablePage {
constructor(private readonly page: ScoutPage) {}
async waitForRender(count: number = 1): Promise<void> {
await expect(async () => await renderWait(count, this.page)).toPass({
timeout: 10_000,
});
}
}
const RENDER_COMPLETE_SELECTOR = '[data-render-complete="true"]';
const RENDER_COMPLETE_PENDING_SELECTOR = '[data-render-complete="false"]';
const DATA_LOADING_SELECTOR = '[data-loading]';
async function renderWait(count: number, page: ScoutPage) {
const renderCompleteLocator = page.locator(RENDER_COMPLETE_SELECTOR);
const renderPendingDataTitleLocator = page
.locator(RENDER_COMPLETE_PENDING_SELECTOR)
.and(page.locator('data-title'));
const loadingLocator = page.locator(DATA_LOADING_SELECTOR);
await renderCompleteLocator.waitFor({ timeout: 1000 });
const completedElementsCount = await renderCompleteLocator.count();
if (completedElementsCount < count)
throw new Error(
`${completedElementsCount} elements completed rendering, still waiting on a total of ${count} - ${await renderPendingDataTitleLocator.all()}`
);
const loadingCount = await loadingLocator.count();
if (loadingCount > 0) throw new Error(`${loadingCount} elements still loading contents`);
}

View file

@ -15,14 +15,14 @@ import { ScoutPage } from '../../fixtures';
* in certain test scenarios.
*
* @param PageObjectClass - The page object class to be instantiated lazily.
* @param scoutPage - ScoutPage instance, that extendes the Playwright `page` fixture and passed to the page object class constructor.
* @param scoutPage - ScoutPage instance, that extends the Playwright `page` fixture and passed to the page object class constructor.
* @param constructorArgs - Additional arguments to be passed to the page object class constructor.
* @returns A proxy object that behaves like an instance of the page object class, instantiating it on demand.
*/
export function createLazyPageObject<T extends object>(
PageObjectClass: new (page: ScoutPage, ...args: any[]) => T,
export function createLazyPageObject<T extends object, Args extends any[]>(
PageObjectClass: new (page: ScoutPage, ...args: Args) => T,
scoutPage: ScoutPage,
...constructorArgs: any[]
...constructorArgs: Args
): T {
let instance: T | null = null;
return new Proxy({} as T, {

View file

@ -27,6 +27,6 @@
"@kbn/mock-idp-utils",
"@kbn/test-subj-selector",
"@kbn/scout-info",
"@kbn/scout-reporting"
"@kbn/scout-reporting",
]
}

View file

@ -9,7 +9,8 @@
"public/**/*",
"server/**/*",
"server/config.ts",
"../../../../../typings/**/*"
"../../../../../typings/**/*",
"ui_tests/**/*",
],
"kbn_references": [
"@kbn/core",
@ -92,6 +93,7 @@
"@kbn/field-utils",
"@kbn/react-hooks",
"@kbn/react-kibana-mount",
"@kbn/scout",
],
"exclude": [
"target/**/*",

View file

@ -0,0 +1,22 @@
## How to run tests
You can drop the following in your terminal.
```bash
run_tests() {
local suit_name=$1
local config_path=$2
local run_mode=$3
echo "--- $suit_name ($run_mode) UI Tests"
if ! node scripts/scout run-tests "$run_mode" --config "$config_path"; then
echo "$suit_name: failed"
else
echo "$suit_name: passed"
fi
}
for run_mode in "--stateful" "--serverless=es" "--serverless=oblt" "--serverless=security"; do
run_tests "Maps" "x-pack/platform/plugins/shared/maps/ui_tests/playwright.config.ts" "$run_mode"
done
```

View file

@ -0,0 +1,11 @@
/*
* 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.
*/
export const VISIBLE_CHROME = 'kbnAppWrapper visibleChrome';
export const HIDDEN_CHROME = 'kbnAppWrapper hiddenChrome';
export const FULL_SCREEN_MODE = 'mapsFullScreenMode';
export const EXIT_FULL_SCREEN = 'exitFullScreenModeButton';

View file

@ -0,0 +1,13 @@
/*
* 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 { createPlaywrightConfig } from '@kbn/scout';
// eslint-disable-next-line import/no-default-export
export default createPlaywrightConfig({
testDir: './tests',
});

View file

@ -0,0 +1,54 @@
/*
* 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 { expect, tags, test } from '@kbn/scout';
import {
VISIBLE_CHROME,
HIDDEN_CHROME,
FULL_SCREEN_MODE,
EXIT_FULL_SCREEN,
} from '../fixtures/constants';
test.describe(
'Maps',
{
tag: tags.DEPLOYMENT_AGNOSTIC,
},
() => {
test.beforeEach(async ({ browserAuth, pageObjects }) => {
await browserAuth.loginAsViewer();
await pageObjects.maps.gotoNewMap();
await pageObjects.renderable.waitForRender();
});
test('Full screen mode', async ({ page }) => {
const fullScreenBtn = page.getByTestId(FULL_SCREEN_MODE);
const exitFullScreenBtn = page.getByTestId(EXIT_FULL_SCREEN);
const visibleChrome = page.getByTestId(VISIBLE_CHROME);
const hiddenChrome = page.getByTestId(HIDDEN_CHROME);
const baseMapBtn = page.getByRole('button', { name: 'Basemap' });
await expect(fullScreenBtn).toBeVisible();
await expect(exitFullScreenBtn).not.toBeVisible();
await expect(visibleChrome).toBeVisible();
await expect(hiddenChrome).not.toBeVisible();
await expect(baseMapBtn).toBeVisible();
await fullScreenBtn.click();
await expect(fullScreenBtn).not.toBeVisible();
await expect(exitFullScreenBtn).toBeVisible();
await expect(visibleChrome).not.toBeVisible();
await expect(hiddenChrome).toBeVisible();
await expect(baseMapBtn).toBeVisible();
await exitFullScreenBtn.click();
await expect(fullScreenBtn).toBeVisible();
});
}
);