From f118b381efeccdfc8bcc5bc5e4d76fe8382d7606 Mon Sep 17 00:00:00 2001 From: Kianna <30884335+kiannaquach@users.noreply.github.com> Date: Mon, 16 Mar 2026 11:24:45 -0700 Subject: [PATCH] [UI][VAULT-42963] plugin management (#12973) (#13044) * plugin management tests! * Add general settings test * Add configuration settings page * Update configuration page tests.. * Use configuration page for pki tests * Fix double comment * Add configuration page tests * Update keymgmt and pki tune tests * Update secret engines to use the step helper * Add transform configuration workflow test --- ui/e2e/pages/base.ts | 13 +- ui/e2e/pages/configuration-settings.ts | 113 ++++++++++++++++++ .../keymgmt-tune-external.ent.spec.ts | 14 ++- ui/e2e/tests/superuser/keymgmt.spec.ts | 47 ++++++++ .../superuser/kubernetes-secrets.spec.ts | 87 ++++++++++---- ui/e2e/tests/superuser/kv.spec.ts | 55 +++++++++ ui/e2e/tests/superuser/pki.spec.ts | 76 ++++++++++++ ui/e2e/tests/superuser/transform.spec.ts | 47 ++++++++ ui/e2e/tests/superuser/transit.spec.ts | 47 ++++++++ 9 files changed, 469 insertions(+), 30 deletions(-) create mode 100644 ui/e2e/pages/configuration-settings.ts diff --git a/ui/e2e/pages/base.ts b/ui/e2e/pages/base.ts index aa0d3d0492..bfca4aabd7 100644 --- a/ui/e2e/pages/base.ts +++ b/ui/e2e/pages/base.ts @@ -4,6 +4,7 @@ */ import { Page } from '@playwright/test'; +import { findEngineDisplayName } from './configuration-settings'; export class BasePage { constructor(protected page: Page) {} @@ -25,6 +26,16 @@ export class BasePage { } } + async disableEngine(path: string) { + await this.page.goto('secrets-engines'); + await this.page + .getByRole('row', { name: `Type of backend ${path}` }) + .getByLabel('supported secrets engine menu') + .click(); + await this.page.getByRole('button', { name: 'Delete' }).click(); + await this.page.getByRole('button', { name: 'Confirm' }).click(); + } + /** * Enable a secrets engine with a dynamic path * @param engineType - The type of engine to enable (e.g., 'KV', 'Transit', 'PKI Certificates') @@ -47,7 +58,7 @@ export class BasePage { // Click "Enable new engine" await this.page.getByRole('link', { name: 'Enable new engine' }).click(); - await this.page.getByRole('heading', { name: engineType }).click(); + await this.page.getByRole('heading', { name: findEngineDisplayName(engineType) }).click(); if (options?.external) { // Prerequisite: mock plugin catalog endpoint in the test so the External plugin option is available. diff --git a/ui/e2e/pages/configuration-settings.ts b/ui/e2e/pages/configuration-settings.ts new file mode 100644 index 0000000000..a470e0491b --- /dev/null +++ b/ui/e2e/pages/configuration-settings.ts @@ -0,0 +1,113 @@ +/** + * Copyright IBM Corp. 2016, 2025 + * SPDX-License-Identifier: BUSL-1.1 + */ + +import { expect, type Page } from '@playwright/test'; +import { ALL_ENGINES } from '../../lib/core/addon/utils/all-engines-metadata'; + +export const findEngineDisplayName = (engineType: string) => { + const engine = ALL_ENGINES.find((e) => e.type === engineType); + return engine ? engine.displayName : engineType; +}; + +const configurableEngines = ALL_ENGINES.filter((engine) => engine.isConfigurable).map( + (engine) => engine.type +); + +export class ConfigurationSettingsPage { + constructor(protected page: Page) {} + + async navigateToConfiguration(path: string) { + await this.page.getByRole('button', { name: 'Manage', exact: true }).click(); + await this.page.getByRole('link', { name: 'Configure' }).click(); + await expect(this.page.getByRole('heading', { name: `${path} configuration` })).toContainText( + `${path} configuration` + ); + } + + async assertPluginSettingsTabActive(engineType: string) { + const engineDisplayName = findEngineDisplayName(engineType); + await expect(this.page.getByRole('link', { name: 'General settings' })).not.toHaveClass(/active/); + await expect(this.page.getByRole('link', { name: `${engineDisplayName} settings` })).toHaveClass( + /active/ + ); + await expect(this.page.getByRole('link', { name: `${engineDisplayName} settings` })).toContainText( + `${engineDisplayName} settings` + ); + } + + async navigateToGeneralSettings(engineType: string) { + const engineDisplayName = findEngineDisplayName(engineType); + await this.page.getByRole('link', { name: 'General settings' }).click(); + await expect(this.page.getByRole('link', { name: 'General settings' })).toHaveClass(/active/); + + if (configurableEngines.includes(engineDisplayName)) { + await expect( + this.page.getByRole('link', { + name: `${engineDisplayName} settings`, + }) + ).not.toHaveClass(/active/); + } + + await expect(this.page.getByRole('form', { name: 'general settings form' })).toBeVisible(); + } + + async editAndVerifyGeneralSettings(path: string, engineType: string, isExternalPlugin = false) { + await expect(this.page.getByText(`Engine type ${engineType}`)).toBeVisible(); + await expect(this.page.getByText('Running version')).toContainText('Running version'); + await expect(this.page.getByRole('group', { name: 'Path' })).toBeVisible(); + await expect(this.page.getByRole('button', { name: `copy ${path}/` })).toContainText(`${path}/`); + await expect(this.page.getByRole('group', { name: 'Accessor' })).toBeVisible(); + await expect( + this.page.getByText('Default time-to-live (TTL) How long secrets in this engine stay valid. seconds') + ).toBeVisible(); + + if (!isExternalPlugin) { + await this.page.getByRole('textbox', { name: 'Description' }).fill('some description'); + await this.page.getByRole('textbox', { name: 'Default time-to-live (TTL)time' }).fill('2'); + await this.page.getByRole('button', { name: 'Save changes' }).click(); + await expect(this.page.getByRole('alert', { name: 'Configuration saved' })).toBeVisible(); + await expect(this.page.getByRole('textbox', { name: 'Description' })).toHaveValue('some description'); + await expect(this.page.getByRole('textbox', { name: 'Default time-to-live (TTL)time' })).toHaveValue( + '2' + ); + } + } + + async verifyUnsavedChangesModalOnNavigateAway(path: string) { + // make a change to trigger the unsaved changes modal + await this.page.getByRole('textbox', { name: 'Description' }).fill('unsaved changes test'); + + // try to navigate away + this.page.getByRole('link', { name: 'Back to main navigation' }).click(); + + // verify the unsaved changes modal appears + const modal = this.page.getByRole('dialog', { name: 'Unsaved changes' }); + await expect(modal).toBeVisible(); + await expect( + this.page.getByText("You've made changes to the following: Description Would you like to apply them?") + ).toBeVisible(); + + // save unsaved changes + await modal.getByRole('button', { name: 'Save changes' }).click(); + + // verify still on the configuration page and description was updated + await this.page.getByRole('link', { name: 'Secrets', exact: true }).click(); + await this.page.getByRole('link', { name: path }).click(); + await this.page.getByRole('button', { name: 'Manage' }).click(); + await this.page.getByRole('link', { name: 'Configure' }).click(); + await this.page.getByRole('link', { name: 'General settings' }).click(); + await expect(this.page.getByRole('textbox', { name: 'Description' })).toHaveValue('unsaved changes test'); + + // make another change to trigger the unsaved changes modal + await this.page.getByRole('textbox', { name: 'Description' }).fill('unsaved changes test 2'); + + // try to navigate away again + this.page.getByRole('link', { name: 'Back to main navigation' }).click(); + + // dismiss the modal + await modal.getByRole('button', { name: 'Discard changes' }).click(); + await expect(this.page.getByRole('link', { name: 'Dashboard' })).toBeVisible(); + } +} diff --git a/ui/e2e/tests/superuser/keymgmt-tune-external.ent.spec.ts b/ui/e2e/tests/superuser/keymgmt-tune-external.ent.spec.ts index 6acdd0ac4e..1642e67a04 100644 --- a/ui/e2e/tests/superuser/keymgmt-tune-external.ent.spec.ts +++ b/ui/e2e/tests/superuser/keymgmt-tune-external.ent.spec.ts @@ -4,6 +4,7 @@ */ import { expect, test } from '@playwright/test'; +import { ConfigurationSettingsPage } from '../../pages/configuration-settings'; const PINNED_PLUGIN_DATA = { data: { @@ -100,6 +101,8 @@ const UPDATED_KEYMGMT_EXTERNAL_MOUNT_DATA = { }; test('tune external keymgmt workflow', async ({ page }) => { + const configurationSettingsPage = new ConfigurationSettingsPage(page); + await test.step('mock the keymgmt pinned version response', async () => { await page.route('**v1/sys/plugins/pins/secret/vault-plugin-secrets-keymgmt', async (route) => { if (route.request().method() === 'GET') { @@ -142,7 +145,7 @@ test('tune external keymgmt workflow', async ({ page }) => { }); }); - await test.step('mock the initial keymgmt external tunde response', async () => { + await test.step('mock the initial keymgmt external tune response', async () => { await page.route('**/v1/sys/mounts/keymgmt-external/tune', async (route) => { if (route.request().method() === 'POST') { await route.fulfill({ @@ -159,11 +162,10 @@ test('tune external keymgmt workflow', async ({ page }) => { await test.step("navigate to the external keymgmt mount's general settings page", async () => { await page.goto('secrets-engines/keymgmt-external/list'); - await page.getByRole('button', { name: 'Manage' }).click(); - await page.getByRole('link', { name: 'Configure' }).click(); - await expect(page.getByRole('heading', { level: 1 })).toContainText('keymgmt-external configuration'); - await expect(page.getByRole('link', { name: 'General settings' })).toBeVisible(); - await expect(page.getByRole('paragraph').nth(2)).toContainText('vault-plugin-secrets-keymgmt'); + const path = 'keymgmt-external'; + const engineType = 'vault-plugin-secrets-keymgmt'; + await configurationSettingsPage.navigateToConfiguration(path); + await configurationSettingsPage.editAndVerifyGeneralSettings(path, engineType, true); await expect(page.getByRole('paragraph').nth(3)).toContainText('v0.17.0+ent (Pinned)'); }); diff --git a/ui/e2e/tests/superuser/keymgmt.spec.ts b/ui/e2e/tests/superuser/keymgmt.spec.ts index 866c08f377..07e34acc75 100644 --- a/ui/e2e/tests/superuser/keymgmt.spec.ts +++ b/ui/e2e/tests/superuser/keymgmt.spec.ts @@ -5,6 +5,7 @@ import { expect, test } from '@playwright/test'; import { BasePage } from '../../pages/base'; +import { ConfigurationSettingsPage } from '../../pages/configuration-settings'; test('keymgmt workflow', async ({ page }) => { const basePage = new BasePage(page); @@ -86,3 +87,49 @@ test('keymgmt workflow', async ({ page }) => { await page.getByRole('button', { name: 'Dismiss' }).click(); }); }); + +test('keymgmt tune workflow', async ({ page }) => { + const basePage = new BasePage(page); + const configurationSettingsPage = new ConfigurationSettingsPage(page); + + const path = 'keymgmt-tune'; + const engineType = 'keymgmt'; + + await test.step('enable keymgmt secrets engine mount', async () => { + await basePage.enableEngine(engineType, path); + }); + + await test.step('navigate to configuration page from manage dropdown ', async () => { + await configurationSettingsPage.navigateToConfiguration(path); + }); + + // keymgmt does not have plugin settings, so we only need to test for general settings + + await test.step('navigate and verify general settings form', async () => { + await configurationSettingsPage.navigateToGeneralSettings(engineType); + await configurationSettingsPage.editAndVerifyGeneralSettings(path, engineType); + await page.getByRole('link', { name: 'Exit configuration' }).click(); + }); + + await test.step('ensure that we navigate back to the keymgmt overview page when Exit configuration is clicked', async () => { + await expect( + page + .locator('div') + .filter({ hasText: `${path} Manage Create provider` }) + .nth(3) + ).toBeVisible(); + }); + + await test.step('verify unsaved changes modal works in general settings', async () => { + // Navigate back to general settings + await configurationSettingsPage.navigateToConfiguration(path); + await configurationSettingsPage.navigateToGeneralSettings(engineType); + + // Test Unsaved changes modal + await configurationSettingsPage.verifyUnsavedChangesModalOnNavigateAway(path); + }); + + await test.step('clean up and disable engine', async () => { + await basePage.disableEngine(path); + }); +}); diff --git a/ui/e2e/tests/superuser/kubernetes-secrets.spec.ts b/ui/e2e/tests/superuser/kubernetes-secrets.spec.ts index 3038d1fa01..57759df65c 100644 --- a/ui/e2e/tests/superuser/kubernetes-secrets.spec.ts +++ b/ui/e2e/tests/superuser/kubernetes-secrets.spec.ts @@ -5,6 +5,7 @@ import { test, expect } from '@playwright/test'; import { BasePage } from '../../pages/base'; +import { ConfigurationSettingsPage } from '../../pages/configuration-settings'; test('kubernetes secrets workflow', async ({ page }) => { const basePage = new BasePage(page); @@ -52,29 +53,6 @@ test('kubernetes secrets workflow', async ({ page }) => { await basePage.dismissFlashMessages(); }); - await test.step('edit kubernetes configuration', async () => { - await page.getByRole('button', { name: 'Manage' }).click(); - await page.getByRole('link', { name: 'Configure' }).click(); - await page.getByRole('link', { name: 'Edit configuration' }).click(); - await expect(page.getByRole('textbox', { name: 'Service account JWT' })).toBeEmpty(); - await page.getByRole('textbox', { name: 'Kubernetes host' }).fill('https://127.0.0.1:8443'); - await page.getByRole('textbox', { name: 'Kubernetes CA Certificate' }).fill('-----NEW CERT-----'); - await page.getByRole('button', { name: 'Save' }).click(); - await page.getByRole('button', { name: 'Confirm' }).click(); - await expect( - page.locator('.info-table-row').filter({ - hasText: 'Kubernetes host https://127.0.0.1:8443', - }) - ).toBeVisible(); - await expect( - page.locator('.info-table-row').filter({ - hasText: 'Certificate PEM Format -----NEW CERT-----', - }) - ).toBeVisible(); - await page.getByRole('link', { name: 'Exit configuration' }).click(); - await basePage.dismissFlashMessages(); - }); - await test.step('create kubernetes role', async () => { await page.getByRole('link', { name: 'Roles' }).click(); await expect(page.locator('section')).toContainText( @@ -206,4 +184,67 @@ test('kubernetes secrets workflow', async ({ page }) => { 'This will generate credentials using the role test-role.' ); }); + await test.step('clean up and disable engine', async () => { + await basePage.disableEngine('kubernetes'); + }); +}); + +test('kubernetes tune workflow', async ({ page }) => { + const basePage = new BasePage(page); + const configurationSettingsPage = new ConfigurationSettingsPage(page); + + const path = 'kubernetes-tune'; + const engineType = 'kubernetes'; + + await test.step('enable kubernetes secrets engine mount', async () => { + await basePage.enableEngine(engineType, path); + }); + + await test.step('navigate to configuration page from manage dropdown and ensure plugin settings tab is active', async () => { + await configurationSettingsPage.navigateToConfiguration(path); + await configurationSettingsPage.assertPluginSettingsTabActive(engineType); + }); + + await test.step('configure kubernetes plugin settings', async () => { + await page.locator('div').filter({ hasText: 'Manual configuration Generate' }).nth(4).click(); + await page.getByRole('textbox', { name: 'Kubernetes host' }).fill('https://192.168.99.100:8443'); + await page.getByRole('textbox', { name: 'Service account JWT' }).fill('test-jwt'); + await page.getByRole('textbox', { name: 'Kubernetes CA Certificate' }).fill('-----CERTIFICATE-----'); + await page.getByRole('button', { name: 'Save' }).click(); + }); + + await test.step('ensure kubernetes plugin settings was saved', async () => { + await expect(page.locator('section')).toContainText('Kubernetes host https://192.168.99.100:8443'); + }); + + await test.step('edit plugin settings configuration', async () => { + await page.getByRole('link', { name: 'Edit configuration' }).click(); + await page.getByRole('textbox', { name: 'Kubernetes host' }).fill('https://192.168.99.100:8448'); + await page.getByRole('button', { name: 'Save' }).click(); + await page.getByRole('button', { name: 'Confirm' }).click(); + await expect(page.locator('section')).toContainText('Kubernetes host https://192.168.99.100:8448'); + }); + + await test.step('navigate and verify general settings form', async () => { + await configurationSettingsPage.navigateToGeneralSettings(engineType); + await configurationSettingsPage.editAndVerifyGeneralSettings(path, engineType); + await page.getByRole('link', { name: 'Exit configuration' }).click(); + }); + + await test.step('ensure that we navigate back to the kubernetes overview page when Exit configuration is clicked', async () => { + await expect(page.getByText(`Vault Secrets engines ${path} ${path} Kubernetes Manage`)).toBeVisible(); + }); + + await test.step('verify unsaved changes modal works in general settings', async () => { + // Navigate back to general settings + await configurationSettingsPage.navigateToConfiguration(path); + await configurationSettingsPage.navigateToGeneralSettings(engineType); + + // Test Unsaved changes modal + await configurationSettingsPage.verifyUnsavedChangesModalOnNavigateAway(path); + }); + + await test.step('clean up and disable engine', async () => { + await basePage.disableEngine(path); + }); }); diff --git a/ui/e2e/tests/superuser/kv.spec.ts b/ui/e2e/tests/superuser/kv.spec.ts index 17e2fe7d22..e5674c8bbb 100644 --- a/ui/e2e/tests/superuser/kv.spec.ts +++ b/ui/e2e/tests/superuser/kv.spec.ts @@ -5,6 +5,7 @@ import { test, expect } from '@playwright/test'; import { BasePage } from '../../pages/base'; +import { ConfigurationSettingsPage } from '../../pages/configuration-settings'; test('kvv2 workflow', async ({ page }) => { const basePage = new BasePage(page); @@ -134,3 +135,57 @@ test('kvv2 workflow', async ({ page }) => { await page.getByRole('link', { name: 'View policy' }).click(); await expect(page.getByRole('heading', { name: 'foo-policy' })).toBeVisible(); }); + +test('kvv2 tune workflow', async ({ page }) => { + const basePage = new BasePage(page); + const configurationSettingsPage = new ConfigurationSettingsPage(page); + + const path = 'kv-tune'; + const engineType = 'kv'; + + await test.step('enable kvv2 secrets engine mount', async () => { + await basePage.enableEngine(engineType, path); + }); + + await test.step('navigate to configuration page from manage dropdown and ensure plugin settings tab is active', async () => { + await configurationSettingsPage.navigateToConfiguration(path); + await configurationSettingsPage.assertPluginSettingsTabActive(engineType); + }); + + await test.step('edit plugin settings configuration', async () => { + await page.getByRole('link', { name: 'Edit configuration' }).click(); + await page.getByRole('link', { name: 'Edit configuration' }).click(); + await page.locator('#max_versions').fill('2'); + await page.locator('#label-cas_required').check(); + await page.getByRole('button', { name: 'Save' }).click(); + await expect(page.getByText('Require check and set Yes')).toBeVisible(); + }); + + await test.step('navigate and verify general settings form', async () => { + await configurationSettingsPage.navigateToGeneralSettings(engineType); + await configurationSettingsPage.editAndVerifyGeneralSettings(path, engineType); + await page.getByRole('link', { name: 'Exit configuration' }).click(); + }); + + await test.step('ensure that we navigate back to the kv overview page when Exit configuration is clicked', async () => { + await expect( + page + .locator('div') + .filter({ hasText: `${path} version 2 KV Manage` }) + .nth(3) + ).toBeVisible(); + }); + + await test.step('verify unsaved changes modal works in general settings', async () => { + // Navigate back to general settings + await configurationSettingsPage.navigateToConfiguration(path); + await configurationSettingsPage.navigateToGeneralSettings(engineType); + + // Test Unsaved changes modal + await configurationSettingsPage.verifyUnsavedChangesModalOnNavigateAway(path); + }); + + await test.step('clean up and disable engine', async () => { + await basePage.disableEngine(path); + }); +}); diff --git a/ui/e2e/tests/superuser/pki.spec.ts b/ui/e2e/tests/superuser/pki.spec.ts index b3f5ae8473..e5007aea81 100644 --- a/ui/e2e/tests/superuser/pki.spec.ts +++ b/ui/e2e/tests/superuser/pki.spec.ts @@ -5,6 +5,7 @@ import { test, expect } from '@playwright/test'; import { BasePage } from '../../pages/base'; +import { ConfigurationSettingsPage } from '../../pages/configuration-settings'; test('pki workflow', async ({ page }) => { const basePage = new BasePage(page); @@ -144,3 +145,78 @@ test('pki workflow', async ({ page }) => { await page.getByText('Type to find an issuer...').click(); await expect(page.getByRole('option').first()).toBeVisible(); }); + +test('pki tune workflow', async ({ page }) => { + const basePage = new BasePage(page); + const configurationSettingsPage = new ConfigurationSettingsPage(page); + + const path = 'pki-tune'; + const engineType = 'pki'; + + await test.step('enable pki secrets engine mount', async () => { + await basePage.enableEngine(engineType, path, { + defaultLeaseTtl: { unit: 5, option: 'm' }, + maxLeaseTtl: { unit: 10, option: 'm' }, + }); + }); + + await test.step('navigate to configuration page from manage dropdown and ensure plugin settings tab is active', async () => { + await configurationSettingsPage.navigateToConfiguration(path); + await configurationSettingsPage.assertPluginSettingsTabActive(engineType); + }); + + await test.step('configure pki plugin settings', async () => { + await page.locator('label').filter({ hasText: 'Generate root Generates a new' }).click(); + await page.getByLabel('Type').selectOption('exported'); + await page.getByRole('textbox', { name: 'Common name' }).click(); + await page.getByRole('textbox', { name: 'Common name' }).fill('common-name-1'); + await page.getByRole('textbox', { name: 'Issuer name' }).click(); + await page.getByRole('textbox', { name: 'Issuer name' }).fill('issue-name-1'); + await page.getByRole('button', { name: 'Done' }).click(); + }); + + await test.step('ensure pki plugin settings was saved', async () => { + await expect(page.getByLabel('Next steps')).toContainText( + 'Next steps The private_key is only available once. Make sure you copy and save it now.' + ); + await expect(page.locator('section')).toContainText('Common name common-name-1'); + await expect(page.locator('section')).toContainText('Issuer name issue-name-1'); + await page.getByRole('button', { name: 'Done' }).click(); + }); + + // Navigate back to plugin settings page + await configurationSettingsPage.navigateToConfiguration(path); + + await test.step('edit plugin settings configuration', async () => { + await page.getByRole('link', { name: 'Edit configuration' }).click(); + await expect(page.locator('form')).toContainText('Cluster Config'); + await expect(page.getByText("Mount's API path Specifies")).toBeVisible(); + await page.getByRole('button', { name: 'Cancel' }).click(); + }); + + await test.step('navigate and verify general settings form', async () => { + // General settings + await configurationSettingsPage.navigateToGeneralSettings(engineType); + await configurationSettingsPage.editAndVerifyGeneralSettings(path, engineType); + await page.getByRole('link', { name: 'Exit configuration' }).click(); + }); + + await test.step('ensure that we navigate back to the pki overview page when Exit configuration is clicked', async () => { + await expect( + page.getByText(`Vault Secrets engines ${path} ${path} Generate policy Manage`) + ).toBeVisible(); + }); + + await test.step('verify unsaved changes modal works in general settings', async () => { + // Navigate back to general settings + await configurationSettingsPage.navigateToConfiguration(path); + await configurationSettingsPage.navigateToGeneralSettings(engineType); + + // Test Unsaved changes modal + await configurationSettingsPage.verifyUnsavedChangesModalOnNavigateAway(path); + }); + + await test.step('clean up and disable engine', async () => { + await basePage.disableEngine(path); + }); +}); diff --git a/ui/e2e/tests/superuser/transform.spec.ts b/ui/e2e/tests/superuser/transform.spec.ts index ce8662eac2..80629b02f9 100644 --- a/ui/e2e/tests/superuser/transform.spec.ts +++ b/ui/e2e/tests/superuser/transform.spec.ts @@ -5,6 +5,7 @@ import { expect, test } from '@playwright/test'; import { BasePage } from '../../pages/base'; +import { ConfigurationSettingsPage } from '../../pages/configuration-settings'; test('transform workflow', async ({ page }) => { const basePage = new BasePage(page); @@ -91,3 +92,49 @@ test('transform workflow', async ({ page }) => { await page.getByRole('button', { name: 'Dismiss' }).click(); }); }); + +test('transform tune workflow', async ({ page }) => { + const basePage = new BasePage(page); + const configurationSettingsPage = new ConfigurationSettingsPage(page); + + const path = 'transform-tune'; + const engineType = 'transform'; + + await test.step('enable transform secrets engine mount', async () => { + await basePage.enableEngine(engineType, path); + }); + + await test.step('navigate to configuration page from manage dropdown ', async () => { + await configurationSettingsPage.navigateToConfiguration(path); + }); + + // transform does not have plugin settings, so we only need to test for general settings + + await test.step('navigate and verify general settings form', async () => { + await configurationSettingsPage.navigateToGeneralSettings(engineType); + await configurationSettingsPage.editAndVerifyGeneralSettings(path, engineType); + await page.getByRole('link', { name: 'Exit configuration' }).click(); + }); + + await test.step('ensure that we navigate back to the transform overview page when Exit configuration is clicked', async () => { + await expect( + page + .locator('div') + .filter({ hasText: `${path} Manage Create transformation` }) + .nth(3) + ).toBeVisible(); + }); + + await test.step('verify unsaved changes modal works in general settings', async () => { + // Navigate back to general settings + await configurationSettingsPage.navigateToConfiguration(path); + await configurationSettingsPage.navigateToGeneralSettings(engineType); + + // Test Unsaved changes modal + await configurationSettingsPage.verifyUnsavedChangesModalOnNavigateAway(path); + }); + + await test.step('clean up and disable engine', async () => { + await basePage.disableEngine(path); + }); +}); diff --git a/ui/e2e/tests/superuser/transit.spec.ts b/ui/e2e/tests/superuser/transit.spec.ts index dbce1fa77f..c9c53add68 100644 --- a/ui/e2e/tests/superuser/transit.spec.ts +++ b/ui/e2e/tests/superuser/transit.spec.ts @@ -5,6 +5,7 @@ import { test, expect } from '@playwright/test'; import { BasePage } from '../../pages/base'; +import { ConfigurationSettingsPage } from '../../pages/configuration-settings'; test('transit workflow', async ({ page }) => { const basePage = new BasePage(page); @@ -82,3 +83,49 @@ test('transit workflow', async ({ page }) => { await expect(page.getByText('Results Valid')).toBeVisible(); await page.getByRole('button', { name: 'Close' }).click(); }); + +test('transit tune workflow', async ({ page }) => { + const basePage = new BasePage(page); + const configurationSettingsPage = new ConfigurationSettingsPage(page); + + const path = 'transit-tune'; + const engineType = 'transit'; + + await test.step('enable Transit secrets engine mount', async () => { + await basePage.enableEngine(engineType, path); + }); + + await test.step('navigate to configuration page from manage dropdown ', async () => { + await configurationSettingsPage.navigateToConfiguration(path); + }); + + // Transit does not have plugin settings, so we only need to test for general settings + + await test.step('navigate and verify general settings form', async () => { + await configurationSettingsPage.navigateToGeneralSettings(engineType); + await configurationSettingsPage.editAndVerifyGeneralSettings(path, engineType); + await page.getByRole('link', { name: 'Exit configuration' }).click(); + }); + + await test.step('ensure that we navigate back to the transit overview page when Exit configuration is clicked', async () => { + await expect( + page + .locator('div') + .filter({ hasText: `${path} Manage Create key` }) + .nth(3) + ).toBeVisible(); + }); + + await test.step('verify unsaved changes modal works in general settings', async () => { + // Navigate back to general settings + await configurationSettingsPage.navigateToConfiguration(path); + await configurationSettingsPage.navigateToGeneralSettings(engineType); + + // Test Unsaved changes modal + await configurationSettingsPage.verifyUnsavedChangesModalOnNavigateAway(path); + }); + + await test.step('clean up and disable engine', async () => { + await basePage.disableEngine(path); + }); +});