diff --git a/ui/app/components/mount-backend-form.hbs b/ui/app/components/mount-backend-form.hbs index 8cd2b88838..2aa615429b 100644 --- a/ui/app/components/mount-backend-form.hbs +++ b/ui/app/components/mount-backend-form.hbs @@ -5,7 +5,7 @@ -

+

{{#if this.showEnable}} {{#let (find-by "type" @mountModel.type @mountTypes) as |typeInfo|}} @@ -59,12 +59,12 @@ @text={{if (eq @mountType "secret") "Enable engine" "Enable method"}} @icon={{if this.mountBackend.isRunning "loading"}} type="submit" - data-test-mount-submit="true" + data-test-save disabled={{this.mountBackend.isRunning}} />
- +
{{#if this.invalidFormAlert}}
diff --git a/ui/tests/acceptance/auth/test-helper.js b/ui/tests/acceptance/auth/test-helper.js index dc0c7b8fff..531530d0af 100644 --- a/ui/tests/acceptance/auth/test-helper.js +++ b/ui/tests/acceptance/auth/test-helper.js @@ -3,13 +3,10 @@ * SPDX-License-Identifier: BUSL-1.1 */ -import { click, currentURL, fillIn } from '@ember/test-helpers'; +import { click, currentURL } from '@ember/test-helpers'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; - -const SELECTORS = { - mountType: (name) => `[data-test-mount-type="${name}"]`, - submit: '[data-test-mount-submit]', -}; +import { MOUNT_BACKEND_FORM } from 'vault/tests/helpers/components/mount-backend-form-selectors'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; const assertFields = (assert, fields, customSelectors = {}) => { fields.forEach((param) => { @@ -22,16 +19,14 @@ const assertFields = (assert, fields, customSelectors = {}) => { }; export default (test) => { test('it renders mount fields', async function (assert) { - await click(SELECTORS.mountType(this.type)); + await click(MOUNT_BACKEND_FORM.mountType(this.type)); await click(GENERAL.toggleGroup('Method Options')); assertFields(assert, this.mountFields, this.customSelectors); }); test('it renders tune fields', async function (assert) { // enable auth method to check tune fields - await click(SELECTORS.mountType(this.type)); - await fillIn(GENERAL.inputByAttr('path'), this.path); - await click(SELECTORS.submit); + await mountBackend(this.type, this.path); assert.strictEqual( currentURL(), `/vault/settings/auth/configure/${this.path}/configuration`, diff --git a/ui/tests/acceptance/enterprise-kmip-test.js b/ui/tests/acceptance/enterprise-kmip-test.js index 916cc31da0..8d3eac31a8 100644 --- a/ui/tests/acceptance/enterprise-kmip-test.js +++ b/ui/tests/acceptance/enterprise-kmip-test.js @@ -22,6 +22,7 @@ import rolesPage from 'vault/tests/pages/secrets/backend/kmip/roles'; import credentialsPage from 'vault/tests/pages/secrets/backend/kmip/credentials'; import mountSecrets from 'vault/tests/pages/settings/mount-secret-backend'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; import { allEngines } from 'vault/helpers/mountable-secret-engines'; import { mountEngineCmd, runCmd } from 'vault/tests/helpers/commands'; import { v4 as uuidv4 } from 'uuid'; @@ -29,18 +30,9 @@ import { v4 as uuidv4 } from 'uuid'; // port has a lower limit of 1024 const getRandomPort = () => Math.floor(Math.random() * 5000 + 1024); -const mount = async (backend) => { - const res = await runCmd(`write sys/mounts/${backend} type=kmip`); - await settled(); - if (res.includes('Error')) { - throw new Error(`Error mounting secrets engine: ${res}`); - } - return backend; -}; - const mountWithConfig = async (backend) => { const addr = `127.0.0.1:${getRandomPort()}`; - await mount(backend); + await runCmd(mountEngineCmd('kmip', backend), false); const res = await runCmd(`write ${backend}/config listen_addrs=${addr}`); if (res.includes('Error')) { throw new Error(`Error configuring KMIP: ${res}`); @@ -105,8 +97,8 @@ module('Acceptance | Enterprise | KMIP secrets', function (hooks) { const engine = allEngines().find((e) => e.type === 'kmip'); await mountSecrets.visit(); - await mountSecrets.selectType(engine.type); - await mountSecrets.path(this.backend).submit(); + await mountBackend(engine.type, `${engine.type}-${uuidv4()}`); + assert.strictEqual( currentRouteName(), `vault.cluster.secrets.backend.${engine.engineRoute}`, @@ -116,7 +108,8 @@ module('Acceptance | Enterprise | KMIP secrets', function (hooks) { }); test('it can configure a KMIP secrets engine', async function (assert) { - const backend = await mount(this.backend); + await runCmd(mountEngineCmd('kmip', this.backend)); + const backend = this.backend; await scopesPage.visit({ backend }); await settled(); await scopesPage.configurationLink(); diff --git a/ui/tests/acceptance/enterprise-kmse-test.js b/ui/tests/acceptance/enterprise-kmse-test.js index c1f503b813..19dc083428 100644 --- a/ui/tests/acceptance/enterprise-kmse-test.js +++ b/ui/tests/acceptance/enterprise-kmse-test.js @@ -10,6 +10,7 @@ import authPage from 'vault/tests/pages/auth'; import mountSecrets from 'vault/tests/pages/settings/mount-secret-backend'; import { setupMirage } from 'ember-cli-mirage/test-support'; import { allEngines } from 'vault/helpers/mountable-secret-engines'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; import { runCmd } from '../helpers/commands'; module('Acceptance | Enterprise | keymgmt', function (hooks) { @@ -27,9 +28,7 @@ module('Acceptance | Enterprise | keymgmt', function (hooks) { // delete any previous mount with same name await runCmd([`delete sys/mounts/${engine.type}`]); await mountSecrets.visit(); - await mountSecrets.selectType(engine.type); - await mountSecrets.path(engine.type); - await mountSecrets.submit(); + await mountBackend(engine.type, engine.type); assert.strictEqual( currentRouteName(), diff --git a/ui/tests/acceptance/enterprise-transform-test.js b/ui/tests/acceptance/enterprise-transform-test.js index 18d3702414..37347a89a9 100644 --- a/ui/tests/acceptance/enterprise-transform-test.js +++ b/ui/tests/acceptance/enterprise-transform-test.js @@ -5,7 +5,7 @@ import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; -import { currentURL, click, settled, currentRouteName } from '@ember/test-helpers'; +import { currentURL, click, settled, currentRouteName, visit } from '@ember/test-helpers'; import { create } from 'ember-cli-page-object'; import { selectChoose } from 'ember-power-select/test-support'; import { typeInSearch, clickTrigger } from 'ember-power-select/test-support/helpers'; @@ -19,16 +19,11 @@ import alphabetsPage from 'vault/tests/pages/secrets/backend/transform/alphabets import searchSelect from 'vault/tests/pages/components/search-select'; import { runCmd } from '../helpers/commands'; import { allEngines } from 'vault/helpers/mountable-secret-engines'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; +import { v4 as uuidv4 } from 'uuid'; const searchSelectComponent = create(searchSelect); -const mount = async () => { - const path = `transform-${Date.now()}`; - await mountSecrets.enable('transform', path); - await settled(); - return path; -}; - const newTransformation = async (backend, name, submit = false) => { const transformationName = name || 'foo'; await transformationsPage.visitCreate({ backend }); @@ -75,9 +70,7 @@ module('Acceptance | Enterprise | Transform secrets', function (hooks) { // delete any previous mount with same name await runCmd([`delete sys/mounts/${engine.type}`]); await mountSecrets.visit(); - await mountSecrets.selectType(engine.type); - await mountSecrets.path(engine.type); - await mountSecrets.submit(); + await mountBackend(engine.type, engine.type); assert.strictEqual( currentRouteName(), @@ -108,7 +101,9 @@ module('Acceptance | Enterprise | Transform secrets', function (hooks) { }); test('it can create a transformation and add itself to the role attached', async function (assert) { - const backend = await mount(); + await visit('/vault/settings/mount-secret-backend'); + const backend = `transform-${uuidv4()}`; + await mountBackend('transform', backend); const transformationName = 'foo'; const roleName = 'foo-role'; await settled(); @@ -158,7 +153,9 @@ module('Acceptance | Enterprise | Transform secrets', function (hooks) { test('it can create a role and add itself to the transformation attached', async function (assert) { const roleName = 'my-role'; - const backend = await mount(); + await visit('/vault/settings/mount-secret-backend'); + const backend = `transform-${uuidv4()}`; + await mountBackend('transform', backend); // create transformation without role await newTransformation(backend, 'a-transformation', true); await click(`[data-test-secret-breadcrumb="${backend}"] a`); @@ -197,7 +194,9 @@ module('Acceptance | Enterprise | Transform secrets', function (hooks) { test('it adds a role to a transformation when added to a role', async function (assert) { const roleName = 'role-test'; - const backend = await mount(); + await visit('/vault/settings/mount-secret-backend'); + const backend = `transform-${uuidv4()}`; + await mountBackend('transform', backend); const transformation = await newTransformation(backend, 'b-transformation', true); await newRole(backend, roleName); await transformationsPage.visitShow({ backend, id: transformation }); @@ -207,7 +206,9 @@ module('Acceptance | Enterprise | Transform secrets', function (hooks) { test('it shows a message if an update fails after save', async function (assert) { const roleName = 'role-remove'; - const backend = await mount(); + await visit('/vault/settings/mount-secret-backend'); + const backend = `transform-${uuidv4()}`; + await mountBackend('transform', backend); // Create transformation const transformation = await newTransformation(backend, 'c-transformation', true); // create role @@ -244,7 +245,9 @@ module('Acceptance | Enterprise | Transform secrets', function (hooks) { test('it allows creation and edit of a template', async function (assert) { const templateName = 'my-template'; - const backend = await mount(); + await visit('/vault/settings/mount-secret-backend'); + const backend = `transform-${uuidv4()}`; + await mountBackend('transform', backend); await click('[data-test-secret-list-tab="Templates"]'); assert.strictEqual( @@ -286,7 +289,9 @@ module('Acceptance | Enterprise | Transform secrets', function (hooks) { test('it allows creation and edit of an alphabet', async function (assert) { const alphabetName = 'vowels-only'; - const backend = await mount(); + await visit('/vault/settings/mount-secret-backend'); + const backend = `transform-${uuidv4()}`; + await mountBackend('transform', backend); await click('[data-test-secret-list-tab="Alphabets"]'); assert.strictEqual( diff --git a/ui/tests/acceptance/secrets/backend/alicloud/secret-test.js b/ui/tests/acceptance/secrets/backend/alicloud/secret-test.js index e1f5114e7c..975948383a 100644 --- a/ui/tests/acceptance/secrets/backend/alicloud/secret-test.js +++ b/ui/tests/acceptance/secrets/backend/alicloud/secret-test.js @@ -11,6 +11,7 @@ import { v4 as uuidv4 } from 'uuid'; import mountSecrets from 'vault/tests/pages/settings/mount-secret-backend'; import backendsPage from 'vault/tests/pages/secrets/backends'; import authPage from 'vault/tests/pages/auth'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; module('Acceptance | alicloud/enable', function (hooks) { setupApplicationTest(hooks); @@ -24,10 +25,7 @@ module('Acceptance | alicloud/enable', function (hooks) { const enginePath = `alicloud-${this.uid}`; await mountSecrets.visit(); await settled(); - await mountSecrets.selectType('alicloud'); - await settled(); - await mountSecrets.path(enginePath).submit(); - await settled(); + await mountBackend('alicloud', enginePath); assert.strictEqual( currentRouteName(), diff --git a/ui/tests/acceptance/secrets/backend/aws/aws-configuration-test.js b/ui/tests/acceptance/secrets/backend/aws/aws-configuration-test.js index 605bd26b3c..1f11e3f84c 100644 --- a/ui/tests/acceptance/secrets/backend/aws/aws-configuration-test.js +++ b/ui/tests/acceptance/secrets/backend/aws/aws-configuration-test.js @@ -16,6 +16,7 @@ import { runCmd } from 'vault/tests/helpers/commands'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; import { overrideResponse } from 'vault/tests/helpers/stubs'; import { SECRET_ENGINE_SELECTORS as SES } from 'vault/tests/helpers/secret-engine/secret-engine-selectors'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; import { createConfig, expectedConfigKeys, @@ -46,9 +47,7 @@ module('Acceptance | aws | configuration', function (hooks) { const path = `aws-${this.uid}`; // in this test go through the full mount process. Bypass this step in later tests. await visit('/vault/settings/mount-secret-backend'); - await click(SES.mountType('aws')); - await fillIn(GENERAL.inputByAttr('path'), path); - await click(SES.mountSubmit); + await mountBackend('aws', path); await click(SES.configTab); assert.dom(GENERAL.emptyStateTitle).hasText('AWS not configured'); assert.dom(GENERAL.emptyStateActions).hasText('Configure AWS'); diff --git a/ui/tests/acceptance/secrets/backend/gcpkms/secrets-test.js b/ui/tests/acceptance/secrets/backend/gcpkms/secrets-test.js index fba46e0bdd..efe0221581 100644 --- a/ui/tests/acceptance/secrets/backend/gcpkms/secrets-test.js +++ b/ui/tests/acceptance/secrets/backend/gcpkms/secrets-test.js @@ -11,6 +11,7 @@ import { v4 as uuidv4 } from 'uuid'; import mountSecrets from 'vault/tests/pages/settings/mount-secret-backend'; import backendsPage from 'vault/tests/pages/secrets/backends'; import authPage from 'vault/tests/pages/auth'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; module('Acceptance | gcpkms/enable', function (hooks) { setupApplicationTest(hooks); @@ -25,9 +26,8 @@ module('Acceptance | gcpkms/enable', function (hooks) { const enginePath = `gcpkms-${this.uid}`; await mountSecrets.visit(); await settled(); - await mountSecrets.selectType('gcpkms'); - await mountSecrets.path(enginePath).submit(); - await settled(); + await mountBackend('gcpkms', enginePath); + assert.strictEqual( currentRouteName(), 'vault.cluster.secrets.backends', diff --git a/ui/tests/acceptance/secrets/backend/kv/secret-test.js b/ui/tests/acceptance/secrets/backend/kv/secret-test.js index 184cfd83e1..b182a2ddd1 100644 --- a/ui/tests/acceptance/secrets/backend/kv/secret-test.js +++ b/ui/tests/acceptance/secrets/backend/kv/secret-test.js @@ -19,6 +19,7 @@ import { writeSecret, writeVersionedSecret } from 'vault/tests/helpers/kv/kv-run import { runCmd } from 'vault/tests/helpers/commands'; import { PAGE } from 'vault/tests/helpers/kv/kv-selectors'; import codemirror from 'vault/tests/helpers/codemirror'; +import { MOUNT_BACKEND_FORM } from 'vault/tests/helpers/components/mount-backend-form-selectors'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; import { SECRET_ENGINE_SELECTORS as SS } from 'vault/tests/helpers/secret-engine/secret-engine-selectors'; @@ -49,15 +50,14 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) { const enginePath = `kv-secret-${this.uid}`; const maxVersion = '101'; await mountSecrets.visit(); - await click('[data-test-mount-type="kv"]'); - - await fillIn('[data-test-input="path"]', enginePath); + await click(MOUNT_BACKEND_FORM.mountType('kv')); + await fillIn(GENERAL.inputByAttr('path'), enginePath); await fillIn('[data-test-input="maxVersions"]', maxVersion); await click('[data-test-input="casRequired"]'); await click('[data-test-toggle-label="Automate secret deletion"]'); await fillIn('[data-test-select="ttl-unit"]', 's'); await fillIn('[data-test-ttl-value="Automate secret deletion"]', '1'); - await click('[data-test-mount-submit="true"]'); + await click(GENERAL.saveButton); await click(PAGE.secretTab('Configuration')); @@ -138,8 +138,11 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) { this.backend = `kv-v1-${this.uid}`; // mount version 1 engine await mountSecrets.visit(); - await mountSecrets.selectType('kv'); - await mountSecrets.path(this.backend).toggleOptions().version(1).submit(); + await click(MOUNT_BACKEND_FORM.mountType('kv')); + await fillIn(GENERAL.inputByAttr('path'), this.backend); + await click(GENERAL.toggleGroup('Method Options')); + await mountSecrets.version(1); + await click(GENERAL.saveButton); }); hooks.afterEach(async function () { await runCmd([`delete sys/mounts/${this.backend}`]); diff --git a/ui/tests/acceptance/secrets/backend/ldap/overview-test.js b/ui/tests/acceptance/secrets/backend/ldap/overview-test.js index 1490e40e00..c2210d57b8 100644 --- a/ui/tests/acceptance/secrets/backend/ldap/overview-test.js +++ b/ui/tests/acceptance/secrets/backend/ldap/overview-test.js @@ -10,10 +10,11 @@ import { v4 as uuidv4 } from 'uuid'; import ldapMirageScenario from 'vault/mirage/scenarios/ldap'; import ldapHandlers from 'vault/mirage/handlers/ldap'; import authPage from 'vault/tests/pages/auth'; -import { click, fillIn, visit } from '@ember/test-helpers'; +import { click, visit } from '@ember/test-helpers'; import { selectChoose } from 'ember-power-select/test-support'; import { isURL, visitURL } from 'vault/tests/helpers/ldap/ldap-helpers'; import { deleteEngineCmd, mountEngineCmd, runCmd } from 'vault/tests/helpers/commands'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; module('Acceptance | ldap | overview', function (hooks) { setupApplicationTest(hooks); @@ -35,9 +36,7 @@ module('Acceptance | ldap | overview', function (hooks) { const backend = 'ldap-test-mount'; await visit('/vault/secrets'); await click('[data-test-enable-engine]'); - await click('[data-test-mount-type="ldap"]'); - await fillIn('[data-test-input="path"]', backend); - await click('[data-test-mount-submit]'); + await mountBackend('ldap', backend); assert.true(isURL('overview', backend), 'Transitions to ldap overview route on mount success'); assert.dom('[data-test-header-title]').hasText(backend); // cleanup mounted engine diff --git a/ui/tests/acceptance/secrets/backend/ssh/configuration-test.js b/ui/tests/acceptance/secrets/backend/ssh/configuration-test.js index 27d3c31ffc..0ad832839e 100644 --- a/ui/tests/acceptance/secrets/backend/ssh/configuration-test.js +++ b/ui/tests/acceptance/secrets/backend/ssh/configuration-test.js @@ -3,7 +3,7 @@ * SPDX-License-Identifier: BUSL-1.1 */ -import { click, fillIn, currentURL, visit, waitFor } from '@ember/test-helpers'; +import { click, currentURL, visit, waitFor } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import { v4 as uuidv4 } from 'uuid'; @@ -14,6 +14,7 @@ import { setupMirage } from 'ember-cli-mirage/test-support'; import { runCmd } from 'vault/tests/helpers/commands'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; import { SECRET_ENGINE_SELECTORS as SES } from 'vault/tests/helpers/secret-engine/secret-engine-selectors'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; import { configUrl } from 'vault/tests/helpers/secret-engine/secret-engine-helpers'; import { overrideResponse } from 'vault/tests/helpers/stubs'; @@ -31,9 +32,7 @@ module('Acceptance | ssh | configuration', function (hooks) { const sshPath = `ssh-${this.uid}`; // in this test go through the full mount process. Bypass this step in later tests. await visit('/vault/settings/mount-secret-backend'); - await click(SES.mountType('ssh')); - await fillIn(GENERAL.inputByAttr('path'), sshPath); - await click(SES.mountSubmit); + await mountBackend('ssh', sshPath); await click(SES.configTab); assert.dom(GENERAL.emptyStateTitle).hasText('SSH not configured'); assert.dom(GENERAL.emptyStateActions).hasText('Configure SSH'); diff --git a/ui/tests/acceptance/secrets/backend/ssh/roles-test.js b/ui/tests/acceptance/secrets/backend/ssh/roles-test.js index 7b49364079..d684a1a2a0 100644 --- a/ui/tests/acceptance/secrets/backend/ssh/roles-test.js +++ b/ui/tests/acceptance/secrets/backend/ssh/roles-test.js @@ -106,6 +106,7 @@ module('Acceptance | ssh | roles', function (hooks) { }, }, ]; + test('it creates roles, generates keys and deletes roles', async function (assert) { assert.expect(28); const sshPath = `ssh-${this.uid}`; @@ -150,8 +151,7 @@ module('Acceptance | ssh | roles', function (hooks) { await settled(); // eslint-disable-line role.assertAfterGenerate(assert, sshPath); - // click the "Back" button - await click(SES.backButton); + await click(GENERAL.backButton); assert.dom('[data-test-secret-generate-form]').exists(`${role.type}: back takes you back to the form`); await click(GENERAL.cancelButton); @@ -175,13 +175,22 @@ module('Acceptance | ssh | roles', function (hooks) { await runCmd(`delete sys/mounts/${sshPath}`); }); module('Acceptance | ssh | otp role', function () { + const createOTPRole = async (name) => { + await fillIn(GENERAL.inputByAttr('name'), name); + await fillIn(GENERAL.inputByAttr('keyType'), name); + await click(GENERAL.toggleGroup('Options')); + await fillIn(GENERAL.inputByAttr('keyType'), 'otp'); + await fillIn(GENERAL.inputByAttr('defaultUser'), 'admin'); + await fillIn(GENERAL.inputByAttr('cidrList'), '0.0.0.0/0'); + await click(SES.ssh.createRole); + }; test('it deletes a role from list view', async function (assert) { assert.expect(2); const path = `ssh-${this.uid}`; await enablePage.enable('ssh', path); await settled(); await editPage.visitRoot({ backend: path }); - await editPage.createOTPRole('role'); + await createOTPRole('role'); await settled(); await showPage.visit({ backend: path, id: 'role' }); await settled(); @@ -203,7 +212,7 @@ module('Acceptance | ssh | roles', function (hooks) { await enablePage.enable('ssh', path); await settled(); await editPage.visitRoot({ backend: path }); - await editPage.createOTPRole('role'); + await createOTPRole('role'); await settled(); assert.strictEqual( currentRouteName(), @@ -222,11 +231,11 @@ module('Acceptance | ssh | roles', function (hooks) { 'navs to the credentials page' ); - await generatePage.generateOTP(); - await settled(); + await fillIn(GENERAL.inputByAttr('username'), 'admin'); + await fillIn(GENERAL.inputByAttr('ip'), '192.168.1.1'); + await click(GENERAL.saveButton); assert.ok(generatePage.warningIsPresent, 'shows warning'); - await generatePage.back(); - await settled(); + await click(GENERAL.backButton); assert.ok(generatePage.userIsPresent, 'clears generate, shows user input'); assert.ok(generatePage.ipIsPresent, 'clears generate, shows ip input'); // cleanup diff --git a/ui/tests/acceptance/settings-test.js b/ui/tests/acceptance/settings-test.js index a2c005a4af..811bfd3bf0 100644 --- a/ui/tests/acceptance/settings-test.js +++ b/ui/tests/acceptance/settings-test.js @@ -3,7 +3,7 @@ * SPDX-License-Identifier: BUSL-1.1 */ -import { currentURL, find, visit, settled, click } from '@ember/test-helpers'; +import { currentURL, visit, click, fillIn } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import { v4 as uuidv4 } from 'uuid'; @@ -13,6 +13,7 @@ import mountSecrets from 'vault/tests/pages/settings/mount-secret-backend'; import authPage from 'vault/tests/pages/auth'; import { deleteEngineCmd, mountEngineCmd, runCmd } from 'vault/tests/helpers/commands'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; +import { MOUNT_BACKEND_FORM } from 'vault/tests/helpers/components/mount-backend-form-selectors'; const { searchSelect } = GENERAL; @@ -31,22 +32,24 @@ module('Acceptance | secret engine mount settings', function (hooks) { // mount unsupported backend await visit('/vault/settings/mount-secret-backend'); - assert.strictEqual(currentURL(), '/vault/settings/mount-secret-backend'); - - await mountSecrets.selectType(type); - await mountSecrets - .path(path) - .toggleOptions() - .enableDefaultTtl() - .defaultTTLUnit('s') - .defaultTTLVal(100) - .submit(); - await settled(); - assert.ok( - find('[data-test-flash-message]').textContent.trim(), - `Successfully mounted '${type}' at '${path}'!` + assert.strictEqual( + currentURL(), + '/vault/settings/mount-secret-backend', + 'navigates to the mount secret backend page' ); - await settled(); + await click(MOUNT_BACKEND_FORM.mountType(type)); + await fillIn(GENERAL.inputByAttr('path'), path); + await click(GENERAL.toggleGroup('Method Options')); + await mountSecrets.enableDefaultTtl().defaultTTLUnit('s').defaultTTLVal(100); + await click(GENERAL.saveButton); + + assert + .dom(`${GENERAL.flashMessage}.is-success`) + .includesText( + `Success Successfully mounted the ${type} secrets engine at ${path}`, + 'flash message is shown after mounting' + ); + assert.strictEqual(currentURL(), `/vault/secrets`, 'redirects to secrets page'); // cleanup await runCmd(deleteEngineCmd(path)); diff --git a/ui/tests/acceptance/settings/auth/enable-test.js b/ui/tests/acceptance/settings/auth/enable-test.js index d82cc28130..ab483f4d2f 100644 --- a/ui/tests/acceptance/settings/auth/enable-test.js +++ b/ui/tests/acceptance/settings/auth/enable-test.js @@ -3,14 +3,14 @@ * SPDX-License-Identifier: BUSL-1.1 */ -import { click, currentRouteName, fillIn, visit } from '@ember/test-helpers'; +import { click, currentRouteName, visit } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import { v4 as uuidv4 } from 'uuid'; -import { GENERAL } from 'vault/tests/helpers/general-selectors'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; import { login } from 'vault/tests/helpers/auth/auth-helpers'; import { deleteAuthCmd, runCmd } from 'vault/tests/helpers/commands'; -import { SECRET_ENGINE_SELECTORS as SES } from 'vault/tests/helpers/secret-engine/secret-engine-selectors'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Acceptance | settings/auth/enable', function (hooks) { setupApplicationTest(hooks); @@ -26,9 +26,7 @@ module('Acceptance | settings/auth/enable', function (hooks) { const type = 'approle'; await visit('/vault/settings/auth/enable'); assert.strictEqual(currentRouteName(), 'vault.cluster.settings.auth.enable'); - await click(SES.mountType(type)); - await fillIn(GENERAL.inputByAttr('path'), path); - await click(SES.mountSubmit); + await mountBackend(type, path); assert .dom(GENERAL.latestFlashContent) .hasText(`Successfully mounted the ${type} auth method at ${path}.`); @@ -49,9 +47,7 @@ module('Acceptance | settings/auth/enable', function (hooks) { const path = `approle-config-${this.uid}`; const type = 'approle'; await visit('/vault/settings/auth/enable'); - await click(SES.mountType(type)); - await fillIn(GENERAL.inputByAttr('path'), path); - await click(SES.mountSubmit); + await mountBackend(type, path); // the config details is updated to query mount details from sys/internal/ui/mounts // but we still want these forms to continue using sys/auth which returns 0 for default ttl values // check tune form (right after enabling) diff --git a/ui/tests/acceptance/settings/mount-secret-backend-test.js b/ui/tests/acceptance/settings/mount-secret-backend-test.js index ee1e6e8d91..6a648b4514 100644 --- a/ui/tests/acceptance/settings/mount-secret-backend-test.js +++ b/ui/tests/acceptance/settings/mount-secret-backend-test.js @@ -30,6 +30,8 @@ import { mountableEngines } from 'vault/helpers/mountable-secret-engines'; // al import { supportedSecretBackends } from 'vault/helpers/supported-secret-backends'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; import { SECRET_ENGINE_SELECTORS as SES } from 'vault/tests/helpers/secret-engine/secret-engine-selectors'; +import { MOUNT_BACKEND_FORM } from 'vault/tests/helpers/components/mount-backend-form-selectors'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; import { SELECTORS as OIDC } from 'vault/tests/helpers/oidc-config'; import { adminOidcCreateRead, adminOidcCreate } from 'vault/tests/helpers/secret-engine/policy-generator'; import { WIF_ENGINES } from 'vault/helpers/mountable-secret-engines'; @@ -59,17 +61,17 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { await page.visit(); assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend'); - await page.selectType('kv'); + await click(MOUNT_BACKEND_FORM.mountType('kv')); + await fillIn(GENERAL.inputByAttr('path'), path); + await click(GENERAL.toggleGroup('Method Options')); await page - .path(path) - .toggleOptions() .enableDefaultTtl() .defaultTTLUnit('h') .defaultTTLVal(defaultTTLHours) .enableMaxTtl() .maxTTLUnit('h') - .maxTTLVal(maxTTLHours) - .submit(); + .maxTTLVal(maxTTLHours); + await click(GENERAL.saveButton); await configPage.visit({ backend: path }); assert.strictEqual(configPage.defaultTTL, `${this.calcDays(defaultTTLHours)}`, 'shows the proper TTL'); assert.strictEqual(configPage.maxTTL, `${this.calcDays(maxTTLHours)}`, 'shows the proper max TTL'); @@ -82,16 +84,16 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { await page.visit(); - assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend'); - await page.selectType('kv'); - await page - .path(path) - .toggleOptions() - .enableDefaultTtl() - .enableMaxTtl() - .maxTTLUnit('h') - .maxTTLVal(maxTTLHours) - .submit(); + assert.strictEqual( + currentRouteName(), + 'vault.cluster.settings.mount-secret-backend', + 'navigates to mount page' + ); + await click(MOUNT_BACKEND_FORM.mountType('kv')); + await fillIn(GENERAL.inputByAttr('path'), path); + await click(GENERAL.toggleGroup('Method Options')); + await page.enableDefaultTtl().enableMaxTtl().maxTTLUnit('h').maxTTLVal(maxTTLHours); + await click(GENERAL.saveButton); await configPage.visit({ backend: path }); assert.strictEqual(configPage.defaultTTL, '1 month 1 day', 'shows system default TTL'); assert.strictEqual(configPage.maxTTL, `${this.calcDays(maxTTLHours)}`, 'shows the proper max TTL'); @@ -100,7 +102,7 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { test('it sets the max ttl after pki chosen, resets after', async function (assert) { await page.visit(); assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend'); - await page.selectType('pki'); + await click(MOUNT_BACKEND_FORM.mountType('pki')); assert.dom('[data-test-input="maxLeaseTtl"]').exists(); assert .dom('[data-test-input="maxLeaseTtl"] [data-test-ttl-toggle]') @@ -109,8 +111,8 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { assert.dom('[data-test-input="maxLeaseTtl"] [data-test-select="ttl-unit"]').hasValue('d'); // Go back and choose a different type - await page.back(); - await page.selectType('database'); + await click(GENERAL.backButton); + await click(MOUNT_BACKEND_FORM.mountType('database')); assert.dom('[data-test-input="maxLeaseTtl"]').exists('3650'); assert .dom('[data-test-input="maxLeaseTtl"] [data-test-ttl-toggle]') @@ -131,13 +133,12 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { await page.visit(); assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend'); - await page.selectType('kv'); - await page.path(path).submit(); + await mountBackend('kv', path); await page.secretList(); await settled(); await page.enableEngine(); - await page.selectType('kv'); - await page.path(path).submit(); + await mountBackend('kv', path); + assert.dom('[data-test-message-error-description]').containsText(`path is already in use at ${path}`); assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend'); @@ -185,9 +186,11 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { await authPage.login(userToken); // create the engine await mountSecrets.visit(); - await mountSecrets.selectType('kv'); - await mountSecrets.path(enginePath).setMaxVersion(101).submit(); - await settled(); + await click(MOUNT_BACKEND_FORM.mountType('kv')); + await fillIn(GENERAL.inputByAttr('path'), enginePath); + await mountSecrets.setMaxVersion(101); + await click(GENERAL.saveButton); + assert .dom('[data-test-flash-message]') .containsText( @@ -213,8 +216,8 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { `delete sys/mounts/${engine.type}`, ]); await mountSecrets.visit(); - await mountSecrets.selectType(engine.type); - await mountSecrets.path(engine.type).submit(); + await mountBackend(engine.type, engine.type); + assert.strictEqual( currentRouteName(), `vault.cluster.secrets.backend.${engine.engineRoute}`, @@ -240,12 +243,13 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { `delete sys/mounts/${engine.type}`, ]); await mountSecrets.visit(); - await mountSecrets.selectType(engine.type); - await mountSecrets.path(engine.type); + await click(MOUNT_BACKEND_FORM.mountType(engine.type)); + await fillIn(GENERAL.inputByAttr('path'), engine.type); if (engine.type === 'kv') { - await mountSecrets.toggleOptions().version(1); + await click(GENERAL.toggleGroup('Method Options')); + await mountSecrets.version(1); } - await mountSecrets.submit(); + await click(GENERAL.saveButton); assert.strictEqual( currentRouteName(), @@ -269,8 +273,7 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { `delete sys/mounts/${engine.type}`, ]); await mountSecrets.visit(); - await mountSecrets.selectType(engine.type); - await mountSecrets.path(engine.type).submit(); + await mountBackend(engine.type, engine.type); assert.strictEqual( currentRouteName(), @@ -288,9 +291,7 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { `delete sys/mounts/${v2}`, ]); await mountSecrets.visit(); - await mountSecrets.selectType('kv'); - await mountSecrets.path(v2).submit(); - + await mountBackend('kv', v2); assert.strictEqual(currentURL(), `/vault/secrets/${v2}/kv/list`, `${v2} navigates to list url`); assert.strictEqual( currentRouteName(), @@ -304,8 +305,11 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { `delete sys/mounts/${v1}`, ]); await mountSecrets.visit(); - await mountSecrets.selectType('kv'); - await mountSecrets.path(v1).toggleOptions().version(1).submit(); + await click(MOUNT_BACKEND_FORM.mountType('kv')); + await fillIn(GENERAL.inputByAttr('path'), v1); + await click(GENERAL.toggleGroup('Method Options')); + await mountSecrets.version(1); + await click(GENERAL.saveButton); assert.strictEqual(currentURL(), `/vault/secrets/${v1}/list`, `${v1} navigates to list url`); assert.strictEqual( @@ -322,7 +326,7 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { for (const engine of WIF_ENGINES) { await page.visit(); - await page.selectType(engine); + await click(MOUNT_BACKEND_FORM.mountType(engine)); await click(GENERAL.toggleGroup('Method Options')); assert .dom('[data-test-search-select-with-modal]') @@ -336,8 +340,8 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { .hasText('some-key', 'some-key was selected and displays in the search select'); } // Go back and choose a non-wif engine type - await page.back(); - await page.selectType('ssh'); + await click(GENERAL.backButton); + await click(MOUNT_BACKEND_FORM.mountType('ssh')); assert .dom('[data-test-search-select-with-modal]') .doesNotExist('for type ssh, the modal field does not render.'); @@ -357,8 +361,8 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { await logout.visit(); await authPage.login(secretsAdminToken); await page.visit(); - await page.selectType(engine); - await page.path(path); + await click(MOUNT_BACKEND_FORM.mountType(engine)); + await fillIn(GENERAL.inputByAttr('path'), path); await click(GENERAL.toggleGroup('Method Options')); await clickTrigger('#key'); // create new key @@ -371,7 +375,7 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { assert.dom('#search-select-modal').doesNotExist('modal disappears onSave'); assert.dom(GENERAL.searchSelect.selectedOption()).hasText(newKey, `${newKey} is now selected`); - await page.submit(); + await click(GENERAL.saveButton); await visit(`/vault/secrets/${path}/configuration`); await click(SES.configurationToggle); assert @@ -397,12 +401,12 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { await logout.visit(); await authPage.login(secretsNoOidcAdminToken); await page.visit(); - await page.selectType(engine); - await page.path(path); + await click(MOUNT_BACKEND_FORM.mountType(engine)); + await fillIn(GENERAL.inputByAttr('path'), path); await click(GENERAL.toggleGroup('Method Options')); // type-in fallback component to create new key await typeIn(GENERAL.inputSearch('key'), 'general-key'); - await page.submit(); + await click(GENERAL.saveButton); assert .dom(GENERAL.latestFlashContent) .hasText(`Successfully mounted the aws secrets engine at ${path}.`); diff --git a/ui/tests/helpers/components/mount-backend-form-helpers.js b/ui/tests/helpers/components/mount-backend-form-helpers.js new file mode 100644 index 0000000000..8928009a4c --- /dev/null +++ b/ui/tests/helpers/components/mount-backend-form-helpers.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import { fillIn, click } from '@ember/test-helpers'; +import { MOUNT_BACKEND_FORM } from 'vault/tests/helpers/components/mount-backend-form-selectors'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; + +export const mountBackend = async (type, path) => { + await click(MOUNT_BACKEND_FORM.mountType(type)); + if (path) { + await fillIn(GENERAL.inputByAttr('path'), path); + await click(GENERAL.saveButton); + } else { + // save with default path + await click(GENERAL.saveButton); + } +}; diff --git a/ui/tests/helpers/components/mount-backend-form-selectors.ts b/ui/tests/helpers/components/mount-backend-form-selectors.ts new file mode 100644 index 0000000000..2000201d44 --- /dev/null +++ b/ui/tests/helpers/components/mount-backend-form-selectors.ts @@ -0,0 +1,10 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +/** Ideally we wouldn't have one selector for one file. + However, given the coupled nature of mounting both secret engines and auth methods in one form, and the organization of our helpers, I've opted to keep this as is. This selector spans multiple test, is component scoped and it's used by both secret engines and auth methods. */ +export const MOUNT_BACKEND_FORM = { + mountType: (name: string) => `[data-test-mount-type="${name}"]`, +}; diff --git a/ui/tests/helpers/general-selectors.ts b/ui/tests/helpers/general-selectors.ts index deff4ef53f..5eed1980e6 100644 --- a/ui/tests/helpers/general-selectors.ts +++ b/ui/tests/helpers/general-selectors.ts @@ -94,6 +94,7 @@ export const GENERAL = { navLink: (label: string) => `[data-test-sidebar-nav-link="${label}"]`, cancelButton: '[data-test-cancel]', saveButton: '[data-test-save]', + backButton: '[data-test-back-button]', codemirror: `[data-test-component="code-mirror-modifier"]`, codemirrorTextarea: `[data-test-component="code-mirror-modifier"] textarea`, }; diff --git a/ui/tests/helpers/secret-engine/secret-engine-selectors.ts b/ui/tests/helpers/secret-engine/secret-engine-selectors.ts index af2f7e40cd..4349d5ca9e 100644 --- a/ui/tests/helpers/secret-engine/secret-engine-selectors.ts +++ b/ui/tests/helpers/secret-engine/secret-engine-selectors.ts @@ -4,7 +4,6 @@ */ export const SECRET_ENGINE_SELECTORS = { - backButton: '[data-test-back-button]', configTab: '[data-test-configuration-tab]', configure: '[data-test-secret-backend-configure]', configureTitle: (type: string) => `[data-test-backend-configure-title="${type}"]`, @@ -15,8 +14,6 @@ export const SECRET_ENGINE_SELECTORS = { title: '[data-test-backend-error-title]', }, generateLink: '[data-test-backend-credentials]', - mountType: (name: string) => `[data-test-mount-type="${name}"]`, - mountSubmit: '[data-test-mount-submit]', secretHeader: '[data-test-secret-header]', secretLink: (name: string) => (name ? `[data-test-secret-link="${name}"]` : '[data-test-secret-link]'), secretLinkMenu: (name: string) => `[data-test-secret-link="${name}"] [data-test-popup-menu-trigger]`, diff --git a/ui/tests/integration/components/auth/page-test.js b/ui/tests/integration/components/auth/page-test.js index 45628cd391..d6d88e8a5a 100644 --- a/ui/tests/integration/components/auth/page-test.js +++ b/ui/tests/integration/components/auth/page-test.js @@ -198,7 +198,7 @@ module('Integration | Component | auth | page ', function (hooks) { 'To finish signing in, you will need to complete an additional MFA step. Please wait... Back to login', 'renders okta number challenge on submit' ); - await click('[data-test-back-button]'); + await click(GENERAL.backButton); assert.dom(AUTH_FORM.form).exists('renders auth form on return to login'); assert.dom(GENERAL.selectByAttr('auth-method')).hasValue('okta', 'preserves method type on back'); }); diff --git a/ui/tests/integration/components/mount-backend-form-test.js b/ui/tests/integration/components/mount-backend-form-test.js index 2f4dff2df3..adcc1079f4 100644 --- a/ui/tests/integration/components/mount-backend-form-test.js +++ b/ui/tests/integration/components/mount-backend-form-test.js @@ -6,19 +6,18 @@ import { later, _cancelTimers as cancelTimers } from '@ember/runloop'; import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; -import { render, settled, click, typeIn } from '@ember/test-helpers'; +import { render, settled, click, typeIn, fillIn } from '@ember/test-helpers'; import { setupMirage } from 'ember-cli-mirage/test-support'; import { allowAllCapabilitiesStub, noopStub } from 'vault/tests/helpers/stubs'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; +import { MOUNT_BACKEND_FORM } from 'vault/tests/helpers/components/mount-backend-form-selectors'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; +import { methods } from 'vault/helpers/mountable-auth-methods'; +import { mountableEngines } from 'vault/helpers/mountable-secret-engines'; import hbs from 'htmlbars-inline-precompile'; -import { create } from 'ember-cli-page-object'; -import mountBackendForm from '../../pages/components/mount-backend-form'; - import sinon from 'sinon'; -const component = create(mountBackendForm); - module('Integration | Component | mount backend form', function (hooks) { setupRenderingTest(hooks); setupMirage(hooks); @@ -45,51 +44,56 @@ module('Integration | Component | mount backend form', function (hooks) { }); test('it renders default state', async function (assert) { + assert.expect(15); await render( hbs`` ); - assert.strictEqual( - component.header, - 'Enable an Authentication Method', - 'renders auth header in default state' - ); - assert.ok(component.types.length > 0, 'renders type picker'); + assert + .dom(GENERAL.title) + .hasText('Enable an Authentication Method', 'renders auth header in default state'); + + for (const method of methods()) { + assert + .dom(MOUNT_BACKEND_FORM.mountType(method.type)) + .hasText(method.displayName, `renders type:${method.displayName} picker`); + } }); test('it changes path when type is changed', async function (assert) { await render( hbs`` ); - await component.selectType('aws'); - assert.strictEqual(component.pathValue, 'aws', 'sets the value of the type'); - await component.back(); - await component.selectType('approle'); - assert.strictEqual(component.pathValue, 'approle', 'updates the value of the type'); + + await click(MOUNT_BACKEND_FORM.mountType('aws')); + assert.dom(GENERAL.inputByAttr('path')).hasValue('aws', 'sets the value of the type'); + await click(GENERAL.backButton); + await click(MOUNT_BACKEND_FORM.mountType('approle')); + assert.dom(GENERAL.inputByAttr('path')).hasValue('approle', 'updates the value of the type'); }); test('it keeps path value if the user has changed it', async function (assert) { await render( hbs`` ); - await component.selectType('approle'); + await click(MOUNT_BACKEND_FORM.mountType('approle')); assert.strictEqual(this.model.type, 'approle', 'Updates type on model'); - assert.strictEqual(component.pathValue, 'approle', 'defaults to approle (first in the list)'); - await component.path('newpath'); + assert.dom(GENERAL.inputByAttr('path')).hasValue('approle', 'defaults to approle (first in the list)'); + await fillIn(GENERAL.inputByAttr('path'), 'newpath'); assert.strictEqual(this.model.path, 'newpath', 'Updates path on model'); - await component.back(); + await click(GENERAL.backButton); assert.strictEqual(this.model.type, '', 'Clears type on back'); assert.strictEqual(this.model.path, 'newpath', 'Path is still newPath'); - await component.selectType('aws'); + await click(MOUNT_BACKEND_FORM.mountType('aws')); assert.strictEqual(this.model.type, 'aws', 'Updates type on model'); - assert.strictEqual(component.pathValue, 'newpath', 'keeps custom path value'); + assert.dom(GENERAL.inputByAttr('path')).hasValue('newpath', 'keeps custom path value'); }); test('it does not show a selected token type when first mounting an auth method', async function (assert) { await render( hbs`` ); - await component.selectType('github'); - await component.toggleOptions(); + await click(MOUNT_BACKEND_FORM.mountType('github')); + await click(GENERAL.toggleGroup('Method Options')); assert .dom('[data-test-input="config.tokenType"]') .hasValue('', 'token type does not have a default value.'); @@ -113,7 +117,7 @@ module('Integration | Component | mount backend form', function (hooks) { await render( hbs`` ); - await component.mount('approle', 'foo'); + await mountBackend('approle', 'foo'); later(() => cancelTimers(), 50); await settled(); @@ -131,40 +135,45 @@ module('Integration | Component | mount backend form', function (hooks) { this.model.set('config', this.store.createRecord('mount-config')); }); - test('it renders secret specific headers', async function (assert) { + test('it renders secret engine specific headers', async function (assert) { + assert.expect(17); await render( hbs`` ); - assert.strictEqual(component.header, 'Enable a Secrets Engine', 'renders secrets header'); - assert.ok(component.types.length > 0, 'renders type picker'); + assert.dom(GENERAL.title).hasText('Enable a Secrets Engine', 'renders secrets header'); + for (const method of mountableEngines()) { + assert + .dom(MOUNT_BACKEND_FORM.mountType(method.type)) + .hasText(method.displayName, `renders type:${method.displayName} picker`); + } }); test('it changes path when type is changed', async function (assert) { await render( hbs`` ); - await component.selectType('azure'); - assert.strictEqual(component.pathValue, 'azure', 'sets the value of the type'); - await component.back(); - await component.selectType('nomad'); - assert.strictEqual(component.pathValue, 'nomad', 'updates the value of the type'); + await click(MOUNT_BACKEND_FORM.mountType('azure')); + assert.dom(GENERAL.inputByAttr('path')).hasValue('azure', 'sets the value of the type'); + await click(GENERAL.backButton); + await click(MOUNT_BACKEND_FORM.mountType('nomad')); + assert.dom(GENERAL.inputByAttr('path')).hasValue('nomad', 'updates the value of the type'); }); test('it keeps path value if the user has changed it', async function (assert) { await render( hbs`` ); - await component.selectType('kv'); + await click(MOUNT_BACKEND_FORM.mountType('kv')); assert.strictEqual(this.model.type, 'kv', 'Updates type on model'); - assert.strictEqual(component.pathValue, 'kv', 'path matches mount type'); - await component.path('newpath'); + assert.dom(GENERAL.inputByAttr('path')).hasValue('kv', 'path matches mount type'); + await fillIn(GENERAL.inputByAttr('path'), 'newpath'); assert.strictEqual(this.model.path, 'newpath', 'Updates path on model'); - await component.back(); + await click(GENERAL.backButton); assert.strictEqual(this.model.type, '', 'Clears type on back'); assert.strictEqual(this.model.path, 'newpath', 'path is still newpath'); - await component.selectType('ssh'); + await click(MOUNT_BACKEND_FORM.mountType('ssh')); assert.strictEqual(this.model.type, 'ssh', 'Updates type on model'); - assert.strictEqual(component.pathValue, 'newpath', 'path stays the same'); + assert.dom(GENERAL.inputByAttr('path')).hasValue('newpath', 'path stays the same'); }); test('it calls mount success', async function (assert) { @@ -181,7 +190,7 @@ module('Integration | Component | mount backend form', function (hooks) { hbs`` ); - await component.mount('ssh', 'foo'); + await mountBackend('ssh', 'foo'); later(() => cancelTimers(), 50); await settled(); @@ -197,15 +206,15 @@ module('Integration | Component | mount backend form', function (hooks) { await render( hbs`` ); - await component.selectType('ldap'); + await click(MOUNT_BACKEND_FORM.mountType('ldap')); await click(GENERAL.toggleGroup('Method Options')); assert .dom(GENERAL.fieldByAttr('identityTokenKey')) .doesNotExist(`Identity token key field hidden when type=${this.model.type}`); - await component.back(); - await component.selectType('aws'); + await click(GENERAL.backButton); + await click(MOUNT_BACKEND_FORM.mountType('aws')); await click(GENERAL.toggleGroup('Method Options')); assert .dom(GENERAL.fieldByAttr('identityTokenKey')) @@ -216,7 +225,7 @@ module('Integration | Component | mount backend form', function (hooks) { await render( hbs`` ); - await component.selectType('aws'); + await click(MOUNT_BACKEND_FORM.mountType('aws')); assert.strictEqual( this.model.config.identityTokenKey, undefined, diff --git a/ui/tests/integration/components/mount-backend/type-form-test.js b/ui/tests/integration/components/mount-backend/type-form-test.js index 2c988fb1f1..e66c6304a2 100644 --- a/ui/tests/integration/components/mount-backend/type-form-test.js +++ b/ui/tests/integration/components/mount-backend/type-form-test.js @@ -11,6 +11,7 @@ import sinon from 'sinon'; import { allEngines, mountableEngines } from 'vault/helpers/mountable-secret-engines'; import { allMethods, methods } from 'vault/helpers/mountable-auth-methods'; import { setRunOptions } from 'ember-a11y-testing/test-support'; +import { MOUNT_BACKEND_FORM } from 'vault/tests/helpers/components/mount-backend-form-selectors'; const secretTypes = mountableEngines().map((engine) => engine.type); const allSecretTypes = allEngines().map((engine) => engine.type); @@ -25,26 +26,28 @@ module('Integration | Component | mount-backend/type-form', function (hooks) { }); test('it calls secrets setMountType when type is selected', async function (assert) { + assert.expect(secretTypes.length + 1, 'renders all mountable engines plus calls a spy'); const spy = sinon.spy(); this.set('setType', spy); await render(hbs``); - assert - .dom('[data-test-mount-type]') - .exists({ count: secretTypes.length }, 'Renders all mountable engines'); - await click(`[data-test-mount-type="ssh"]`); + for (const type of secretTypes) { + assert.dom(MOUNT_BACKEND_FORM.mountType(type)).exists(`Renders ${type} mountable secret engine`); + } + await click(MOUNT_BACKEND_FORM.mountType('ssh')); assert.ok(spy.calledOnceWith('ssh')); }); test('it calls auth setMountType when type is selected', async function (assert) { + assert.expect(authTypes.length + 1, 'renders all mountable auth methods plus calls a spy'); const spy = sinon.spy(); this.set('setType', spy); await render(hbs``); - assert - .dom('[data-test-mount-type]') - .exists({ count: authTypes.length }, 'Renders all mountable auth methods'); - await click(`[data-test-mount-type="okta"]`); + for (const type of authTypes) { + assert.dom(MOUNT_BACKEND_FORM.mountType(type)).exists(`Renders ${type} mountable auth engine`); + } + await click(MOUNT_BACKEND_FORM.mountType('okta')); assert.ok(spy.calledOnceWith('okta')); }); @@ -55,6 +58,7 @@ module('Integration | Component | mount-backend/type-form', function (hooks) { }); test('it renders correct items for enterprise secrets', async function (assert) { + assert.expect(allSecretTypes.length, 'renders all enterprise secret engines'); setRunOptions({ rules: { // TODO: Fix disabled enterprise options with enterprise badge @@ -62,14 +66,17 @@ module('Integration | Component | mount-backend/type-form', function (hooks) { }, }); await render(hbs``); - assert - .dom('[data-test-mount-type]') - .exists({ count: allSecretTypes.length }, 'Renders all secret engines'); + for (const type of allSecretTypes) { + assert.dom(MOUNT_BACKEND_FORM.mountType(type)).exists(`Renders ${type} secret engine`); + } }); test('it renders correct items for enterprise auth methods', async function (assert) { + assert.expect(allAuthTypes.length, 'renders all enterprise auth engines'); await render(hbs``); - assert.dom('[data-test-mount-type]').exists({ count: allAuthTypes.length }, 'Renders all auth methods'); + for (const type of allAuthTypes) { + assert.dom(MOUNT_BACKEND_FORM.mountType(type)).exists(`Renders ${type} auth engine`); + } }); }); }); diff --git a/ui/tests/integration/components/okta-number-challenge-test.js b/ui/tests/integration/components/okta-number-challenge-test.js index 2c57009258..a117a9dd13 100644 --- a/ui/tests/integration/components/okta-number-challenge-test.js +++ b/ui/tests/integration/components/okta-number-challenge-test.js @@ -8,6 +8,7 @@ import { setupRenderingTest } from 'ember-qunit'; import { render, click } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; import sinon from 'sinon'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Integration | Component | auth | okta-number-challenge', function (hooks) { setupRenderingTest(hooks); @@ -71,7 +72,7 @@ module('Integration | Component | auth | okta-number-challenge', function (hooks 'Correct description renders' ); assert.dom('[data-test-message-error]').hasText(`Error ${this.hasError}`); - await click('[data-test-back-button]'); + await click(GENERAL.backButton); assert.true(this.onCancel.calledOnce, 'onCancel is called'); }); }); diff --git a/ui/tests/pages/components/mount-backend-form.js b/ui/tests/pages/components/mount-backend-form.js deleted file mode 100644 index 543a4b611b..0000000000 --- a/ui/tests/pages/components/mount-backend-form.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) HashiCorp, Inc. - * SPDX-License-Identifier: BUSL-1.1 - */ - -import { clickable, collection, fillable, text, value, attribute } from 'ember-cli-page-object'; -import fields from './form-field'; - -export default { - ...fields, - header: text('[data-test-mount-form-header]'), - submit: clickable('[data-test-mount-submit]'), - back: clickable('[data-test-mount-back]'), - path: fillable('[data-test-input="path"]'), - toggleOptions: clickable('[data-test-toggle-group="Method Options"]'), - pathValue: value('[data-test-input="path"]'), - types: collection('[data-test-mount-type]', { - select: clickable(), - id: attribute('id'), - }), - type: fillable('[name="mount-type"]'), - async selectType(type) { - return this.types.filterBy('id', type)[0].select(); - }, - async mount(type, path) { - await this.selectType(type); - if (path) { - await this.path(path).submit(); - } else { - await this.submit(); - } - }, -}; diff --git a/ui/tests/pages/secrets/backend/ssh/edit-role.js b/ui/tests/pages/secrets/backend/ssh/edit-role.js index 3c7df37555..a5a58f205b 100644 --- a/ui/tests/pages/secrets/backend/ssh/edit-role.js +++ b/ui/tests/pages/secrets/backend/ssh/edit-role.js @@ -10,15 +10,6 @@ export default create({ ...Base, visitEdit: visitable('/vault/secrets/:backend/edit/:id'), visitEditRoot: visitable('/vault/secrets/:backend/edit'), - keyType: fillable('[data-test-input="keyType"]'), - defaultUser: fillable('[data-test-input="defaultUser"]'), - toggleMore: clickable('[data-test-toggle-group="Options"]'), name: fillable('[data-test-input="name"]'), - CIDR: fillable('[data-test-input="cidrList"]'), save: clickable('[data-test-role-ssh-create]'), - - async createOTPRole(name) { - await this.name(name); - await this.toggleMore().keyType('otp').defaultUser('admin').CIDR('0.0.0.0/0').save(); - }, }); diff --git a/ui/tests/pages/secrets/backend/ssh/generate-otp.js b/ui/tests/pages/secrets/backend/ssh/generate-otp.js index 2e67e466e2..f49afde06f 100644 --- a/ui/tests/pages/secrets/backend/ssh/generate-otp.js +++ b/ui/tests/pages/secrets/backend/ssh/generate-otp.js @@ -4,7 +4,7 @@ */ import { Base } from '../credentials'; -import { clickable, value, create, fillable, isPresent } from 'ember-cli-page-object'; +import { value, create, fillable, isPresent } from 'ember-cli-page-object'; export default create({ ...Base, @@ -14,9 +14,5 @@ export default create({ ip: fillable('[data-test-input="ip"]'), warningIsPresent: isPresent('[data-test-warning]'), commonNameValue: value('[data-test-input="commonName"]'), - submit: clickable('[data-test-save]'), - back: clickable('[data-test-back-button]'), - generateOTP: async function () { - await this.user('admin').ip('192.168.1.1').submit(); - }, + generateOTP: async function () {}, }); diff --git a/ui/tests/pages/settings/auth/enable.js b/ui/tests/pages/settings/auth/enable.js index 34893885a3..13c309c137 100644 --- a/ui/tests/pages/settings/auth/enable.js +++ b/ui/tests/pages/settings/auth/enable.js @@ -4,15 +4,14 @@ */ import { create, visitable } from 'ember-cli-page-object'; -import backendForm from '../../components/mount-backend-form'; import flashMessages from '../../components/flash-message'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; export default create({ visit: visitable('/vault/settings/auth/enable'), - ...backendForm, flash: flashMessages, enable: async function (type, path) { await this.visit(); - await this.mount(type, path); + await mountBackend(type, path); }, }); diff --git a/ui/tests/pages/settings/mount-secret-backend.js b/ui/tests/pages/settings/mount-secret-backend.js index 6a4e58661c..ef7da0be9e 100644 --- a/ui/tests/pages/settings/mount-secret-backend.js +++ b/ui/tests/pages/settings/mount-secret-backend.js @@ -5,11 +5,10 @@ import { create, visitable, fillable, clickable } from 'ember-cli-page-object'; import { settled } from '@ember/test-helpers'; -import mountForm from 'vault/tests/pages/components/mount-backend-form'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; export default create({ visit: visitable('/vault/settings/mount-secret-backend'), - ...mountForm, version: fillable('[data-test-input="version"]'), setMaxVersion: fillable('[data-test-input="maxVersions"]'), enableMaxTtl: clickable('[data-test-toggle-input="Max Lease TTL"]'), @@ -23,7 +22,7 @@ export default create({ enable: async function (type, path) { await this.visit(); await settled(); - await this.mount(type, path); + await mountBackend(type, path); await settled(); }, });