diff --git a/ui/lib/core/addon/components/form-field.hbs b/ui/lib/core/addon/components/form-field.hbs index be08fd2365..2dbc31b997 100644 --- a/ui/lib/core/addon/components/form-field.hbs +++ b/ui/lib/core/addon/components/form-field.hbs @@ -219,6 +219,44 @@ {{this.validationError}} {{/if}} + {{else}} + + {{this.labelString}} + {{#if this.helpTextString}} + {{this.helpTextString}} + {{/if}} + {{#if @attr.options.subText}} + + {{@attr.options.subText}} + {{#if @attr.options.docLink}} + See our documentation + for help. + {{/if}} + + {{/if}} + {{#if @attr.options.characterLimit}} + + {{/if}} + {{#if this.validationError}} + {{this.validationError}} + {{/if}} + {{/if}} {{else if (or (eq @attr.type "boolean") (eq @attr.options.editType "boolean"))}} {{/if}} - {{else}} - {{! Regular Text Input }} - {{/if}} {{else if (eq @attr.type "object")}} diff --git a/ui/lib/core/addon/components/form-field.js b/ui/lib/core/addon/components/form-field.js index 0f10d92d57..9f018298fd 100644 --- a/ui/lib/core/addon/components/form-field.js +++ b/ui/lib/core/addon/components/form-field.js @@ -120,8 +120,10 @@ export default class FormFieldComponent extends Component { } else if (type === 'number' || type === 'string') { if (options?.editType === 'textarea' || options?.editType === 'password') { return true; - } else { + } else if (options?.editType === 'json') { return false; + } else { + return true; } } else if (type === 'boolean' || options?.editType === 'boolean') { return true; diff --git a/ui/tests/acceptance/config-ui/messages/messages-test.js b/ui/tests/acceptance/config-ui/messages/messages-test.js index f2ae4655f7..b7add218c8 100644 --- a/ui/tests/acceptance/config-ui/messages/messages-test.js +++ b/ui/tests/acceptance/config-ui/messages/messages-test.js @@ -245,7 +245,7 @@ module('Acceptance | Enterprise | config-ui/message', function (hooks) { assert .dom(CUSTOM_MESSAGES.modal('preview image')) .doesNotExist('preview image does not show because you have a missing title'); - assert.dom(CUSTOM_MESSAGES.input('title')).hasClass('has-error-border', 'error around title shows'); + assert.dom(GENERAL.validationErrorByAttr('title')).exists(); }); // unauthenticated messages @@ -340,7 +340,7 @@ module('Acceptance | Enterprise | config-ui/message', function (hooks) { await fillIn('[data-test-kv-value="0"]', 'www.learn.com'); await click(GENERAL.button('preview')); assert.dom(CUSTOM_MESSAGES.modal('preview image')).doesNotExist('preview image does not show'); - assert.dom(CUSTOM_MESSAGES.input('title')).hasClass('has-error-border', 'error around title shows'); + assert.dom(GENERAL.validationErrorByAttr('title')).exists(); }); test('cleanup message pollution', async function (assert) { diff --git a/ui/tests/acceptance/mfa-method-test.js b/ui/tests/acceptance/mfa-method-test.js index 1929cb57fc..64ba06cd8a 100644 --- a/ui/tests/acceptance/mfa-method-test.js +++ b/ui/tests/acceptance/mfa-method-test.js @@ -193,7 +193,7 @@ module('Acceptance | mfa-method', function (hooks) { await click('[data-test-mleh-radio="skip"]'); await click('[data-test-mfa-create-save]'); assert - .dom('[data-test-inline-error-message]') + .dom('[data-test-validation-error]') .exists({ count: required.length }, `Required field validations display for ${type}`); for (const field of required) { diff --git a/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-create-test.js b/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-create-test.js index 5f2ff9111f..e6685cd674 100644 --- a/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-create-test.js +++ b/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-create-test.js @@ -84,7 +84,7 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // Create secret form -- validations await click(FORM.saveBtn); assert.dom(FORM.invalidFormAlert).hasText('There is an error with this form.'); - assert.dom(FORM.validation('path')).hasText("Path can't be blank."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't be blank."); await typeIn(FORM.inputByAttr('path'), secretPath); assert .dom(FORM.validationWarning) @@ -167,9 +167,9 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // Create secret await typeIn(FORM.inputByAttr('path'), 'my/'); - assert.dom(FORM.validation('path')).hasText("Path can't end in forward slash '/'."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't end in forward slash '/'."); await typeIn(FORM.inputByAttr('path'), 'secret'); - assert.dom(FORM.validation('path')).doesNotExist('form validation goes away'); + assert.dom(GENERAL.validationErrorByAttr('path')).doesNotExist('form validation goes away'); await fillIn(FORM.keyInput(), 'password'); await fillIn(FORM.maskedValueInput(), 'kittens1234'); @@ -182,10 +182,10 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // MaxVersions validation await fillIn(FORM.inputByAttr('maxVersions'), 'seven'); await click(FORM.saveBtn); - assert.dom(FORM.validation('maxVersions')).hasText('Maximum versions must be a number.'); + assert.dom(GENERAL.validationErrorByAttr('maxVersions')).hasText('Maximum versions must be a number.'); await fillIn(FORM.inputByAttr('maxVersions'), '99999999999999999'); await click(FORM.saveBtn); - assert.dom(FORM.validation('maxVersions')).hasText('You cannot go over 16 characters.'); + assert.dom(GENERAL.validationErrorByAttr('maxVersions')).hasText('You cannot go over 16 characters.'); await fillIn(FORM.inputByAttr('maxVersions'), '7'); // Fill in other metadata @@ -378,7 +378,7 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // Create secret form -- validations await click(FORM.saveBtn); assert.dom(FORM.invalidFormAlert).hasText('There is an error with this form.'); - assert.dom(FORM.validation('path')).hasText("Path can't be blank."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't be blank."); await typeIn(FORM.inputByAttr('path'), secretPath); assert .dom(FORM.validationWarning) @@ -425,9 +425,9 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // Create secret await typeIn(FORM.inputByAttr('path'), 'my/'); - assert.dom(FORM.validation('path')).hasText("Path can't end in forward slash '/'."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't end in forward slash '/'."); await typeIn(FORM.inputByAttr('path'), 'secret'); - assert.dom(FORM.validation('path')).doesNotExist('form validation goes away'); + assert.dom(GENERAL.validationErrorByAttr('path')).doesNotExist('form validation goes away'); await fillIn(FORM.keyInput(), 'password'); await fillIn(FORM.maskedValueInput(), 'kittens1234'); @@ -440,10 +440,10 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // MaxVersions validation await fillIn(FORM.inputByAttr('maxVersions'), 'seven'); await click(FORM.saveBtn); - assert.dom(FORM.validation('maxVersions')).hasText('Maximum versions must be a number.'); + assert.dom(GENERAL.validationErrorByAttr('maxVersions')).hasText('Maximum versions must be a number.'); await fillIn(FORM.inputByAttr('maxVersions'), '99999999999999999'); await click(FORM.saveBtn); - assert.dom(FORM.validation('maxVersions')).hasText('You cannot go over 16 characters.'); + assert.dom(GENERAL.validationErrorByAttr('maxVersions')).hasText('You cannot go over 16 characters.'); await fillIn(FORM.inputByAttr('maxVersions'), '7'); // Fill in other metadata @@ -527,7 +527,7 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // Create secret form -- validations await click(FORM.saveBtn); assert.dom(FORM.invalidFormAlert).hasText('There is an error with this form.'); - assert.dom(FORM.validation('path')).hasText("Path can't be blank."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't be blank."); await typeIn(FORM.inputByAttr('path'), secretPath); assert .dom(FORM.validationWarning) @@ -574,9 +574,9 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // Create secret await typeIn(FORM.inputByAttr('path'), 'my/'); - assert.dom(FORM.validation('path')).hasText("Path can't end in forward slash '/'."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't end in forward slash '/'."); await typeIn(FORM.inputByAttr('path'), 'secret'); - assert.dom(FORM.validation('path')).doesNotExist('form validation goes away'); + assert.dom(GENERAL.validationErrorByAttr('path')).doesNotExist('form validation goes away'); await fillIn(FORM.keyInput(), 'password'); await fillIn(FORM.maskedValueInput(), 'kittens1234'); @@ -589,10 +589,10 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // MaxVersions validation await fillIn(FORM.inputByAttr('maxVersions'), 'seven'); await click(FORM.saveBtn); - assert.dom(FORM.validation('maxVersions')).hasText('Maximum versions must be a number.'); + assert.dom(GENERAL.validationErrorByAttr('maxVersions')).hasText('Maximum versions must be a number.'); await fillIn(FORM.inputByAttr('maxVersions'), '99999999999999999'); await click(FORM.saveBtn); - assert.dom(FORM.validation('maxVersions')).hasText('You cannot go over 16 characters.'); + assert.dom(GENERAL.validationErrorByAttr('maxVersions')).hasText('You cannot go over 16 characters.'); await fillIn(FORM.inputByAttr('maxVersions'), '7'); // Fill in other metadata @@ -678,7 +678,7 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // Create secret form -- validations await click(FORM.saveBtn); assert.dom(FORM.invalidFormAlert).hasText('There is an error with this form.'); - assert.dom(FORM.validation('path')).hasText("Path can't be blank."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't be blank."); await typeIn(FORM.inputByAttr('path'), secretPath); assert .dom(FORM.validationWarning) @@ -743,9 +743,9 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // Create secret await typeIn(FORM.inputByAttr('path'), 'my/'); - assert.dom(FORM.validation('path')).hasText("Path can't end in forward slash '/'."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't end in forward slash '/'."); await typeIn(FORM.inputByAttr('path'), 'secret'); - assert.dom(FORM.validation('path')).doesNotExist('form validation goes away'); + assert.dom(GENERAL.validationErrorByAttr('path')).doesNotExist('form validation goes away'); await fillIn(FORM.keyInput(), 'password'); await fillIn(FORM.maskedValueInput(), 'kittens1234'); @@ -758,10 +758,10 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // MaxVersions validation await fillIn(FORM.inputByAttr('maxVersions'), 'seven'); await click(FORM.saveBtn); - assert.dom(FORM.validation('maxVersions')).hasText('Maximum versions must be a number.'); + assert.dom(GENERAL.validationErrorByAttr('maxVersions')).hasText('Maximum versions must be a number.'); await fillIn(FORM.inputByAttr('maxVersions'), '99999999999999999'); await click(FORM.saveBtn); - assert.dom(FORM.validation('maxVersions')).hasText('You cannot go over 16 characters.'); + assert.dom(GENERAL.validationErrorByAttr('maxVersions')).hasText('You cannot go over 16 characters.'); await fillIn(FORM.inputByAttr('maxVersions'), '7'); // Fill in other metadata @@ -888,7 +888,7 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // Create secret form -- validations await click(FORM.saveBtn); assert.dom(FORM.invalidFormAlert).hasText('There is an error with this form.'); - assert.dom(FORM.validation('path')).hasText("Path can't be blank."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't be blank."); await typeIn(FORM.inputByAttr('path'), secretPath); assert .dom(FORM.validationWarning) @@ -971,9 +971,9 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // Create secret await typeIn(FORM.inputByAttr('path'), 'my/'); - assert.dom(FORM.validation('path')).hasText("Path can't end in forward slash '/'."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't end in forward slash '/'."); await typeIn(FORM.inputByAttr('path'), 'secret'); - assert.dom(FORM.validation('path')).doesNotExist('form validation goes away'); + assert.dom(GENERAL.validationErrorByAttr('path')).doesNotExist('form validation goes away'); await fillIn(FORM.keyInput(), 'password'); await fillIn(FORM.maskedValueInput(), 'kittens1234'); @@ -986,10 +986,10 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook // MaxVersions validation await fillIn(FORM.inputByAttr('maxVersions'), 'seven'); await click(FORM.saveBtn); - assert.dom(FORM.validation('maxVersions')).hasText('Maximum versions must be a number.'); + assert.dom(GENERAL.validationErrorByAttr('maxVersions')).hasText('Maximum versions must be a number.'); await fillIn(FORM.inputByAttr('maxVersions'), '99999999999999999'); await click(FORM.saveBtn); - assert.dom(FORM.validation('maxVersions')).hasText('You cannot go over 16 characters.'); + assert.dom(GENERAL.validationErrorByAttr('maxVersions')).hasText('You cannot go over 16 characters.'); await fillIn(FORM.inputByAttr('maxVersions'), '7'); // Fill in other metadata @@ -1104,7 +1104,7 @@ path "${this.backend}/metadata/*" { // Create secret form -- validations await click(FORM.saveBtn); assert.dom(FORM.invalidFormAlert).hasText('There is an error with this form.'); - assert.dom(FORM.validation('path')).hasText("Path can't be blank."); + assert.dom(GENERAL.validationErrorByAttr('path')).hasText("Path can't be blank."); await typeIn(FORM.inputByAttr('path'), secretPath); assert.dom(PAGE.create.metadataSection).doesNotExist('Hides metadata section by default'); diff --git a/ui/tests/helpers/kv/kv-selectors.js b/ui/tests/helpers/kv/kv-selectors.js index 6edaf6861e..a2ad41876d 100644 --- a/ui/tests/helpers/kv/kv-selectors.js +++ b/ui/tests/helpers/kv/kv-selectors.js @@ -117,6 +117,7 @@ export const FORM = { inlineAlert: '[data-test-inline-alert]', validation: (attr) => `[data-test-field="${attr}"] [data-test-inline-alert]`, messageError: '[data-test-message-error]', + validationError: (attr) => `[data-test-validation-error="${attr}"]`, validationWarning: '[data-test-validation-warning]', invalidFormAlert: '[data-test-invalid-form-alert]', versionAlert: '[data-test-secret-version-alert]', diff --git a/ui/tests/integration/components/clients/config-test.js b/ui/tests/integration/components/clients/config-test.js index c21e6c1c50..9d3971decd 100644 --- a/ui/tests/integration/components/clients/config-test.js +++ b/ui/tests/integration/components/clients/config-test.js @@ -78,7 +78,7 @@ module('Integration | Component | client count config', function (hooks) { await fillIn('[data-test-input="retentionMonths"]', 20); await click(GENERAL.submitButton); assert - .dom('[data-test-inline-error-message]') + .dom(GENERAL.validationErrorByAttr('retentionMonths')) .hasText( 'Retention period must be greater than or equal to 48.', 'Validation error shows for min retention period' @@ -86,7 +86,7 @@ module('Integration | Component | client count config', function (hooks) { await fillIn('[data-test-input="retentionMonths"]', 90); await click(GENERAL.submitButton); assert - .dom('[data-test-inline-error-message]') + .dom(GENERAL.validationErrorByAttr('retentionMonths')) .hasText( 'Retention period must be less than or equal to 60.', 'Validation error shows for max retention period' @@ -142,7 +142,7 @@ module('Integration | Component | client count config', function (hooks) { await fillIn('[data-test-input="retentionMonths"]', 5); await click(GENERAL.submitButton); assert - .dom('[data-test-inline-error-message]') + .dom(GENERAL.validationErrorByAttr('retentionMonths')) .hasText( 'Retention period must be greater than or equal to 24.', 'Validation error shows for incorrect retention period' diff --git a/ui/tests/integration/components/config-ui/messages/page/create-and-edit-test.js b/ui/tests/integration/components/config-ui/messages/page/create-and-edit-test.js index 590b2d6f7d..ffc9eb3746 100644 --- a/ui/tests/integration/components/config-ui/messages/page/create-and-edit-test.js +++ b/ui/tests/integration/components/config-ui/messages/page/create-and-edit-test.js @@ -125,15 +125,12 @@ module('Integration | Component | messages/page/create-and-edit', function (hook }); test('it should have form vaildations', async function (assert) { + assert.expect(2); + await this.renderComponent(); await click(GENERAL.submitButton); - assert - .dom(CUSTOM_MESSAGES.input('title')) - .hasClass('has-error-border', 'show error border for title field'); - assert - .dom(`${CUSTOM_MESSAGES.fieldValidation('title')} ${CUSTOM_MESSAGES.inlineErrorMessage}`) - .hasText('Title is required.'); + assert.dom(`${GENERAL.validationErrorByAttr('title')}`).hasText('Title is required.'); assert.dom(`${GENERAL.validationErrorByAttr('message')}`).hasText('Message is required.'); }); diff --git a/ui/tests/integration/components/form-field-test.js b/ui/tests/integration/components/form-field-test.js index 5e5d6b44e3..f8a3c6d66a 100644 --- a/ui/tests/integration/components/form-field-test.js +++ b/ui/tests/integration/components/form-field-test.js @@ -107,28 +107,6 @@ module('Integration | Component | form field', function (hooks) { // LEGACY FORM FIELDS // ------------------ - test('it renders: string', async function (assert) { - const [model, spy] = await setup.call(this, createAttr('foo', 'string', { defaultValue: 'default' })); - assert.strictEqual(component.fields.objectAt(0).labelValue, 'Foo', 'renders a label'); - assert.strictEqual(component.fields.objectAt(0).inputValue, 'default', 'renders default value'); - assert.ok(component.hasInput, 'renders input for string'); - await component.fields.objectAt(0).input('bar').change(); - - assert.strictEqual(model.get('foo'), 'bar'); - assert.ok(spy.calledWith('foo', 'bar'), 'onChange called with correct args'); - }); - - test('it renders: number', async function (assert) { - const [model, spy] = await setup.call(this, createAttr('foo', 'number', { defaultValue: 5 })); - assert.strictEqual(component.fields.objectAt(0).labelValue, 'Foo', 'renders a label'); - assert.strictEqual(component.fields.objectAt(0).inputValue, '5', 'renders default value'); - assert.ok(component.hasInput, 'renders input for number'); - await component.fields.objectAt(0).input(8).change(); - - assert.strictEqual(model.get('foo'), '8'); - assert.ok(spy.calledWith('foo', '8'), 'onChange called with correct args'); - }); - test('it renders: object', async function (assert) { await setup.call(this, createAttr('foo', 'object')); assert.dom('[data-test-component="json-editor-title"]').hasText('Foo', 'renders a label'); @@ -283,14 +261,13 @@ module('Integration | Component | form field', function (hooks) { assert.strictEqual(component.fields.objectAt(0).labelValue, 'Not Foo', 'renders the label from options'); }); - test('it renders a help tooltip and placeholder', async function (assert) { + test('it renders a help tooltip', async function (assert) { await setup.call( this, - createAttr('foo', 'string', { helpText: 'Here is some help text', placeholder: 'example::value' }) + createAttr('foo', 'string', { editType: 'stringArray', helpText: 'Here is some help text' }) ); await component.tooltipTrigger(); assert.ok(component.hasTooltip, 'renders the tooltip component'); - assert.dom(GENERAL.inputByAttr('foo')).hasAttribute('placeholder', 'example::value'); }); test('it should not expand and toggle ttl when default 0s value is present', async function (assert) { @@ -1207,4 +1184,131 @@ module('Integration | Component | form field', function (hooks) { .exists('Validation warning renders') .hasText('Warning message #1 Warning message #2', 'Validation warnings are combined'); }); + + // ––––– editType === undefined && (type === 'string' || type === 'number') ––––– + + test('it renders: editType=undefined type=string - as Hds::Form::TextInput', async function (assert) { + const [model, spy] = await setup.call(this, createAttr('myfield', 'string', { defaultValue: 'default' })); + assert + .dom('.field [class^="hds-form-field"] input[type="text"].hds-form-text-input') + .exists('renders as Hds::Form::TextInput::Field'); + assert + .dom(`input[type=text]`) + .exists('renders input[type="text"]') + .hasAttribute( + 'data-test-input', + 'myfield', + 'input[type="text"] has correct `data-test-input` attribute' + ) + .hasAttribute('name', 'myfield', 'input[type="text"] has correct `name` attribute') + .hasAttribute('id', 'myfield', 'input[type="text"] has correct `id` attribute'); + assert.dom(GENERAL.fieldLabel()).hasText('Myfield', 'renders the input[type="text"] label'); + assert.dom(GENERAL.inputByAttr('myfield')).hasValue('default', 'renders default value'); + await fillIn(GENERAL.inputByAttr('myfield'), 'bar'); + assert.strictEqual(model.get('myfield'), 'bar'); + assert.true(spy.calledWith('myfield', 'bar'), 'onChange called with correct args'); + }); + + test('it renders: editType=undefined type=number - as Hds::Form::TextInput', async function (assert) { + const [model, spy] = await setup.call(this, createAttr('myfield', 'number', { defaultValue: 123 })); + assert + .dom('.field [class^="hds-form-field"] input[type="text"].hds-form-text-input') + .exists('renders as Hds::Form::TextInput::Field'); + assert + .dom(`input[type=text]`) + .exists('renders input[type="text"]') + .hasAttribute( + 'data-test-input', + 'myfield', + 'input[type="text"] has correct `data-test-input` attribute' + ) + .hasAttribute('name', 'myfield', 'input[type="text"] has correct `name` attribute') + .hasAttribute('id', 'myfield', 'input[type="text"] has correct `id` attribute'); + assert.dom(GENERAL.fieldLabel()).hasText('Myfield', 'renders the input[type="text"] label'); + assert.dom(GENERAL.inputByAttr('myfield')).hasValue('123', 'renders default value'); + await fillIn(GENERAL.inputByAttr('myfield'), 1234); + assert.strictEqual(model.get('myfield'), '1234'); + assert.true(spy.calledWith('myfield', '1234'), 'onChange called with correct args'); + }); + + test('it renders: editType=undefined - with passed characterLimit, docLink, editDisabled, helpText, label, placeholder, subText', async function (assert) { + await setup.call( + this, + createAttr('myfield', 'string', { + characterLimit: 10, + docLink: '/docs', + editDisabled: true, + helpText: 'Some helpText', + label: 'Custom label', + placeholder: 'Custom placeholder', + subText: 'Some subText', + }) + ); + assert.dom(GENERAL.fieldLabel()).hasText('Custom label', 'renders the custom label from options'); + assert + .dom('.hds-form-field__character-count') + .containsText('10', 'renders the characterLimit helper text from options'); + assert + .dom(GENERAL.inputByAttr('myfield')) + .hasAttribute('placeholder', 'Custom placeholder', 'renders the placeholder from options') + .hasAttribute('disabled', '', 'renders the disabled attribute from options') + .hasAttribute('maxlength', '10', 'renders the characterLimit from options'); + assert + .dom(GENERAL.helpTextByAttr('Some subText')) + .exists('renders `subText` option as HelperText') + .hasText( + 'Some subText See our documentation for help.', + 'renders the right subText string from options' + ); + assert + .dom(`${GENERAL.helpTextByAttr('Some subText')} ${GENERAL.docLinkByAttr('/docs')}`) + .exists('renders `docLink` option as as link inside the subText'); + assert + .dom(GENERAL.helpTextByAttr('Some helpText')) + .exists('renders `helpText` option as HelperText') + .hasText('Some helpText', 'renders the right helpText string from options'); + }); + + test('it renders: editType=undefined - with readOnly when mode=edit', async function (assert) { + this.setProperties({ + attr: createAttr('myfield', 'string', { readOnly: true }), + mode: 'edit', + model: { myfield: false }, + onChange: () => {}, + }); + + await render( + hbs`` + ); + assert + .dom(GENERAL.inputByAttr('myfield')) + .hasAttribute('readonly', '', 'renders the readOnly attribute from options'); + }); + + test('it renders: editType=undefined - with validation errors and warnings', async function (assert) { + this.setProperties({ + attr: createAttr('myfield', 'string'), + model: { myfield: false }, + modelValidations: { + myfield: { + isValid: false, + errors: ['Error message #1', 'Error message #2'], + warnings: ['Warning message #1', 'Warning message #2'], + }, + }, + onChange: () => {}, + }); + + await render( + hbs`` + ); + assert + .dom(GENERAL.validationErrorByAttr('myfield')) + .exists('Validation error renders') + .hasText('Error message #1 Error message #2', 'Validation errors are combined'); + assert + .dom(GENERAL.validationWarningByAttr('myfield')) + .exists('Validation warning renders') + .hasText('Warning message #1 Warning message #2', 'Validation warnings are combined'); + }); }); diff --git a/ui/tests/integration/components/keymgmt/provider-edit-test.js b/ui/tests/integration/components/keymgmt/provider-edit-test.js index 9aa3fef963..5da7173020 100644 --- a/ui/tests/integration/components/keymgmt/provider-edit-test.js +++ b/ui/tests/integration/components/keymgmt/provider-edit-test.js @@ -199,7 +199,7 @@ module('Integration | Component | keymgmt/provider-edit', function (hooks) { assert.dom(`[${ts}-creds-title]`).doesNotExist('New credentials header hidden in create mode'); await click(`[${ts}-submit]`); - assert.dom('[data-test-inline-error-message]').exists('Validation error messages shown'); + assert.dom('[data-test-validation-error]').exists('Validation error messages shown'); await fillIn('[data-test-input="provider"]', 'azurekeyvault'); ['client_id', 'client_secret', 'tenant_id'].forEach((prop) => { diff --git a/ui/tests/integration/components/kubernetes/page/configure-test.js b/ui/tests/integration/components/kubernetes/page/configure-test.js index 1877ccfb6a..0979db68fa 100644 --- a/ui/tests/integration/components/kubernetes/page/configure-test.js +++ b/ui/tests/integration/components/kubernetes/page/configure-test.js @@ -231,7 +231,7 @@ module('Integration | Component | kubernetes | Page::Configure', function (hooks await click('[data-test-config-save]'); assert - .dom(`${GENERAL.validationErrorByAttr('kubernetesHost')} [data-test-inline-error-message]`) + .dom(GENERAL.validationErrorByAttr('kubernetesHost')) .hasText('Kubernetes host is required', 'Error renders for required field'); assert.dom('[data-test-alert]').hasText('There is an error with this form.', 'Alert renders'); }); diff --git a/ui/tests/integration/components/kubernetes/page/role/create-and-edit-test.js b/ui/tests/integration/components/kubernetes/page/role/create-and-edit-test.js index 3981ad397b..5db6ee649f 100644 --- a/ui/tests/integration/components/kubernetes/page/role/create-and-edit-test.js +++ b/ui/tests/integration/components/kubernetes/page/role/create-and-edit-test.js @@ -163,7 +163,7 @@ module('Integration | Component | kubernetes | Page::Role::CreateAndEdit', funct ); await click('[data-test-radio-card="basic"]'); await click('[data-test-submit]'); - assert.dom('[data-test-inline-error-message]').hasText('Name is required', 'Validation error renders'); + assert.dom(GENERAL.validationErrorByAttr('name')).hasText('Name is required', 'Validation error renders'); await fillIn('[data-test-input="name"]', 'role-1'); await fillIn('[data-test-input="serviceAccountName"]', 'default'); await click('[data-test-submit]'); @@ -327,10 +327,7 @@ module('Integration | Component | kubernetes | Page::Role::CreateAndEdit', funct ); await click('[data-test-radio-card="basic"]'); await click('[data-test-submit]'); - assert - .dom('[data-test-input="name"]') - .hasClass('has-error-border', 'shows border error on input with error'); - assert.dom('[data-test-inline-error-message]').hasText('Name is required'); + assert.dom(GENERAL.validationErrorByAttr('name')).hasText('Name is required'); assert .dom('[data-test-invalid-form-alert] [data-test-inline-error-message]') .hasText('There is an error with this form.'); diff --git a/ui/tests/integration/components/kv/page/kv-page-metadata-edit-test.js b/ui/tests/integration/components/kv/page/kv-page-metadata-edit-test.js index 6cef2ea9f3..871d67e5c0 100644 --- a/ui/tests/integration/components/kv/page/kv-page-metadata-edit-test.js +++ b/ui/tests/integration/components/kv/page/kv-page-metadata-edit-test.js @@ -148,7 +148,7 @@ module('Integration | Component | kv | Page::Secret::Metadata::Edit', function ( await fillIn(FORM.inputByAttr('maxVersions'), 'a'); await click(FORM.saveBtn); assert - .dom(FORM.inlineAlert) + .dom(FORM.validationError('maxVersions')) .hasText('Maximum versions must be a number.', 'Validation message is shown for max_versions'); await click(FORM.cancelBtn); diff --git a/ui/tests/integration/components/kv/page/kv-page-secrets-create-test.js b/ui/tests/integration/components/kv/page/kv-page-secrets-create-test.js index 59049ff26e..06fdd036bc 100644 --- a/ui/tests/integration/components/kv/page/kv-page-secrets-create-test.js +++ b/ui/tests/integration/components/kv/page/kv-page-secrets-create-test.js @@ -9,7 +9,7 @@ import { setupEngine } from 'ember-engines/test-support'; import { setupMirage } from 'ember-cli-mirage/test-support'; import { Response } from 'miragejs'; import { hbs } from 'ember-cli-htmlbars'; -import { click, fillIn, findAll, render, typeIn } from '@ember/test-helpers'; +import { click, fillIn, render, typeIn } from '@ember/test-helpers'; import codemirror from 'vault/tests/helpers/codemirror'; import { FORM } from 'vault/tests/helpers/kv/kv-selectors'; import sinon from 'sinon'; @@ -242,11 +242,11 @@ module('Integration | Component | kv-v2 | Page::Secrets::Create', function (hook await fillIn(FORM.inputByAttr('path'), ''); // clear input await typeIn(FORM.inputByAttr('path'), 'slash/'); - assert.dom(FORM.validation('path')).hasText(`Path can't end in forward slash '/'.`); + assert.dom(FORM.validationError('path')).hasText(`Path can't end in forward slash '/'.`); await typeIn(FORM.inputByAttr('path'), 'secret'); assert - .dom(FORM.validation('path')) + .dom(FORM.validationError('path')) .doesNotExist('it removes validation on key up when secret contains slash but does not end in one'); await click(GENERAL.toggleInput('json')); @@ -258,9 +258,8 @@ module('Integration | Component | kv-v2 | Page::Secrets::Create', function (hook codemirror().setValue('{}'); // clear linting error await fillIn(FORM.inputByAttr('path'), ''); await click(FORM.saveBtn); - const [pathValidation, formAlert] = findAll(FORM.inlineAlert); - assert.dom(pathValidation).hasText(`Path can't be blank.`); - assert.dom(formAlert).hasText('There is an error with this form.'); + assert.dom(FORM.validationError('path')).hasText(`Path can't be blank.`); + assert.dom(FORM.inlineAlert).hasText('There is an error with this form.'); }); test('it toggles JSON view and saves modified data', async function (assert) { diff --git a/ui/tests/integration/components/ldap/page/configure-test.js b/ui/tests/integration/components/ldap/page/configure-test.js index 681f43048e..bdc270360f 100644 --- a/ui/tests/integration/components/ldap/page/configure-test.js +++ b/ui/tests/integration/components/ldap/page/configure-test.js @@ -81,10 +81,10 @@ module('Integration | Component | ldap | Page::Configure', function (hooks) { await click(selectors.save); assert - .dom('[data-test-field="binddn"] [data-test-inline-error-message]') + .dom(GENERAL.validationErrorByAttr('binddn')) .hasText('Administrator distinguished name is required.', 'Validation message renders for binddn'); assert - .dom('[data-test-field="bindpass"] [data-test-inline-error-message]') + .dom(GENERAL.validationErrorByAttr('bindpass')) .hasText('Administrator password is required.', 'Validation message renders for bindpass'); assert .dom('[data-test-invalid-form-message]') diff --git a/ui/tests/integration/components/ldap/page/role/create-and-edit-test.js b/ui/tests/integration/components/ldap/page/role/create-and-edit-test.js index 9a6f10c99a..566c1474f7 100644 --- a/ui/tests/integration/components/ldap/page/role/create-and-edit-test.js +++ b/ui/tests/integration/components/ldap/page/role/create-and-edit-test.js @@ -11,6 +11,7 @@ import { render, click, fillIn } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import sinon from 'sinon'; import { ldapRoleID } from 'vault/adapters/ldap/role'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Integration | Component | ldap | Page::Role::CreateAndEdit', function (hooks) { setupRenderingTest(hooks); @@ -135,9 +136,7 @@ module('Integration | Component | ldap | Page::Role::CreateAndEdit', function (h await click('[data-test-submit]'); fields.forEach((field) => { - assert - .dom(`[data-test-field="${field}"] [data-test-inline-error-message]`) - .exists('Validation message renders'); + assert.dom(GENERAL.validationErrorByAttr(field)).exists('Validation message renders'); }); assert diff --git a/ui/tests/integration/components/oidc/client-form-test.js b/ui/tests/integration/components/oidc/client-form-test.js index b144b80a0d..17636b1289 100644 --- a/ui/tests/integration/components/oidc/client-form-test.js +++ b/ui/tests/integration/components/oidc/client-form-test.js @@ -102,10 +102,12 @@ module('Integration | Component | oidc/client-form', function (hooks) { const validationErrors = findAll(SELECTORS.inlineAlert); assert - .dom(validationErrors[0]) + .dom(GENERAL.validationErrorByAttr('name')) .hasText('Name is required. Name cannot contain whitespace.', 'Validation messages are shown for name'); - assert.dom(validationErrors[1]).hasText('Key is required.', 'Validation message is shown for key'); - assert.dom(validationErrors[2]).hasText('There are 3 errors with this form.', 'Renders form error count'); + assert + .dom(GENERAL.validationErrorByAttr('key')) + .hasText('Key is required.', 'Validation message is shown for key'); + assert.dom(validationErrors[1]).hasText('There are 3 errors with this form.', 'Renders form error count'); // fill out form with valid inputs await clickTrigger(); diff --git a/ui/tests/integration/components/oidc/key-form-test.js b/ui/tests/integration/components/oidc/key-form-test.js index 55b5c297d8..3b3859ced7 100644 --- a/ui/tests/integration/components/oidc/key-form-test.js +++ b/ui/tests/integration/components/oidc/key-form-test.js @@ -12,6 +12,7 @@ import oidcConfigHandlers from 'vault/mirage/handlers/oidc-config'; import { OIDC_BASE_URL, CLIENT_LIST_RESPONSE, SELECTORS } from 'vault/tests/helpers/oidc-config'; import { setRunOptions } from 'ember-a11y-testing/test-support'; import { capabilitiesStub, overrideResponse } from 'vault/tests/helpers/stubs'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Integration | Component | oidc/key-form', function (hooks) { setupRenderingTest(hooks); @@ -57,11 +58,12 @@ module('Integration | Component | oidc/key-form', function (hooks) { await fillIn('[data-test-input="name"]', ' '); await click(SELECTORS.keySaveButton); - const validationErrors = findAll(SELECTORS.inlineAlert); assert - .dom(validationErrors[0]) + .dom(GENERAL.validationErrorByAttr('name')) .hasText('Name is required. Name cannot contain whitespace.', 'Validation messages are shown for name'); - assert.dom(validationErrors[1]).hasText('There are 2 errors with this form.', 'Renders form error count'); + assert + .dom(SELECTORS.inlineAlert) + .hasText('There are 2 errors with this form.', 'Renders form error count'); assert.dom('[data-test-oidc-radio="limited"] input').isDisabled('limit radio button disabled on create'); await fillIn('[data-test-input="name"]', 'test-key'); diff --git a/ui/tests/integration/components/oidc/provider-form-test.js b/ui/tests/integration/components/oidc/provider-form-test.js index 538d75abf9..ee7cdb44a3 100644 --- a/ui/tests/integration/components/oidc/provider-form-test.js +++ b/ui/tests/integration/components/oidc/provider-form-test.js @@ -13,6 +13,7 @@ import { SELECTORS, OIDC_BASE_URL, CLIENT_LIST_RESPONSE } from 'vault/tests/help import parseURL from 'core/utils/parse-url'; import { setRunOptions } from 'ember-a11y-testing/test-support'; import { capabilitiesStub, overrideResponse } from 'vault/tests/helpers/stubs'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; const ISSUER_URL = 'http://127.0.0.1:8200/v1/identity/oidc/provider/test-provider'; @@ -81,11 +82,12 @@ module('Integration | Component | oidc/provider-form', function (hooks) { await fillIn('[data-test-input="name"]', ' '); await click(SELECTORS.providerSaveButton); - const validationErrors = findAll(SELECTORS.inlineAlert); assert - .dom(validationErrors[0]) + .dom(GENERAL.validationErrorByAttr('name')) .hasText('Name is required. Name cannot contain whitespace.', 'Validation messages are shown for name'); - assert.dom(validationErrors[1]).hasText('There are 2 errors with this form.', 'Renders form error count'); + assert + .dom(SELECTORS.inlineAlert) + .hasText('There are 2 errors with this form.', 'Renders form error count'); await click('[data-test-oidc-radio="limited"]'); assert diff --git a/ui/tests/integration/components/oidc/scope-form-test.js b/ui/tests/integration/components/oidc/scope-form-test.js index a2454434d1..987673904f 100644 --- a/ui/tests/integration/components/oidc/scope-form-test.js +++ b/ui/tests/integration/components/oidc/scope-form-test.js @@ -5,11 +5,12 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; -import { render, fillIn, click, findAll } from '@ember/test-helpers'; +import { render, fillIn, click } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; import { setupMirage } from 'ember-cli-mirage/test-support'; import { SELECTORS, OIDC_BASE_URL } from 'vault/tests/helpers/oidc-config'; import { capabilitiesStub } from 'vault/tests/helpers/stubs'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Integration | Component | oidc/scope-form', function (hooks) { setupRenderingTest(hooks); @@ -20,7 +21,7 @@ module('Integration | Component | oidc/scope-form', function (hooks) { }); test('it should save new scope', async function (assert) { - assert.expect(9); + assert.expect(8); this.server.post('/identity/oidc/scope/test', (schema, req) => { assert.ok(true, 'Request made to save scope'); @@ -45,13 +46,13 @@ module('Integration | Component | oidc/scope-form', function (hooks) { // check validation errors await click(SELECTORS.scopeSaveButton); - const validationErrors = findAll(SELECTORS.inlineAlert); - assert.dom(validationErrors[0]).hasText('Name is required.', 'Validation messages are shown for name'); - assert.dom(validationErrors[1]).hasText('There is an error with this form.', 'Renders form error count'); - assert - .dom('[data-test-inline-error-message]') - .hasText('Name is required.', 'Validation message is shown for name'); + .dom(GENERAL.validationErrorByAttr('name')) + .hasText('Name is required.', 'Validation messages are shown for name'); + assert + .dom(SELECTORS.inlineAlert) + .hasText('There is an error with this form.', 'Renders form error count'); + // json editor has test coverage so let's just confirm that it renders assert .dom('[data-test-input="template"] [data-test-component="json-editor-toolbar"]') diff --git a/ui/tests/integration/components/pki/page/pki-issuer-rotate-root-test.js b/ui/tests/integration/components/pki/page/pki-issuer-rotate-root-test.js index 47d68d5733..9ca7869869 100644 --- a/ui/tests/integration/components/pki/page/pki-issuer-rotate-root-test.js +++ b/ui/tests/integration/components/pki/page/pki-issuer-rotate-root-test.js @@ -126,12 +126,8 @@ module('Integration | Component | page/pki-issuer-rotate-root', function (hooks) await fillIn(GENERAL.inputByAttr('issuerName'), 'default'); await click(GENERAL.submitButton); assert.dom(SELECTORS.validationError).hasText('There are 2 errors with this form.'); - assert - .dom(GENERAL.inputByAttr('commonName')) - .hasClass('has-error-border', 'common name has error border'); - assert - .dom(GENERAL.inputByAttr('issuerName')) - .hasClass('has-error-border', 'issuer name has error border'); + assert.dom(GENERAL.validationErrorByAttr('commonName')).exists(); + assert.dom(GENERAL.validationErrorByAttr('issuerName')).exists(); }); test('it sends request to rotate/internal on save when using old root settings', async function (assert) { diff --git a/ui/tests/integration/components/pki/pki-generate-csr-test.js b/ui/tests/integration/components/pki/pki-generate-csr-test.js index 2898ebfa6f..79b7280e59 100644 --- a/ui/tests/integration/components/pki/pki-generate-csr-test.js +++ b/ui/tests/integration/components/pki/pki-generate-csr-test.js @@ -105,7 +105,7 @@ module('Integration | Component | pki-generate-csr', function (hooks) { .dom(GENERAL.validationErrorByAttr('type')) .hasText('Type is required.', 'Type validation error renders'); assert - .dom('[data-test-field="commonName"] [data-test-inline-alert]') + .dom(GENERAL.validationErrorByAttr('commonName')) .hasText('Common name is required.', 'Common name validation error renders'); assert.dom('[data-test-alert]').hasText('There are 2 errors with this form.', 'Alert renders'); diff --git a/ui/tests/integration/components/pki/pki-role-form-test.js b/ui/tests/integration/components/pki/pki-role-form-test.js index 1796e62b3a..4973ad9332 100644 --- a/ui/tests/integration/components/pki/pki-role-form-test.js +++ b/ui/tests/integration/components/pki/pki-role-form-test.js @@ -86,7 +86,7 @@ module('Integration | Component | pki-role-form', function (hooks) { test('it should save a new pki role with various options selected', async function (assert) { // Key usage, Key params and Not valid after options are tested in their respective component tests - assert.expect(8); + assert.expect(7); this.server.post(`/${this.role.backend}/roles/test-role`, (schema, req) => { assert.ok(true, 'Request made to save role'); const request = JSON.parse(req.requestBody); @@ -123,10 +123,7 @@ module('Integration | Component | pki-role-form', function (hooks) { await click(GENERAL.submitButton); assert - .dom(GENERAL.inputByAttr('name')) - .hasClass('has-error-border', 'shows border error on role name field when no role name is submitted'); - assert - .dom('[data-test-inline-error-message]') + .dom(GENERAL.validationErrorByAttr('name')) .includesText('Name is required.', 'show correct error message'); await fillIn(GENERAL.inputByAttr('name'), 'test-role'); 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 407ebeb56c..6b74d9068e 100644 --- a/ui/tests/integration/components/secret-engine/configure-ssh-test.js +++ b/ui/tests/integration/components/secret-engine/configure-ssh-test.js @@ -65,7 +65,7 @@ module('Integration | Component | SecretEngine/configure-ssh', function (hooks) await fillIn(GENERAL.inputByAttr('publicKey'), 'hello'); await click(GENERAL.submitButton); assert - .dom(GENERAL.inlineError) + .dom(GENERAL.validationErrorByAttr('publicKey')) .hasText( 'You must provide a Public and Private keys or leave both unset.', 'Public key validation error renders.' @@ -74,9 +74,9 @@ module('Integration | Component | SecretEngine/configure-ssh', function (hooks) await click(GENERAL.inputByAttr('generateSigningKey')); await click(GENERAL.submitButton); assert - .dom(GENERAL.inlineError) + .dom(GENERAL.validationErrorByAttr('generateSigningKey')) .hasText( - 'You must provide a Public and Private keys or leave both unset.', + 'Provide a Public and Private key or set "Generate Signing Key" to true.', 'Generate signing key validation message shows.' ); }); diff --git a/ui/tests/integration/components/totp/key-form-test.js b/ui/tests/integration/components/totp/key-form-test.js index 7a00ef01c7..261ff353e2 100644 --- a/ui/tests/integration/components/totp/key-form-test.js +++ b/ui/tests/integration/components/totp/key-form-test.js @@ -5,7 +5,7 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; -import { render, fillIn, click, findAll } from '@ember/test-helpers'; +import { render, fillIn, click } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; import { setupMirage } from 'ember-cli-mirage/test-support'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; @@ -57,21 +57,22 @@ module('Integration | Component | totp/key-form', function (hooks) { // check validation errors await click(GENERAL.submitButton); - const validationErrors = findAll(GENERAL.inlineAlert); - assert.dom(validationErrors[0]).hasText(`Name can't be blank.`, 'Validation messages are shown for name'); assert - .dom(validationErrors[1]) + .dom(GENERAL.validationErrorByAttr('name')) + .hasText(`Name can't be blank.`, 'Validation messages are shown for name'); + assert + .dom(GENERAL.validationErrorByAttr('issuer')) .hasText( `Issuer can't be blank when when the key is generated by Vault.`, 'Validation messages are shown for issuer' ); assert - .dom(validationErrors[2]) + .dom(GENERAL.validationErrorByAttr('accountName')) .hasText( `Account name can't be blank when the key is generated by Vault.`, 'Validation messages are shown for account name' ); - assert.dom(validationErrors[3]).hasText('There are 3 errors with this form.', 'Renders form error count'); + assert.dom(GENERAL.inlineAlert).hasText('There are 3 errors with this form.', 'Renders form error count'); await fillIn('[data-test-input="name"]', 'test-key'); await fillIn('[data-test-input="issuer"]', 'test-issuer'); @@ -117,15 +118,16 @@ module('Integration | Component | totp/key-form', function (hooks) { // check validation errors await click(GENERAL.submitButton); - const validationErrors = findAll(GENERAL.inlineAlert); - assert.dom(validationErrors[0]).hasText(`Name can't be blank.`, 'Validation messages are shown for name'); assert - .dom(validationErrors[1]) + .dom(GENERAL.validationErrorByAttr('name')) + .hasText(`Name can't be blank.`, 'Validation messages are shown for name'); + assert + .dom(GENERAL.validationErrorByAttr('key')) .hasText( `Key can't be blank if key is being passed from another service and the URL is empty.`, 'Validation messages are shown for issuer' ); - assert.dom(validationErrors[2]).hasText('There are 2 errors with this form.', 'Renders form error count'); + assert.dom(GENERAL.inlineAlert).hasText('There are 2 errors with this form.', 'Renders form error count'); await fillIn('[data-test-input="name"]', 'test-key'); await fillIn('[data-test-input="key"]', 'test-root-key'); diff --git a/ui/tests/integration/helpers/transition-to-test.js b/ui/tests/integration/helpers/transition-to-test.js index 32b7e35ac6..57e9926f09 100644 --- a/ui/tests/integration/helpers/transition-to-test.js +++ b/ui/tests/integration/helpers/transition-to-test.js @@ -25,7 +25,9 @@ module('Integration | Helper | transition-to', function (hooks) { }); test('it does not call transition on render', async function (assert) { - await render(hbs``); + await render( + hbs`` + ); assert.true(this.router.transitionTo.notCalled, 'transitionTo not called on render'); assert.true(this.router.transitionToExternal.notCalled, 'transitionToExternal not called on render'); @@ -33,7 +35,7 @@ module('Integration | Helper | transition-to', function (hooks) { test('it calls transitionTo correctly', async function (assert) { await render( - hbs`` + hbs`` ); await click('[data-test-btn]'); @@ -48,7 +50,7 @@ module('Integration | Helper | transition-to', function (hooks) { test('it calls transitionToExternal correctly', async function (assert) { await render( - hbs`` + hbs`` ); await click('[data-test-btn]'); @@ -68,7 +70,7 @@ module('Integration | Helper | transition-to', function (hooks) { // This test passing, indirectly means the helper works as expected. Failures might be something like "global failure: TypeError: this.router is undefined" test('it uses service:app-router when base router undefined', async function (assert) { await render( - hbs``, + hbs``, { owner: this.engine } ); await click('[data-test-btn]');