From cbedd820c164c765bdad5de8b2bfe142f47ca257 Mon Sep 17 00:00:00 2001 From: hashicc <191911133+hashicc@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:56:58 -0500 Subject: [PATCH 1/6] test(e2e): add e2e test for scope chooser with filtered targets Closes: https://hashicorp.atlassian.net/browse/ICU-16121 --- e2e-tests/desktop/tests/scope.spec.js | 85 +++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 e2e-tests/desktop/tests/scope.spec.js diff --git a/e2e-tests/desktop/tests/scope.spec.js b/e2e-tests/desktop/tests/scope.spec.js new file mode 100644 index 0000000000..4063b1fbcc --- /dev/null +++ b/e2e-tests/desktop/tests/scope.spec.js @@ -0,0 +1,85 @@ +import { expect, test } from '../fixtures/baseTest.js'; +import * as boundaryHttp from '../../helpers/boundary-http.js'; + +test.describe('Scope tests', async () => { + let orgA; + let projectA; + let targetA; + + let orgB; + let projectB; + let targetB; + + test.beforeEach(async ({ request, targetAddress, targetPort }) => { + // Group A resources + orgA = await boundaryHttp.createOrg(request); + projectA = await boundaryHttp.createProject(request, orgA.id); + targetA = await boundaryHttp.createTarget(request, { + scopeId: projectA.id, + type: 'tcp', + port: targetPort, + address: targetAddress, + }); + + // Group B resources + orgB = await boundaryHttp.createOrg(request); + projectB = await boundaryHttp.createProject(request, orgB.id); + targetB = await boundaryHttp.createTarget(request, { + scopeId: projectB.id, + type: 'tcp', + port: targetPort, + address: targetAddress, + }); + }); + + test.afterEach(async ({ request }) => { + if (orgA) { + await boundaryHttp.deleteOrg(request, orgA.id); + } + + if (orgB) { + await boundaryHttp.deleteOrg(request, orgB.id); + } + }); + + test('Shows the filtered targets based on selected scope', async ({ authedPage }) => { + const headerNav = await authedPage.getByLabel('header-nav'); + await expect(headerNav).toBeVisible(); + await expect(headerNav).toContainText('Global'); + + await expect( + authedPage.getByRole('link', { name: targetA.name }), + ).toBeVisible(); + await expect( + authedPage.getByRole('link', { name: targetB.name }), + ).toBeVisible(); + + await headerNav.click(); + const orgAHeaderNavLink = await authedPage.getByRole('link', { + name: orgA.name, + }); + await orgAHeaderNavLink.click(); + + await expect(headerNav).toContainText(orgA.name); + await expect( + authedPage.getByRole('link', { name: targetA.name }), + ).toBeVisible(); + await expect( + authedPage.getByRole('link', { name: targetB.name }), + ).not.toBeVisible(); + + await headerNav.click(); + const orgBHeaderNavLink = await authedPage.getByRole('link', { + name: orgB.name, + }); + await orgBHeaderNavLink.click(); + + await expect(headerNav).toContainText(orgB.name); + await expect( + authedPage.getByRole('link', { name: targetB.name }), + ).toBeVisible(); + await expect( + authedPage.getByRole('link', { name: targetA.name }), + ).not.toBeVisible(); + }); +}); From 333eab000fc1cf6a9fd540a37bdcffb5f66a34ab Mon Sep 17 00:00:00 2001 From: hashicc Date: Mon, 6 Jan 2025 22:39:50 +0000 Subject: [PATCH 2/6] Add missing copyright headers --- e2e-tests/desktop/tests/scope.spec.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/e2e-tests/desktop/tests/scope.spec.js b/e2e-tests/desktop/tests/scope.spec.js index 4063b1fbcc..486c4951cf 100644 --- a/e2e-tests/desktop/tests/scope.spec.js +++ b/e2e-tests/desktop/tests/scope.spec.js @@ -1,3 +1,8 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + import { expect, test } from '../fixtures/baseTest.js'; import * as boundaryHttp from '../../helpers/boundary-http.js'; From ba27e86f679cbbad5d70b2c962a7f0bf7c0ff549 Mon Sep 17 00:00:00 2001 From: hashicc <191911133+hashicc@users.noreply.github.com> Date: Mon, 6 Jan 2025 17:50:46 -0500 Subject: [PATCH 3/6] chore(e2e): use prettier on scope.spec.js --- e2e-tests/desktop/tests/scope.spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/e2e-tests/desktop/tests/scope.spec.js b/e2e-tests/desktop/tests/scope.spec.js index 486c4951cf..7f833834f3 100644 --- a/e2e-tests/desktop/tests/scope.spec.js +++ b/e2e-tests/desktop/tests/scope.spec.js @@ -47,7 +47,9 @@ test.describe('Scope tests', async () => { } }); - test('Shows the filtered targets based on selected scope', async ({ authedPage }) => { + test('Shows the filtered targets based on selected scope', async ({ + authedPage, + }) => { const headerNav = await authedPage.getByLabel('header-nav'); await expect(headerNav).toBeVisible(); await expect(headerNav).toContainText('Global'); From 149eca4e274f876bc2b46ac862665090870c58a6 Mon Sep 17 00:00:00 2001 From: hashicc <191911133+hashicc@users.noreply.github.com> Date: Tue, 7 Jan 2025 13:14:55 -0500 Subject: [PATCH 4/6] refactor(e2e): use explicit checks for scope in summary --- e2e-tests/desktop/tests/scope.spec.js | 47 +++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/e2e-tests/desktop/tests/scope.spec.js b/e2e-tests/desktop/tests/scope.spec.js index 7f833834f3..43a0c19d96 100644 --- a/e2e-tests/desktop/tests/scope.spec.js +++ b/e2e-tests/desktop/tests/scope.spec.js @@ -47,12 +47,45 @@ test.describe('Scope tests', async () => { } }); + async function assertSelectedHeaderNav( + headerNavLocator, + selectedScopeString, + ) { + const scopeStrings = ['Global', orgA.name, orgB.name]; + + if ( + typeof selectedScopeString !== 'string' || + !scopeStrings.includes(selectedScopeString) + ) { + throw new Error( + `Expected \`selectedScopeString\` argument to be a string and one of ${scopeStrings.join( + ', ', + )}.`, + ); + } + + const unselectedScopeStrings = scopeStrings.filter( + (scopeString) => scopeString !== selectedScopeString, + ); + for (const unselectedScopeString of unselectedScopeStrings) { + // `toMatchAriaSnapshot` can be used to assert the text within a summary element, + // see: https://playwright.dev/docs/aria-snapshots#grouped-elements + await expect(headerNavLocator).not.toMatchAriaSnapshot(` + - group: ${unselectedScopeString} + `); + } + + await expect(headerNavLocator).toMatchAriaSnapshot(` + - group: ${selectedScopeString} + `); + } + test('Shows the filtered targets based on selected scope', async ({ authedPage, }) => { - const headerNav = await authedPage.getByLabel('header-nav'); - await expect(headerNav).toBeVisible(); - await expect(headerNav).toContainText('Global'); + const headerNavLocator = await authedPage.getByLabel('header-nav'); + await expect(headerNavLocator).toBeVisible(); + await assertSelectedHeaderNav(headerNavLocator, 'Global'); await expect( authedPage.getByRole('link', { name: targetA.name }), @@ -61,13 +94,13 @@ test.describe('Scope tests', async () => { authedPage.getByRole('link', { name: targetB.name }), ).toBeVisible(); - await headerNav.click(); + await headerNavLocator.click(); const orgAHeaderNavLink = await authedPage.getByRole('link', { name: orgA.name, }); await orgAHeaderNavLink.click(); - await expect(headerNav).toContainText(orgA.name); + await assertSelectedHeaderNav(headerNavLocator, orgA.name); await expect( authedPage.getByRole('link', { name: targetA.name }), ).toBeVisible(); @@ -75,13 +108,13 @@ test.describe('Scope tests', async () => { authedPage.getByRole('link', { name: targetB.name }), ).not.toBeVisible(); - await headerNav.click(); + await headerNavLocator.click(); const orgBHeaderNavLink = await authedPage.getByRole('link', { name: orgB.name, }); await orgBHeaderNavLink.click(); - await expect(headerNav).toContainText(orgB.name); + await assertSelectedHeaderNav(headerNavLocator, orgB.name); await expect( authedPage.getByRole('link', { name: targetB.name }), ).toBeVisible(); From 301a1b36b1db5516b5da42ac9c7627d8f061fcf2 Mon Sep 17 00:00:00 2001 From: hashicc <191911133+hashicc@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:52:21 -0500 Subject: [PATCH 5/6] refactor(e2e): move test hooks and associated variables to top-level Move beforeEach and afterEach and the associated variables setup in hooks to top-level within scope.spec.js. This matches the patterns used in other tests. --- e2e-tests/desktop/tests/scope.spec.js | 72 +++++++++++++-------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/e2e-tests/desktop/tests/scope.spec.js b/e2e-tests/desktop/tests/scope.spec.js index 43a0c19d96..49ec52deed 100644 --- a/e2e-tests/desktop/tests/scope.spec.js +++ b/e2e-tests/desktop/tests/scope.spec.js @@ -6,47 +6,47 @@ import { expect, test } from '../fixtures/baseTest.js'; import * as boundaryHttp from '../../helpers/boundary-http.js'; -test.describe('Scope tests', async () => { - let orgA; - let projectA; - let targetA; - - let orgB; - let projectB; - let targetB; - - test.beforeEach(async ({ request, targetAddress, targetPort }) => { - // Group A resources - orgA = await boundaryHttp.createOrg(request); - projectA = await boundaryHttp.createProject(request, orgA.id); - targetA = await boundaryHttp.createTarget(request, { - scopeId: projectA.id, - type: 'tcp', - port: targetPort, - address: targetAddress, - }); +let orgA; +let projectA; +let targetA; + +let orgB; +let projectB; +let targetB; + +test.beforeEach(async ({ request, targetAddress, targetPort }) => { + // Group A resources + orgA = await boundaryHttp.createOrg(request); + projectA = await boundaryHttp.createProject(request, orgA.id); + targetA = await boundaryHttp.createTarget(request, { + scopeId: projectA.id, + type: 'tcp', + port: targetPort, + address: targetAddress, + }); - // Group B resources - orgB = await boundaryHttp.createOrg(request); - projectB = await boundaryHttp.createProject(request, orgB.id); - targetB = await boundaryHttp.createTarget(request, { - scopeId: projectB.id, - type: 'tcp', - port: targetPort, - address: targetAddress, - }); + // Group B resources + orgB = await boundaryHttp.createOrg(request); + projectB = await boundaryHttp.createProject(request, orgB.id); + targetB = await boundaryHttp.createTarget(request, { + scopeId: projectB.id, + type: 'tcp', + port: targetPort, + address: targetAddress, }); +}); - test.afterEach(async ({ request }) => { - if (orgA) { - await boundaryHttp.deleteOrg(request, orgA.id); - } +test.afterEach(async ({ request }) => { + if (orgA) { + await boundaryHttp.deleteOrg(request, orgA.id); + } - if (orgB) { - await boundaryHttp.deleteOrg(request, orgB.id); - } - }); + if (orgB) { + await boundaryHttp.deleteOrg(request, orgB.id); + } +}); +test.describe('Scope tests', async () => { async function assertSelectedHeaderNav( headerNavLocator, selectedScopeString, From 50790c5ec8ce4f75298e62de56e19ca368f24d0e Mon Sep 17 00:00:00 2001 From: hashicc <191911133+hashicc@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:59:06 -0500 Subject: [PATCH 6/6] refactor(e2e): use simpler scoped locator for summary element within header-nav --- e2e-tests/desktop/tests/scope.spec.js | 39 +++------------------------ 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/e2e-tests/desktop/tests/scope.spec.js b/e2e-tests/desktop/tests/scope.spec.js index 49ec52deed..00b78c14c8 100644 --- a/e2e-tests/desktop/tests/scope.spec.js +++ b/e2e-tests/desktop/tests/scope.spec.js @@ -47,45 +47,12 @@ test.afterEach(async ({ request }) => { }); test.describe('Scope tests', async () => { - async function assertSelectedHeaderNav( - headerNavLocator, - selectedScopeString, - ) { - const scopeStrings = ['Global', orgA.name, orgB.name]; - - if ( - typeof selectedScopeString !== 'string' || - !scopeStrings.includes(selectedScopeString) - ) { - throw new Error( - `Expected \`selectedScopeString\` argument to be a string and one of ${scopeStrings.join( - ', ', - )}.`, - ); - } - - const unselectedScopeStrings = scopeStrings.filter( - (scopeString) => scopeString !== selectedScopeString, - ); - for (const unselectedScopeString of unselectedScopeStrings) { - // `toMatchAriaSnapshot` can be used to assert the text within a summary element, - // see: https://playwright.dev/docs/aria-snapshots#grouped-elements - await expect(headerNavLocator).not.toMatchAriaSnapshot(` - - group: ${unselectedScopeString} - `); - } - - await expect(headerNavLocator).toMatchAriaSnapshot(` - - group: ${selectedScopeString} - `); - } - test('Shows the filtered targets based on selected scope', async ({ authedPage, }) => { const headerNavLocator = await authedPage.getByLabel('header-nav'); await expect(headerNavLocator).toBeVisible(); - await assertSelectedHeaderNav(headerNavLocator, 'Global'); + await expect(headerNavLocator.locator('summary')).toHaveText('Global'); await expect( authedPage.getByRole('link', { name: targetA.name }), @@ -100,7 +67,7 @@ test.describe('Scope tests', async () => { }); await orgAHeaderNavLink.click(); - await assertSelectedHeaderNav(headerNavLocator, orgA.name); + await expect(headerNavLocator.locator('summary')).toHaveText(orgA.name); await expect( authedPage.getByRole('link', { name: targetA.name }), ).toBeVisible(); @@ -114,7 +81,7 @@ test.describe('Scope tests', async () => { }); await orgBHeaderNavLink.click(); - await assertSelectedHeaderNav(headerNavLocator, orgB.name); + await expect(headerNavLocator.locator('summary')).toHaveText(orgB.name); await expect( authedPage.getByRole('link', { name: targetB.name }), ).toBeVisible();