diff --git a/changelog/28539.txt b/changelog/28539.txt new file mode 100644 index 000000000000..ebbc5476135b --- /dev/null +++ b/changelog/28539.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: fix `default_role` input missing from oidc auth method configuration form +``` diff --git a/ui/app/utils/openapi-helpers.ts b/ui/app/utils/openapi-helpers.ts index 20844fa4bd77..91675bf580da 100644 --- a/ui/app/utils/openapi-helpers.ts +++ b/ui/app/utils/openapi-helpers.ts @@ -136,7 +136,6 @@ export function filterPathsByItemType(pathInfo: PathsInfo, itemType: string): Pa * This object maps model names to the openAPI path that hydrates the model, given the backend path. */ const OPENAPI_POWERED_MODELS = { - 'role-ssh': (backend: string) => `/v1/${backend}/roles/example?help=1`, 'auth-config/azure': (backend: string) => `/v1/auth/${backend}/config?help=1`, 'auth-config/cert': (backend: string) => `/v1/auth/${backend}/config?help=1`, 'auth-config/gcp': (backend: string) => `/v1/auth/${backend}/config?help=1`, @@ -144,18 +143,20 @@ const OPENAPI_POWERED_MODELS = { 'auth-config/jwt': (backend: string) => `/v1/auth/${backend}/config?help=1`, 'auth-config/kubernetes': (backend: string) => `/v1/auth/${backend}/config?help=1`, 'auth-config/ldap': (backend: string) => `/v1/auth/${backend}/config?help=1`, + 'auth-config/oidc': (backend: string) => `/v1/auth/${backend}/config?help=1`, 'auth-config/okta': (backend: string) => `/v1/auth/${backend}/config?help=1`, 'auth-config/radius': (backend: string) => `/v1/auth/${backend}/config?help=1`, 'kmip/config': (backend: string) => `/v1/${backend}/config?help=1`, 'kmip/role': (backend: string) => `/v1/${backend}/scope/example/role/example?help=1`, - 'pki/role': (backend: string) => `/v1/${backend}/roles/example?help=1`, - 'pki/tidy': (backend: string) => `/v1/${backend}/config/auto-tidy?help=1`, - 'pki/sign-intermediate': (backend: string) => `/v1/${backend}/issuer/example/sign-intermediate?help=1`, 'pki/certificate/generate': (backend: string) => `/v1/${backend}/issue/example?help=1`, 'pki/certificate/sign': (backend: string) => `/v1/${backend}/sign/example?help=1`, 'pki/config/acme': (backend: string) => `/v1/${backend}/config/acme?help=1`, 'pki/config/cluster': (backend: string) => `/v1/${backend}/config/cluster?help=1`, 'pki/config/urls': (backend: string) => `/v1/${backend}/config/urls?help=1`, + 'pki/role': (backend: string) => `/v1/${backend}/roles/example?help=1`, + 'pki/sign-intermediate': (backend: string) => `/v1/${backend}/issuer/example/sign-intermediate?help=1`, + 'pki/tidy': (backend: string) => `/v1/${backend}/config/auto-tidy?help=1`, + 'role-ssh': (backend: string) => `/v1/${backend}/roles/example?help=1`, }; export function getHelpUrlForModel(modelType: string, backend: string) { diff --git a/ui/lib/core/addon/components/masked-input.hbs b/ui/lib/core/addon/components/masked-input.hbs index 833b940a259d..5cb75aa2da2b 100644 --- a/ui/lib/core/addon/components/masked-input.hbs +++ b/ui/lib/core/addon/components/masked-input.hbs @@ -32,7 +32,7 @@ aria-label={{or @name "masked input"}} {{on "change" this.onChange}} {{on "keyup" (fn this.handleKeyUp @name)}} - data-test-textarea={{or @name ""}} + data-test-input={{or @name ""}} /> {{/if}} {{#if @allowCopy}} diff --git a/ui/tests/acceptance/auth-list-test.js b/ui/tests/acceptance/auth-list-test.js index 2d8caf76f7b7..38584f6b063e 100644 --- a/ui/tests/acceptance/auth-list-test.js +++ b/ui/tests/acceptance/auth-list-test.js @@ -18,8 +18,6 @@ import { GENERAL } from 'vault/tests/helpers/general-selectors'; const SELECTORS = { backendLink: (path) => `[data-test-auth-backend-link="${path}"]`, createUser: '[data-test-entity-create-link="user"]', - input: (attr) => `[data-test-input="${attr}"]`, - password: '[data-test-textarea]', saveBtn: '[data-test-save-config]', methods: '[data-test-access-methods] a', listItem: '[data-test-list-item-content]', @@ -49,8 +47,8 @@ module('Acceptance | auth backend list', function (hooks) { await click(SELECTORS.backendLink(this.path1)); assert.dom(GENERAL.emptyStateTitle).exists('shows empty state'); await click(SELECTORS.createUser); - await fillIn(SELECTORS.input('username'), this.user1); - await fillIn(SELECTORS.password, this.user1); + await fillIn(GENERAL.inputByAttr('username'), this.user1); + await fillIn(GENERAL.inputByAttr('password'), this.user1); await click(SELECTORS.saveBtn); assert.strictEqual(currentURL(), `/vault/access/${this.path1}/item/user`); @@ -61,8 +59,8 @@ module('Acceptance | auth backend list', function (hooks) { await click(SELECTORS.backendLink(this.path2)); assert.dom(GENERAL.emptyStateTitle).exists('shows empty state'); await click(SELECTORS.createUser); - await fillIn(SELECTORS.input('username'), this.user2); - await fillIn(SELECTORS.password, this.user2); + await fillIn(GENERAL.inputByAttr('username'), this.user2); + await fillIn(GENERAL.inputByAttr('password'), this.user2); await click(SELECTORS.saveBtn); assert.strictEqual(currentURL(), `/vault/access/${this.path2}/item/user`); // Confirm that the user was created. There was a bug where the apiPath was not being updated when toggling between auth routes. diff --git a/ui/tests/acceptance/auth/enable-tune-form-test.js b/ui/tests/acceptance/auth/enable-tune-form-test.js new file mode 100644 index 000000000000..07d192fbe8e8 --- /dev/null +++ b/ui/tests/acceptance/auth/enable-tune-form-test.js @@ -0,0 +1,216 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import { module, test } from 'qunit'; +import { setupApplicationTest } from 'ember-qunit'; +import { v4 as uuidv4 } from 'uuid'; + +import { login } from 'vault/tests/helpers/auth/auth-helpers'; +import { visit } from '@ember/test-helpers'; +import { deleteAuthCmd, runCmd } from 'vault/tests/helpers/commands'; +import testHelper from './test-helper'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; + +// These models use openAPI so we assert the form inputs using an acceptance test +// The default selector is to use GENERAL.inputByAttr() +// custom fields should be added to the this.customSelectorss object +module('Acceptance | auth enable tune form test', function (hooks) { + setupApplicationTest(hooks); + hooks.beforeEach(async function () { + // these tend to be the same across models because they share the same mount-config model + // if necessary, they can be overridden in the individual module + this.mountFields = [ + 'path', + 'description', + 'local', + 'sealWrap', + 'config.listingVisibility', + 'config.defaultLeaseTtl', + 'config.maxLeaseTtl', + 'config.tokenType', + 'config.auditNonHmacRequestKeys', + 'config.auditNonHmacResponseKeys', + 'config.passthroughRequestHeaders', + 'config.allowedResponseHeaders', + 'config.pluginVersion', + ]; + }); + + module('azure', function (hooks) { + hooks.beforeEach(async function () { + this.type = 'azure'; + this.path = `${this.type}-${uuidv4()}`; + this.tuneFields = [ + 'environment', + 'identityTokenAudience', + 'identityTokenTtl', + 'maxRetries', + 'maxRetryDelay', + 'resource', + 'retryDelay', + 'rootPasswordTtl', + 'tenantId', + ]; + this.tuneToggles = { 'Azure Options': ['clientId', 'clientSecret'] }; + await login(); + return visit('/vault/settings/auth/enable'); + }); + hooks.afterEach(async function () { + await runCmd(deleteAuthCmd(this.path), false); + }); + testHelper(test); + }); + + module('jwt', function (hooks) { + hooks.beforeEach(async function () { + this.type = 'jwt'; + this.path = `${this.type}-${uuidv4()}`; + this.customSelectors = { + providerConfig: `${GENERAL.fieldByAttr('providerConfig')} textarea`, + }; + this.tuneFields = [ + 'defaultRole', + 'jwksCaPem', + 'jwksUrl', + 'namespaceInState', + 'oidcDiscoveryUrl', + 'oidcResponseMode', + 'oidcResponseTypes', + 'providerConfig', + 'unsupportedCriticalCertExtensions', + ]; + this.tuneToggles = { + 'JWT Options': [ + 'oidcClientId', + 'oidcClientSecret', + 'oidcDiscoveryCaPem', + 'jwtValidationPubkeys', + 'jwtSupportedAlgs', + 'boundIssuer', + ], + }; + await login(); + return visit('/vault/settings/auth/enable'); + }); + hooks.afterEach(async function () { + await runCmd(deleteAuthCmd(this.path), false); + }); + testHelper(test); + }); + + module('ldap', function (hooks) { + hooks.beforeEach(async function () { + this.type = 'ldap'; + this.path = `${this.type}-${uuidv4()}`; + this.tuneFields = [ + 'url', + 'caseSensitiveNames', + 'connectionTimeout', + 'dereferenceAliases', + 'maxPageSize', + 'passwordPolicy', + 'requestTimeout', + 'tokenBoundCidrs', + 'tokenExplicitMaxTtl', + 'tokenMaxTtl', + 'tokenNoDefaultPolicy', + 'tokenNumUses', + 'tokenPeriod', + 'tokenPolicies', + 'tokenTtl', + 'tokenType', + 'usePre111GroupCnBehavior', + 'usernameAsAlias', + ]; + this.tuneToggles = { + 'LDAP Options': [ + 'starttls', + 'insecureTls', + 'discoverdn', + 'denyNullBind', + 'tlsMinVersion', + 'tlsMaxVersion', + 'certificate', + 'clientTlsCert', + 'clientTlsKey', + 'userattr', + 'upndomain', + 'anonymousGroupSearch', + ], + 'Customize User Search': ['binddn', 'userdn', 'bindpass', 'userfilter'], + 'Customize Group Membership Search': ['groupfilter', 'groupattr', 'groupdn', 'useTokenGroups'], + }; + await login(); + return visit('/vault/settings/auth/enable'); + }); + hooks.afterEach(async function () { + await runCmd(deleteAuthCmd(this.path), false); + }); + testHelper(test); + }); + + module('oidc', function (hooks) { + hooks.beforeEach(async function () { + this.type = 'oidc'; + this.path = `${this.type}-${uuidv4()}`; + this.customSelectors = { + providerConfig: `${GENERAL.fieldByAttr('providerConfig')} textarea`, + }; + this.tuneFields = [ + 'oidcDiscoveryUrl', + 'defaultRole', + 'jwksCaPem', + 'jwksUrl', + 'oidcResponseMode', + 'oidcResponseTypes', + 'namespaceInState', + 'providerConfig', + 'unsupportedCriticalCertExtensions', + ]; + this.tuneToggles = { + 'OIDC Options': [ + 'oidcClientId', + 'oidcClientSecret', + 'oidcDiscoveryCaPem', + 'jwtValidationPubkeys', + 'jwtSupportedAlgs', + 'boundIssuer', + ], + }; + await login(); + return visit('/vault/settings/auth/enable'); + }); + hooks.afterEach(async function () { + await runCmd(deleteAuthCmd(this.path), false); + }); + testHelper(test); + }); + + module('okta', function (hooks) { + hooks.beforeEach(async function () { + this.type = 'okta'; + this.path = `${this.type}-${uuidv4()}`; + this.tuneFields = [ + 'orgName', + 'tokenBoundCidrs', + 'tokenExplicitMaxTtl', + 'tokenMaxTtl', + 'tokenNoDefaultPolicy', + 'tokenNumUses', + 'tokenPeriod', + 'tokenPolicies', + 'tokenTtl', + 'tokenType', + ]; + this.tuneToggles = { Options: ['apiToken', 'baseUrl', 'bypassOktaMfa'] }; + await login(); + return visit('/vault/settings/auth/enable'); + }); + hooks.afterEach(async function () { + await runCmd(deleteAuthCmd(this.path), false); + }); + testHelper(test); + }); +}); diff --git a/ui/tests/acceptance/auth/test-helper.js b/ui/tests/acceptance/auth/test-helper.js new file mode 100644 index 000000000000..dc0c7b8fff45 --- /dev/null +++ b/ui/tests/acceptance/auth/test-helper.js @@ -0,0 +1,49 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import { click, currentURL, fillIn } 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]', +}; + +const assertFields = (assert, fields, customSelectors = {}) => { + fields.forEach((param) => { + if (Object.keys(customSelectors).includes(param)) { + assert.dom(customSelectors[param]).exists(); + } else { + assert.dom(GENERAL.inputByAttr(param)).exists(); + } + }); +}; +export default (test) => { + test('it renders mount fields', async function (assert) { + await click(SELECTORS.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); + assert.strictEqual( + currentURL(), + `/vault/settings/auth/configure/${this.path}/configuration`, + `${this.type}: it mounts navigates to tune form` + ); + + assertFields(assert, this.tuneFields, this.customSelectors); + + for (const toggle in this.tuneToggles) { + const fields = this.tuneToggles[toggle]; + await click(GENERAL.toggleGroup(toggle)); + assertFields(assert, fields, this.customSelectors); + } + }); +}; diff --git a/ui/tests/acceptance/mfa-method-test.js b/ui/tests/acceptance/mfa-method-test.js index dbe65eb487f5..499b1d028515 100644 --- a/ui/tests/acceptance/mfa-method-test.js +++ b/ui/tests/acceptance/mfa-method-test.js @@ -11,6 +11,7 @@ import { setupMirage } from 'ember-cli-mirage/test-support'; import mfaConfigHandler from 'vault/mirage/handlers/mfa-config'; import { Response } from 'miragejs'; import { underscore } from '@ember/string'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Acceptance | mfa-method', function (hooks) { setupApplicationTest(hooks); @@ -181,17 +182,10 @@ module('Acceptance | mfa-method', function (hooks) { .dom('[data-test-inline-error-message]') .exists({ count: required.length }, `Required field validations display for ${type}`); - for (const [i, field] of required.entries()) { - let inputType = 'input'; - // this is less than ideal but updating the test selectors in masked-input break a bunch of tests - // add value to the masked input text area data-test attributes for selection - if (['secret_key', 'integration_key'].includes(field)) { - inputType = 'textarea'; - const textareas = this.element.querySelectorAll('[data-test-textarea]'); - textareas[i].setAttribute('data-test-textarea', field); - } - await fillIn(`[data-test-${inputType}="${field}"]`, 'foo'); + for (const field of required) { + await fillIn(GENERAL.inputByAttr(field), 'foo'); } + await click('[data-test-mfa-create-save]'); assert.strictEqual( currentRouteName(), diff --git a/ui/tests/acceptance/reset-password-test.js b/ui/tests/acceptance/reset-password-test.js index 51a4a9ce3f36..731284df2dd4 100644 --- a/ui/tests/acceptance/reset-password-test.js +++ b/ui/tests/acceptance/reset-password-test.js @@ -59,11 +59,11 @@ module('Acceptance | reset password', function (hooks) { ); assert.dom('[data-test-title]').hasText('Reset password', 'page title'); - await fillIn('[data-test-textarea]', 'newpassword'); + await fillIn('[data-test-input="reset-password"]', 'newpassword'); await click('[data-test-reset-password-save]'); await waitFor('[data-test-flash-message]'); assert.dom('[data-test-flash-message]').hasText(`Success ${SUCCESS_MESSAGE}`); - assert.dom('[data-test-textarea]').hasValue('', 'Resets input after save'); + assert.dom('[data-test-input="reset-password"]').hasValue('', 'Resets input after save'); }); test('allows password reset for userpass users logged in via tab', async function (assert) { @@ -91,10 +91,10 @@ module('Acceptance | reset password', function (hooks) { ); assert.dom('[data-test-title]').hasText('Reset password', 'page title'); - await fillIn('[data-test-textarea]', 'newpassword'); + await fillIn('[data-test-input="reset-password"]', 'newpassword'); await click('[data-test-reset-password-save]'); await waitFor('[data-test-flash-message]'); assert.dom('[data-test-flash-message]').hasText(`Success ${SUCCESS_MESSAGE}`); - assert.dom('[data-test-textarea]').hasValue('', 'Resets input after save'); + assert.dom('[data-test-input="reset-password"]').hasValue('', 'Resets input after save'); }); }); 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 9430ccac1442..605bd26b3c1c 100644 --- a/ui/tests/acceptance/secrets/backend/aws/aws-configuration-test.js +++ b/ui/tests/acceptance/secrets/backend/aws/aws-configuration-test.js @@ -368,11 +368,7 @@ module('Acceptance | aws | configuration', function (hooks) { // check all the form fields are present await click(GENERAL.toggleGroup('Root config options')); for (const key of expectedConfigKeys('aws-root-create')) { - if (key === 'secretKey') { - assert.dom(GENERAL.maskedInput(key)).exists(`${key} shows for root section.`); - } else { - assert.dom(GENERAL.inputByAttr(key)).exists(`${key} shows for root section.`); - } + assert.dom(GENERAL.inputByAttr(key)).exists(`${key} shows for root section.`); } for (const key of expectedConfigKeys('aws-lease')) { assert.dom(`[data-test-ttl-form-label="${key}"]`).exists(`${key} shows for Lease section.`); diff --git a/ui/tests/acceptance/secrets/backend/ssh/configuration-test.js b/ui/tests/acceptance/secrets/backend/ssh/configuration-test.js index ecb0ce9b3267..27d3c31ffca8 100644 --- a/ui/tests/acceptance/secrets/backend/ssh/configuration-test.js +++ b/ui/tests/acceptance/secrets/backend/ssh/configuration-test.js @@ -86,7 +86,7 @@ module('Acceptance | ssh | configuration', function (hooks) { `/vault/secrets/${sshPath}/configuration/edit`, 'after deleting public key stays on edit page' ); - assert.dom(GENERAL.maskedInput('privateKey')).hasNoText('Private key is empty and reset'); + assert.dom(GENERAL.inputByAttr('privateKey')).hasNoText('Private key is empty and reset'); assert.dom(GENERAL.inputByAttr('publicKey')).hasNoText('Public key is empty and reset'); assert.dom(GENERAL.inputByAttr('generateSigningKey')).isChecked('Generate signing key is checked'); await click(SES.viewBackend); diff --git a/ui/tests/acceptance/sync/secrets/destination-test.js b/ui/tests/acceptance/sync/secrets/destination-test.js index 82d5cd33f84e..385a139a89b2 100644 --- a/ui/tests/acceptance/sync/secrets/destination-test.js +++ b/ui/tests/acceptance/sync/secrets/destination-test.js @@ -87,7 +87,7 @@ module('Acceptance | sync | destination (singular)', function (hooks) { await visit('vault/sync/secrets/destinations/vercel-project/destination-vercel/edit'); await click(ts.enableField('accessToken')); - await fillIn(ts.maskedInput('accessToken'), 'foobar'); + await fillIn(GENERAL.inputByAttr('accessToken'), 'foobar'); await click(ts.saveButton); await click(ts.toolbar('Edit destination')); await click(ts.saveButton); diff --git a/ui/tests/helpers/general-selectors.ts b/ui/tests/helpers/general-selectors.ts index 90f5c35e1c83..deff4ef53fc3 100644 --- a/ui/tests/helpers/general-selectors.ts +++ b/ui/tests/helpers/general-selectors.ts @@ -94,7 +94,6 @@ export const GENERAL = { navLink: (label: string) => `[data-test-sidebar-nav-link="${label}"]`, cancelButton: '[data-test-cancel]', saveButton: '[data-test-save]', - maskedInput: (name: string) => `[data-test-textarea="${name}"]`, codemirror: `[data-test-component="code-mirror-modifier"]`, codemirrorTextarea: `[data-test-component="code-mirror-modifier"] textarea`, }; diff --git a/ui/tests/helpers/kv/kv-selectors.js b/ui/tests/helpers/kv/kv-selectors.js index 718cfcf371b4..77e7b91416d9 100644 --- a/ui/tests/helpers/kv/kv-selectors.js +++ b/ui/tests/helpers/kv/kv-selectors.js @@ -110,7 +110,7 @@ export const FORM = { kvRow: '[data-test-kv-row]', keyInput: (idx = 0) => `[data-test-kv-key="${idx}"]`, valueInput: (idx = 0) => `[data-test-kv-value="${idx}"]`, - maskedValueInput: (idx = 0) => `[data-test-kv-value="${idx}"] [data-test-textarea]`, + maskedValueInput: (idx = 0) => `[data-test-kv-value="${idx}"] [data-test-input]`, addRow: (idx = 0) => `[data-test-kv-add-row="${idx}"]`, deleteRow: (idx = 0) => `[data-test-kv-delete-row="${idx}"]`, // diff --git a/ui/tests/helpers/secret-engine/secret-engine-helpers.js b/ui/tests/helpers/secret-engine/secret-engine-helpers.js index 4c3c3ee115de..2a9c88601c4d 100644 --- a/ui/tests/helpers/secret-engine/secret-engine-helpers.js +++ b/ui/tests/helpers/secret-engine/secret-engine-helpers.js @@ -182,7 +182,7 @@ export const expectedValueOfConfigKeys = (type, string) => { export const fillInAwsConfig = async (situation = 'withAccess') => { if (situation === 'withAccess') { await fillIn(GENERAL.inputByAttr('accessKey'), 'foo'); - await fillIn(GENERAL.maskedInput('secretKey'), 'bar'); + await fillIn(GENERAL.inputByAttr('secretKey'), 'bar'); } if (situation === 'withAccessOptions') { await click(GENERAL.toggleGroup('Root config options')); diff --git a/ui/tests/helpers/sync/sync-selectors.js b/ui/tests/helpers/sync/sync-selectors.js index 1a5758590af3..61f4ee7616cf 100644 --- a/ui/tests/helpers/sync/sync-selectors.js +++ b/ui/tests/helpers/sync/sync-selectors.js @@ -99,11 +99,6 @@ export const PAGE = { case 'customTags': await fillIn('[data-test-kv-key="0"]', 'foo'); return fillIn('[data-test-kv-value="0"]', value); - case 'accessKeyId': - case 'secretAccessKey': - case 'clientSecret': - case 'accessToken': - return fillIn(GENERAL.maskedInput(attr), value); case 'deploymentEnvironments': await click('[data-test-input="deploymentEnvironments"] input#development'); await click('[data-test-input="deploymentEnvironments"] input#preview'); diff --git a/ui/tests/integration/components/masked-input-test.js b/ui/tests/integration/components/masked-input-test.js index ce56f3f6586d..bd511823ac60 100644 --- a/ui/tests/integration/components/masked-input-test.js +++ b/ui/tests/integration/components/masked-input-test.js @@ -6,13 +6,16 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { render, focus, triggerKeyEvent, typeIn, fillIn, click } from '@ember/test-helpers'; -import { create } from 'ember-cli-page-object'; import hbs from 'htmlbars-inline-precompile'; import sinon from 'sinon'; -import maskedInput from 'vault/tests/pages/components/masked-input'; - -const component = create(maskedInput); +const SELECTORS = { + copyBtn: '[data-test-copy-button]', + downloadBtn: '[data-test-download-button]', + toggle: '[data-test-button="toggle-masked"]', + downloadIcon: '[data-test-download-icon]', + stringify: '[data-test-stringify-toggle]', +}; module('Integration | Component | masked input', function (hooks) { setupRenderingTest(hooks); @@ -26,14 +29,14 @@ module('Integration | Component | masked input', function (hooks) { test('it renders', async function (assert) { await render(hbs``); assert.dom('[data-test-masked-input]').exists('shows masked input'); - assert.ok(component.textareaIsPresent); - assert.dom('[data-test-textarea]').hasClass('masked-font', 'it renders an input with obscure font'); - assert.notOk(component.copyButtonIsPresent, 'does not render copy button by default'); - assert.notOk(component.downloadButtonIsPresent, 'does not render download button by default'); + assert.dom('textarea').exists(); + assert.dom('textarea').hasClass('masked-font', 'it renders an input with obscure font'); + assert.dom(SELECTORS.copyBtn).doesNotExist('does not render copy button by default'); + assert.dom('[data-test-download-button]').doesNotExist('does not render download button by default'); - await component.toggleMasked(); + await click(SELECTORS.toggle); assert.dom('.masked-value').doesNotHaveClass('masked-font', 'it unmasks when show button is clicked'); - await component.toggleMasked(); + await click(SELECTORS.toggle); assert.dom('.masked-value').hasClass('masked-font', 'it remasks text when button is clicked'); }); @@ -42,21 +45,21 @@ module('Integration | Component | masked input', function (hooks) { await render(hbs``); assert.dom('.masked-value').hasClass('masked-font', 'value has obscured font'); - assert.notOk(component.textareaIsPresent, 'it does not render a textarea when displayOnly is true'); + assert.dom('textarea').doesNotExist('it does not render a textarea when displayOnly is true'); }); test('it renders a copy button when allowCopy is true', async function (assert) { this.set('value', { some: 'object' }); await render(hbs``); - assert.ok(component.copyButtonIsPresent); + assert.dom(SELECTORS.copyBtn).exists(); }); test('it renders a download button when allowDownload is true', async function (assert) { await render(hbs` `); - assert.ok(component.downloadIconIsPresent); + assert.dom(SELECTORS.downloadIcon).exists(); - await click('[data-test-download-icon]'); - assert.ok(component.downloadButtonIsPresent, 'clicking download icon opens modal with download button'); + await click(SELECTORS.downloadIcon); + assert.dom(SELECTORS.downloadBtn).exists('clicking download icon opens modal with download button'); }); test('it shortens all outputs when displayOnly and masked', async function (assert) { @@ -65,7 +68,7 @@ module('Integration | Component | masked input', function (hooks) { const maskedValue = document.querySelector('.masked-value').innerText; assert.strictEqual(maskedValue.length, 11); - await component.toggleMasked(); + await click(SELECTORS.toggle); const unMaskedValue = document.querySelector('.masked-value').innerText; assert.strictEqual(unMaskedValue.length, this.value.length); }); @@ -83,7 +86,7 @@ module('Integration | Component | masked input', function (hooks) { this.set('value', 'before'); this.set('onChange', changeSpy); await render(hbs``); - await fillIn('[data-test-textarea]', 'after'); + await fillIn('textarea', 'after'); assert.true(changeSpy.calledWith('after')); }); @@ -92,7 +95,7 @@ module('Integration | Component | masked input', function (hooks) { this.set('value', ''); this.set('onKeyUp', keyupSpy); await render(hbs``); - await typeIn('[data-test-textarea]', 'baz'); + await typeIn('textarea', 'baz'); assert.true(keyupSpy.calledThrice, 'calls for each letter of typing'); assert.true(keyupSpy.firstCall.calledWithExactly('foo', 'b')); assert.true(keyupSpy.secondCall.calledWithExactly('foo', 'ba')); @@ -102,8 +105,8 @@ module('Integration | Component | masked input', function (hooks) { test('it does not remove value on tab', async function (assert) { this.set('value', 'hello'); await render(hbs``); - await triggerKeyEvent('[data-test-textarea]', 'keydown', 9); - await component.toggleMasked(); + await triggerKeyEvent('textarea', 'keydown', 9); + await click(SELECTORS.toggle); const unMaskedValue = document.querySelector('.masked-value').value; assert.strictEqual(unMaskedValue, this.value); }); @@ -119,11 +122,11 @@ module('Integration | Component | masked input', function (hooks) { /> `); assert.dom('[data-test-masked-input]').exists('shows masked input'); - assert.ok(component.copyButtonIsPresent); - assert.ok(component.downloadIconIsPresent); - assert.dom('[data-test-button="toggle-masked"]').exists('shows toggle mask button'); + assert.dom(SELECTORS.copyBtn).exists(); + assert.dom(SELECTORS.downloadIcon).exists(); + assert.dom(SELECTORS.toggle).exists('shows toggle mask button'); - await component.toggleMasked(); + await click(SELECTORS.toggle); assert.dom('.masked-value').doesNotHaveClass('masked-font', 'it unmasks when show button is clicked'); assert .dom('[data-test-icon="minus"]') @@ -154,12 +157,12 @@ module('Integration | Component | masked input', function (hooks) { /> `); - await click('[data-test-download-icon]'); - assert.dom('[data-test-stringify-toggle]').isNotChecked('Stringify toggle off as default'); - await click('[data-test-download-button]'); + await click(SELECTORS.downloadIcon); + assert.dom(SELECTORS.stringify).isNotChecked('Stringify toggle off as default'); + await click(SELECTORS.downloadBtn); - await click('[data-test-download-icon]'); - await click('[data-test-stringify-toggle]'); - await click('[data-test-download-button]'); + await click(SELECTORS.downloadIcon); + await click(SELECTORS.stringify); + await click(SELECTORS.downloadBtn); }); }); diff --git a/ui/tests/integration/components/page/userpass-reset-password-test.js b/ui/tests/integration/components/page/userpass-reset-password-test.js index c995e10f7f1d..674a509c26ba 100644 --- a/ui/tests/integration/components/page/userpass-reset-password-test.js +++ b/ui/tests/integration/components/page/userpass-reset-password-test.js @@ -14,7 +14,7 @@ const S = { infoBanner: '[data-test-current-user-banner]', save: '[data-test-reset-password-save]', error: '[data-test-reset-password-error]', - input: '[data-test-textarea]', + input: '[data-test-input="reset-password"]', }; module('Integration | Component | page/userpass-reset-password', function (hooks) { setupRenderingTest(hooks); diff --git a/ui/tests/integration/components/secret-engine/configure-aws-test.js b/ui/tests/integration/components/secret-engine/configure-aws-test.js index deea1694ef1b..7d805d9f4c4b 100644 --- a/ui/tests/integration/components/secret-engine/configure-aws-test.js +++ b/ui/tests/integration/components/secret-engine/configure-aws-test.js @@ -69,11 +69,7 @@ module('Integration | Component | SecretEngine/ConfigureAws', function (hooks) { // check all the form fields are present await click(GENERAL.toggleGroup('Root config options')); for (const key of expectedConfigKeys('aws-root-create')) { - if (key === 'secretKey') { - assert.dom(GENERAL.maskedInput(key)).exists(`${key} shows for root section.`); - } else { - assert.dom(GENERAL.inputByAttr(key)).exists(`${key} shows for root section.`); - } + assert.dom(GENERAL.inputByAttr(key)).exists(`${key} shows for root section.`); } for (const key of expectedConfigKeys('aws-lease')) { assert.dom(`[data-test-ttl-form-label="${key}"]`).exists(`${key} shows for Lease section.`); @@ -94,11 +90,7 @@ module('Integration | Component | SecretEngine/ConfigureAws', function (hooks) { } // check iam fields do not show for (const key of expectedConfigKeys('aws-root-create-iam')) { - if (key === 'secretKey') { - assert.dom(GENERAL.maskedInput(key)).doesNotExist(`${key} does not show when wif is selected.`); - } else { - assert.dom(GENERAL.inputByAttr(key)).doesNotExist(`${key} does not show when wif is selected.`); - } + assert.dom(GENERAL.inputByAttr(key)).doesNotExist(`${key} does not show when wif is selected.`); } }); @@ -113,7 +105,7 @@ module('Integration | Component | SecretEngine/ConfigureAws', function (hooks) { .dom(GENERAL.inputByAttr('accessKey')) .hasValue('', 'accessKey is cleared after toggling accessType'); assert - .dom(GENERAL.maskedInput('secretKey')) + .dom(GENERAL.inputByAttr('secretKey')) .hasValue('', 'secretKey is cleared after toggling accessType'); await click(SES.aws.accessType('wif')); @@ -435,11 +427,7 @@ module('Integration | Component | SecretEngine/ConfigureAws', function (hooks) { // check all the form fields are present await click(GENERAL.toggleGroup('Root config options')); for (const key of expectedConfigKeys('aws-root-create')) { - if (key === 'secretKey') { - assert.dom(GENERAL.maskedInput(key)).exists(`${key} shows for root section.`); - } else { - assert.dom(GENERAL.inputByAttr(key)).exists(`${key} shows for root section.`); - } + assert.dom(GENERAL.inputByAttr(key)).exists(`${key} shows for root section.`); } for (const key of expectedConfigKeys('aws-lease')) { assert.dom(`[data-test-ttl-form-label="${key}"]`).exists(`${key} shows for Lease section.`); @@ -559,7 +547,7 @@ module('Integration | Component | SecretEngine/ConfigureAws', function (hooks) { await click(GENERAL.enableField('secretKey')); await click('[data-test-button="toggle-masked"]'); - await fillIn(GENERAL.maskedInput('secretKey'), 'new-secret'); + await fillIn(GENERAL.inputByAttr('secretKey'), 'new-secret'); await click(GENERAL.saveButton); }); }); diff --git a/ui/tests/integration/components/secret-engine/configure-ssh-test.js b/ui/tests/integration/components/secret-engine/configure-ssh-test.js index feeb579fa6e4..ae771412110a 100644 --- a/ui/tests/integration/components/secret-engine/configure-ssh-test.js +++ b/ui/tests/integration/components/secret-engine/configure-ssh-test.js @@ -33,7 +33,7 @@ module('Integration | Component | SecretEngine/configure-ssh', function (hooks) @id={{this.id}} /> `); - assert.dom(GENERAL.maskedInput('privateKey')).hasNoText('Private key is empty and reset'); + assert.dom(GENERAL.inputByAttr('privateKey')).hasNoText('Private key is empty and reset'); assert.dom(GENERAL.inputByAttr('publicKey')).hasNoText('Public key is empty and reset'); assert .dom(GENERAL.inputByAttr('generateSigningKey')) diff --git a/ui/tests/integration/components/sync/secrets/page/destinations/create-and-edit-test.js b/ui/tests/integration/components/sync/secrets/page/destinations/create-and-edit-test.js index 302e7faaea0c..3f4a32e5e47d 100644 --- a/ui/tests/integration/components/sync/secrets/page/destinations/create-and-edit-test.js +++ b/ui/tests/integration/components/sync/secrets/page/destinations/create-and-edit-test.js @@ -183,9 +183,9 @@ module('Integration | Component | sync | Secrets::Page::Destinations::CreateAndE await this.renderFormComponent(); await click(PAGE.enableField('accessKeyId')); - await click(PAGE.maskedInput('accessKeyId')); // click on input but do not change value + await click(PAGE.inputByAttr('accessKeyId')); // click on input but do not change value await click(PAGE.enableField('secretAccessKey')); - await fillIn(PAGE.maskedInput('secretAccessKey'), 'new-secret'); + await fillIn(PAGE.inputByAttr('secretAccessKey'), 'new-secret'); await click(PAGE.saveButton); }); @@ -277,10 +277,10 @@ module('Integration | Component | sync | Secrets::Page::Destinations::CreateAndE // iterate over the form fields and filter for those that are obfuscated // fill those in and assert that they are masked filteredObfuscatedFields.forEach(async (field) => { - await fillIn(PAGE.maskedInput(field.name), 'blah'); + await fillIn(PAGE.inputByAttr(field.name), 'blah'); assert - .dom(PAGE.maskedInput(field.name)) + .dom(PAGE.inputByAttr(field.name)) .hasClass('masked-font', `it renders ${field.name} for ${destination} with masked font`); assert .dom(PAGE.form.enableInput(field.name)) diff --git a/ui/tests/pages/components/masked-input.js b/ui/tests/pages/components/masked-input.js deleted file mode 100644 index b83d2a6018f2..000000000000 --- a/ui/tests/pages/components/masked-input.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) HashiCorp, Inc. - * SPDX-License-Identifier: BUSL-1.1 - */ - -import { clickable, isPresent } from 'ember-cli-page-object'; - -export default { - textareaIsPresent: isPresent('[data-test-textarea]'), - copyButtonIsPresent: isPresent('[data-test-copy-button]'), - downloadIconIsPresent: isPresent('[data-test-download-icon]'), - downloadButtonIsPresent: isPresent('[data-test-download-button]'), - toggleMasked: clickable('[data-test-button="toggle-masked"]'), - copyValue: clickable('[data-test-copy-button]'), -};