Skip to content

Commit b5d9ad5

Browse files
[Scout] Migrate snapshot a11y test from ftr
1 parent ae93a37 commit b5d9ad5

8 files changed

Lines changed: 300 additions & 122 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { test as baseTest } from '@kbn/scout';
9+
import type { ScoutPage, ScoutTestFixtures, ScoutWorkerFixtures } from '@kbn/scout';
10+
11+
import type { SnapshotRestorePageObjects } from './page_objects';
12+
import { extendPageObjects } from './page_objects';
13+
14+
export interface SnapshotRestoreTestFixtures extends ScoutTestFixtures {
15+
pageObjects: SnapshotRestorePageObjects;
16+
}
17+
18+
export const test = baseTest.extend<SnapshotRestoreTestFixtures, ScoutWorkerFixtures>({
19+
pageObjects: async (
20+
{ pageObjects, page }: { pageObjects: SnapshotRestorePageObjects; page: ScoutPage },
21+
use: (pageObjects: SnapshotRestorePageObjects) => Promise<void>
22+
) => {
23+
await use(extendPageObjects(pageObjects, page));
24+
},
25+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import type { PageObjects, ScoutPage } from '@kbn/scout';
9+
import { createLazyPageObject } from '@kbn/scout';
10+
11+
import { SnapshotRestorePage } from './snapshot_restore_page';
12+
13+
export interface SnapshotRestorePageObjects extends PageObjects {
14+
snapshotRestore: SnapshotRestorePage;
15+
}
16+
17+
export function extendPageObjects(
18+
pageObjects: PageObjects,
19+
page: ScoutPage
20+
): SnapshotRestorePageObjects {
21+
return {
22+
...pageObjects,
23+
snapshotRestore: createLazyPageObject(SnapshotRestorePage, page),
24+
};
25+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import type { ScoutPage } from '@kbn/scout';
9+
10+
export class SnapshotRestorePage {
11+
constructor(private readonly page: ScoutPage) {}
12+
13+
async waitForSnapshotsTab({
14+
state = 'noRepos',
15+
}: { state?: 'noRepos' | 'noSnapshots' | 'hasSnapshots' } = {}) {
16+
// noRepos → RepositoryEmptyPrompt renders registerRepositoryButton
17+
// noSnapshots → SnapshotEmptyPrompt renders emptyPrompt (repos exist, no snapshots yet)
18+
// hasSnapshots → snapshotList table
19+
const selectorMap = {
20+
noRepos: 'registerRepositoryButton',
21+
noSnapshots: 'emptyPrompt',
22+
hasSnapshots: 'snapshotList',
23+
};
24+
await this.page.testSubj.waitForSelector(selectorMap[state], { state: 'visible' });
25+
}
26+
27+
async navToRepositories() {
28+
await this.page.testSubj.click('repositories_tab');
29+
await this.page.testSubj.waitForSelector('registerRepositoryButton', { state: 'visible' });
30+
}
31+
32+
async navToPolicies() {
33+
await this.page.testSubj.click('policies_tab');
34+
await this.page.testSubj.waitForSelector('createPolicyButton', { state: 'visible' });
35+
}
36+
37+
async navToRestoreStatus() {
38+
await this.page.testSubj.click('restore_status_tab');
39+
await this.page.testSubj.waitForSelector('noRestoredSnapshotsHeader', { state: 'visible' });
40+
}
41+
42+
async fillCreateNewPolicyPageOne(
43+
policyName: string,
44+
snapshotName: string,
45+
repositoryName?: string
46+
) {
47+
await this.page.testSubj.click('createPolicyButton');
48+
await this.page.testSubj.fill('nameInput', policyName);
49+
await this.page.testSubj.fill('snapshotNameInput', snapshotName);
50+
if (repositoryName) {
51+
await this.page.testSubj.locator('repositorySelect').selectOption(repositoryName);
52+
}
53+
await this.page.testSubj.click('nextButton');
54+
await this.page.testSubj.waitForSelector('allIndicesToggle', { state: 'visible' });
55+
}
56+
57+
async fillCreateNewPolicyPageTwo() {
58+
await this.page.testSubj.click('nextButton');
59+
await this.page.testSubj.waitForSelector('expireAfterValueInput', { state: 'visible' });
60+
}
61+
62+
async fillCreateNewPolicyPageThree() {
63+
await this.page.testSubj.click('nextButton');
64+
await this.page.testSubj.waitForSelector('submitButton', { state: 'visible' });
65+
}
66+
67+
async submitNewPolicy() {
68+
await this.page.testSubj.click('submitButton');
69+
await this.page.testSubj.waitForSelector('policyActionMenuButton', { state: 'visible' });
70+
}
71+
72+
async closeFlyout() {
73+
await this.page.testSubj.click('srPolicyDetailsFlyoutCloseButton');
74+
await this.page.testSubj.waitForSelector('policyLink', { state: 'visible' });
75+
}
76+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { createPlaywrightConfig } from '@kbn/scout';
9+
10+
export default createPlaywrightConfig({
11+
testDir: './tests',
12+
});
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { expect } from '@kbn/scout/ui';
9+
import { tags } from '@kbn/scout';
10+
11+
import { test } from '../fixtures';
12+
13+
// Modals, flyouts, and context menus render in EUI portals outside .kbnAppWrapper.
14+
const A11Y_SELECTORS = ['.kbnAppWrapper', '[data-euiportal="true"]'];
15+
16+
test.describe('Snapshot & Restore — accessibility', { tag: tags.stateful.classic }, () => {
17+
test.afterAll(async ({ kbnClient }) => {
18+
await kbnClient.savedObjects.cleanStandardList();
19+
});
20+
21+
test('empty state: all tabs have no a11y violations', async ({
22+
page,
23+
browserAuth,
24+
pageObjects,
25+
}) => {
26+
const { snapshotRestore } = pageObjects;
27+
28+
await browserAuth.loginAsAdmin();
29+
await page.gotoApp('management/data/snapshot_restore');
30+
await snapshotRestore.waitForSnapshotsTab();
31+
32+
await test.step('snapshots tab (empty)', async () => {
33+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
34+
expect(violations).toHaveLength(0);
35+
});
36+
37+
await test.step('repositories tab (empty)', async () => {
38+
await snapshotRestore.navToRepositories();
39+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
40+
expect(violations).toHaveLength(0);
41+
});
42+
43+
await test.step('policies tab (empty)', async () => {
44+
await snapshotRestore.navToPolicies();
45+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
46+
expect(violations).toHaveLength(0);
47+
});
48+
49+
await test.step('restore status tab (empty)', async () => {
50+
await snapshotRestore.navToRestoreStatus();
51+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
52+
expect(violations).toHaveLength(0);
53+
});
54+
});
55+
56+
test('table views with data: snapshots and repositories have no a11y violations', async ({
57+
page,
58+
browserAuth,
59+
pageObjects,
60+
esClient,
61+
}) => {
62+
const { snapshotRestore } = pageObjects;
63+
const repoName = 'testrepo';
64+
const snapshotName = `testsnapshot${Date.now()}`;
65+
66+
await esClient.snapshot.createRepository({
67+
name: repoName,
68+
verify: true,
69+
repository: { type: 'fs', settings: { location: 'temp' } },
70+
});
71+
await esClient.snapshot.create({
72+
repository: repoName,
73+
snapshot: snapshotName,
74+
wait_for_completion: true,
75+
});
76+
77+
try {
78+
await browserAuth.loginAsAdmin();
79+
await page.gotoApp('management/data/snapshot_restore');
80+
await snapshotRestore.waitForSnapshotsTab({ state: 'hasSnapshots' });
81+
82+
await test.step('snapshots table with data', async () => {
83+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
84+
expect(violations).toHaveLength(0);
85+
});
86+
87+
await test.step('repositories table with data', async () => {
88+
await snapshotRestore.navToRepositories();
89+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
90+
expect(violations).toHaveLength(0);
91+
});
92+
} finally {
93+
await esClient.snapshot
94+
.delete({ snapshot: snapshotName, repository: repoName })
95+
.catch(() => {});
96+
await esClient.snapshot.deleteRepository({ name: [repoName] }).catch(() => {});
97+
}
98+
});
99+
100+
test('create policy wizard: all steps have no a11y violations', async ({
101+
page,
102+
browserAuth,
103+
pageObjects,
104+
esClient,
105+
}) => {
106+
const { snapshotRestore } = pageObjects;
107+
const repoName = 'policyrepo';
108+
109+
await esClient.snapshot.createRepository({
110+
name: repoName,
111+
verify: true,
112+
repository: { type: 'fs', settings: { location: 'temp' } },
113+
});
114+
115+
try {
116+
await browserAuth.loginAsAdmin();
117+
await page.gotoApp('management/data/snapshot_restore');
118+
await snapshotRestore.waitForSnapshotsTab({ state: 'noSnapshots' });
119+
await snapshotRestore.navToPolicies();
120+
121+
await test.step('page one', async () => {
122+
await snapshotRestore.fillCreateNewPolicyPageOne(
123+
'testpolicy',
124+
'<daily-snap-{now/d}>',
125+
repoName
126+
);
127+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
128+
expect(violations).toHaveLength(0);
129+
});
130+
131+
await test.step('page two', async () => {
132+
await snapshotRestore.fillCreateNewPolicyPageTwo();
133+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
134+
expect(violations).toHaveLength(0);
135+
});
136+
137+
await test.step('page three', async () => {
138+
await snapshotRestore.fillCreateNewPolicyPageThree();
139+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
140+
expect(violations).toHaveLength(0);
141+
});
142+
143+
await test.step('submit and view flyout', async () => {
144+
await snapshotRestore.submitNewPolicy();
145+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
146+
expect(violations).toHaveLength(0);
147+
});
148+
149+
await test.step('policy table with data', async () => {
150+
await snapshotRestore.closeFlyout();
151+
const { violations } = await page.checkA11y({ include: A11Y_SELECTORS });
152+
expect(violations).toHaveLength(0);
153+
});
154+
} finally {
155+
await esClient.snapshot.deleteRepository({ name: [repoName] }).catch(() => {});
156+
await esClient.slm.deleteLifecycle({ policy_id: 'testpolicy' }).catch(() => {});
157+
}
158+
});
159+
});

x-pack/platform/plugins/private/snapshot_restore/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@kbn/react-kibana-context-render",
3838
"@kbn/licensing-types",
3939
"@kbn/core-http-browser",
40+
"@kbn/scout",
4041
],
4142
"exclude": [
4243
"target/**/*",

x-pack/platform/test/accessibility/apps/group3/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ export default ({ loadTestFile }: FtrProviderContext): void => {
1515
loadTestFile(require.resolve('./graph'));
1616
loadTestFile(require.resolve('./ml_embeddables_in_dashboard'));
1717
loadTestFile(require.resolve('./rules_connectors'));
18-
// Please make sure that the remote clusters, snapshot and restore and
19-
// CCR tests stay in that order. Their execution fails if rearranged.
18+
// Please make sure that the remote clusters and CCR tests stay in that order.
19+
// Their execution fails if rearranged.
2020
loadTestFile(require.resolve('./remote_clusters'));
21-
loadTestFile(require.resolve('./snapshot_and_restore'));
2221
loadTestFile(require.resolve('./cross_cluster_replication'));
2322
loadTestFile(require.resolve('./reporting'));
2423
loadTestFile(require.resolve('./search_sessions'));

0 commit comments

Comments
 (0)