From 831d85b87a93e1b71155581934e205bb53e272b1 Mon Sep 17 00:00:00 2001 From: Erika McVey <50454925+Blackbaud-ErikaMcVey@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:07:37 -0500 Subject: [PATCH 1/2] fix(components/forms): refactor form errors --- .../forms/input-box/basic/demo.component.html | 32 +++-- .../input-box/basic/demo.component.spec.ts | 33 +++-- .../forms/input-box/basic/demo.component.ts | 9 +- .../forms/input-box/input-box.component.html | 10 ++ .../forms/input-box/input-box.component.ts | 16 +++ libs/components/forms/src/index.ts | 3 + .../form-error/form-error.component.ts | 37 +++++- .../modules/form-error/form-errors-token.ts | 3 + .../form-error/form-errors.component.html | 26 ++-- .../form-error/form-errors.component.scss | 1 + .../input-box/input-box.component.html | 1 + .../modules/input-box/input-box.component.ts | 6 + .../lib/modules/input-box/input-box.module.ts | 8 +- .../src/form-error/form-error-harness.ts | 11 +- .../form-error/form-errors-harness.spec.ts | 89 +++++-------- .../src/form-error/form-errors-harness.ts | 105 +++------------ .../input-box-harness-test.component.html | 49 +++++++ .../input-box-harness-test.component.ts | 6 + .../fixtures/input-box-harness-test.module.ts | 5 + .../src/input-box/input-box-harness.spec.ts | 122 ++++++++++++++++++ .../src/input-box/input-box-harness.ts | 68 ++++++++++ 21 files changed, 430 insertions(+), 210 deletions(-) create mode 100644 libs/components/forms/src/lib/modules/form-error/form-errors-token.ts diff --git a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.html b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.html index 2f5f2f99d3..46842d9304 100644 --- a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.html +++ b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.html @@ -16,8 +16,17 @@

New member form

- - + + @@ -69,18 +78,15 @@

New member form

- + - -
- - {{ colorError.message }} - -
+ + + Blur is not a color. + diff --git a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.spec.ts index a348799fb8..a6690a2409 100644 --- a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.spec.ts @@ -1,6 +1,7 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TestBed } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { SkyAppTestUtility } from '@skyux-sdk/testing'; import { SkyInputBoxHarness } from '@skyux/forms/testing'; import { DemoComponent } from './demo.component'; @@ -40,6 +41,22 @@ describe('Basic input box demo', () => { }); }); + describe('last name field', () => { + it('should have last name required', async () => { + const harness = await setupTest({ + dataSkyId: 'input-box-last-name', + }); + const inputEl = document.querySelector( + 'input.last-name-input-box', + ) as HTMLInputElement; + inputEl.value = ''; + SkyAppTestUtility.fireDomEvent(inputEl, 'input'); + SkyAppTestUtility.fireDomEvent(inputEl, 'blur'); + + await expectAsync(harness.hasRequiredError()).toBeResolvedTo(true); + }); + }); + describe('bio field', () => { it('should have a character limit of 250', async () => { const harness = await setupTest({ @@ -71,7 +88,7 @@ describe('Basic input box demo', () => { }); describe('favorite color field', () => { - it('should not allow bird to be selected', async () => { + it('should not allow blur to be selected', async () => { const harness = await setupTest({ dataSkyId: 'input-box-favorite-color', }); @@ -80,19 +97,11 @@ describe('Basic input box demo', () => { '.input-box-favorite-color-select', ) as HTMLSelectElement; - selectEl.value = 'bird'; + selectEl.value = 'blur'; selectEl.dispatchEvent(new Event('change')); - const customErrors = await harness.getCustomErrors(); - - expect(customErrors.length).toBe(1); - - const birdError = customErrors[0]; - - await expectAsync(birdError.getDescriptionType()).toBeResolvedTo('error'); - await expectAsync(birdError.getIndicatorType()).toBeResolvedTo('danger'); - await expectAsync(birdError.getText()).toBeResolvedTo( - 'Bird is not a color.', + await expectAsync(harness.hasCustomFormError('color')).toBeResolvedTo( + true, ); }); }); diff --git a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.ts b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.ts index c6f2f3abc0..17dbd1c267 100644 --- a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.ts @@ -44,13 +44,8 @@ export class DemoComponent { constructor() { this.favoriteColor = new FormControl('none', [ (control): ValidationErrors | null => { - if (control.value === 'bird') { - return { - color: { - invalid: true, - message: 'Bird is not a color.', - }, - }; + if (control.value === 'blur') { + return { color: true }; } return null; diff --git a/apps/playground/src/app/components/forms/input-box/input-box.component.html b/apps/playground/src/app/components/forms/input-box/input-box.component.html index 7e113fea6c..2a5f1e10e7 100644 --- a/apps/playground/src/app/components/forms/input-box/input-box.component.html +++ b/apps/playground/src/app/components/forms/input-box/input-box.component.html @@ -245,6 +245,16 @@
+ + + + Input must be blue. + + { + console.log(control.value); + if (control.value !== 'blue') { + return { blue: true }; + } + return null; + }, + Validators.required, + Validators.maxLength(1), + ]); + this.errorField.markAsTouched(); this.errorForm = new UntypedFormGroup({ errorFormField: new UntypedFormControl('', [Validators.required]), + customError: this.customError, }); this.errorAutofillForm = new UntypedFormGroup({ errorAutofillFormField: new UntypedFormControl('', [ diff --git a/libs/components/forms/src/index.ts b/libs/components/forms/src/index.ts index 5f047eecc3..f4aa170c35 100644 --- a/libs/components/forms/src/index.ts +++ b/libs/components/forms/src/index.ts @@ -29,6 +29,9 @@ export { SkySelectionBoxGridAlignItemsType } from './lib/modules/selection-box/t export { SkyToggleSwitchModule } from './lib/modules/toggle-switch/toggle-switch.module'; export { SkyToggleSwitchChange } from './lib/modules/toggle-switch/types/toggle-switch-change'; +export { SkyFormErrorComponent } from './lib/modules/form-error/form-error.component'; +export { FORM_ERRORS } from './lib/modules/form-error/form-errors-token'; + // Components and directives must be exported to support Angular's "partial" Ivy compiler. // Obscure names are used to indicate types are not part of the public API. diff --git a/libs/components/forms/src/lib/modules/form-error/form-error.component.ts b/libs/components/forms/src/lib/modules/form-error/form-error.component.ts index 1aae6fd575..679f12e147 100644 --- a/libs/components/forms/src/lib/modules/form-error/form-error.component.ts +++ b/libs/components/forms/src/lib/modules/form-error/form-error.component.ts @@ -1,15 +1,26 @@ -import { ChangeDetectionStrategy, Component, HostBinding } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + HostBinding, + Input, + inject, +} from '@angular/core'; import { SkyStatusIndicatorModule } from '@skyux/indicators'; +import { FORM_ERRORS } from './form-errors-token'; + /** * @internal */ @Component({ selector: 'sky-form-error', standalone: true, - imports: [SkyStatusIndicatorModule], + imports: [SkyStatusIndicatorModule, CommonModule], template: ` ('FORM_ERRORS'); diff --git a/libs/components/forms/src/lib/modules/form-error/form-errors.component.html b/libs/components/forms/src/lib/modules/form-error/form-errors.component.html index 43003248ee..850a0bda11 100644 --- a/libs/components/forms/src/lib/modules/form-error/form-errors.component.html +++ b/libs/components/forms/src/lib/modules/form-error/form-errors.component.html @@ -1,11 +1,11 @@ - + {{ 'skyux_form_error_required' | skyLibResources : labelText }} {{ 'skyux_form_error_maxlength' @@ -15,7 +15,7 @@ {{ 'skyux_form_error_minlength' @@ -23,33 +23,23 @@ }} - - {{ - 'skyux_form_error_character_count' - | skyLibResources : labelText : characterCounterError.limit - }} - - - + {{ 'skyux_form_error_date' | skyLibResources }} - + {{ 'skyux_form_error_email' | skyLibResources }} - + {{ 'skyux_form_error_phone' | skyLibResources }} - + {{ 'skyux_form_error_time' | skyLibResources }} - + {{ 'skyux_form_error_url' | skyLibResources }} diff --git a/libs/components/forms/src/lib/modules/form-error/form-errors.component.scss b/libs/components/forms/src/lib/modules/form-error/form-errors.component.scss index de61745539..5f35216baf 100644 --- a/libs/components/forms/src/lib/modules/form-error/form-errors.component.scss +++ b/libs/components/forms/src/lib/modules/form-error/form-errors.component.scss @@ -1,4 +1,5 @@ :host, sky-status-indicator { display: block; + line-height: normal; } diff --git a/libs/components/forms/src/lib/modules/input-box/input-box.component.html b/libs/components/forms/src/lib/modules/input-box/input-box.component.html index 477d94e91c..633402a7d4 100644 --- a/libs/components/forms/src/lib/modules/input-box/input-box.component.html +++ b/libs/components/forms/src/lib/modules/input-box/input-box.component.html @@ -176,6 +176,7 @@ [showErrors]="controlDir?.touched || controlDir?.dirty" > + diff --git a/libs/components/forms/src/lib/modules/input-box/input-box.component.ts b/libs/components/forms/src/lib/modules/input-box/input-box.component.ts index ac67a3b24d..f0c47a4ca6 100644 --- a/libs/components/forms/src/lib/modules/input-box/input-box.component.ts +++ b/libs/components/forms/src/lib/modules/input-box/input-box.component.ts @@ -31,6 +31,8 @@ import { SkyContentInfoProvider, SkyIdService } from '@skyux/core'; import { ReplaySubject } from 'rxjs'; +import { FORM_ERRORS } from '../form-error/form-errors-token'; + import { SkyInputBoxAdapterService } from './input-box-adapter.service'; import { SkyInputBoxControlDirective } from './input-box-control.directive'; import { SkyInputBoxHostService } from './input-box-host.service'; @@ -47,6 +49,10 @@ import { SkyInputBoxPopulateArgs } from './input-box-populate-args'; SkyContentInfoProvider, SkyInputBoxAdapterService, SkyInputBoxHostService, + { + provide: FORM_ERRORS, + useValue: true, + }, ], // Note that change detection is not set to OnPush; default change detection allows the // invalid CSS class to be added when the content control's invalid/dirty state changes. diff --git a/libs/components/forms/src/lib/modules/input-box/input-box.module.ts b/libs/components/forms/src/lib/modules/input-box/input-box.module.ts index a07ab8ddca..768718ea68 100644 --- a/libs/components/forms/src/lib/modules/input-box/input-box.module.ts +++ b/libs/components/forms/src/lib/modules/input-box/input-box.module.ts @@ -3,6 +3,7 @@ import { NgModule } from '@angular/core'; import { SkyThemeModule } from '@skyux/theme'; import { SkyCharacterCounterModule } from '../character-counter/character-counter.module'; +import { SkyFormErrorComponent } from '../form-error/form-error.component'; import { SkyFormErrorsComponent } from '../form-error/form-errors.component'; import { SkyInputBoxControlDirective } from './input-box-control.directive'; @@ -14,11 +15,16 @@ import { SkyInputBoxComponent } from './input-box.component'; imports: [ CommonModule, SkyCharacterCounterModule, + SkyFormErrorComponent, SkyFormErrorsComponent, SkyInputBoxControlDirective, SkyInputBoxHelpInlineComponent, SkyThemeModule, ], - exports: [SkyInputBoxComponent, SkyInputBoxControlDirective], + exports: [ + SkyInputBoxComponent, + SkyInputBoxControlDirective, + SkyFormErrorComponent, + ], }) export class SkyInputBoxModule {} diff --git a/libs/components/forms/testing/src/form-error/form-error-harness.ts b/libs/components/forms/testing/src/form-error/form-error-harness.ts index cc6c5ada58..7dcada5095 100644 --- a/libs/components/forms/testing/src/form-error/form-error-harness.ts +++ b/libs/components/forms/testing/src/form-error/form-error-harness.ts @@ -19,15 +19,10 @@ export class SkyFormErrorHarness extends SkyComponentHarness { return SkyFormErrorHarness.getDataSkyIdPredicate(filters); } - async #getFormErrorClasses(): Promise { - const formErrorClasses = await (await this.host()).getProperty('classList'); - return Array.from(formErrorClasses); - } - /* - * Gets the error class that signifies which error has fired. + * Gets the error name. */ - public async getFirstClassError(): Promise { - return (await this.#getFormErrorClasses())[0]; + public async getErrorName(): Promise { + return (await this.host()).getAttribute('errorName'); } } diff --git a/libs/components/forms/testing/src/form-error/form-errors-harness.spec.ts b/libs/components/forms/testing/src/form-error/form-errors-harness.spec.ts index e7d9e626c6..a7692d5c44 100644 --- a/libs/components/forms/testing/src/form-error/form-errors-harness.spec.ts +++ b/libs/components/forms/testing/src/form-error/form-errors-harness.spec.ts @@ -4,13 +4,23 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ValidationErrors } from '@angular/forms'; // eslint-disable-next-line @nx/enforce-module-boundaries -import { SkyFormErrorsModule } from '@skyux/forms'; +import { + FORM_ERRORS, + SkyFormErrorComponent, + SkyFormErrorsModule, +} from '@skyux/forms'; import { SkyFormErrorsHarness } from './form-errors-harness'; //#region Test component @Component({ selector: 'sky-form-errors-test', + providers: [ + { + provide: FORM_ERRORS, + useValue: true, + }, + ], template: ` { }> { await TestBed.configureTestingModule({ declarations: [TestComponent], - imports: [SkyFormErrorsModule], + imports: [SkyFormErrorsModule, SkyFormErrorComponent], }).compileComponents(); const fixture = TestBed.createComponent(TestComponent); @@ -53,60 +63,28 @@ describe('Form errors harness', () => { dataSkyId: 'other-error', }); + fixture.detectChanges(); fixture.detectChanges(); - await expectAsync(formErrorsHarness.getNumberOfErrors()).toBeResolvedTo(1); - await expectAsync(formErrorsHarness.hasRequiredError()).toBeResolvedTo( + await expectAsync(formErrorsHarness.hasError('required')).toBeResolvedTo( true, ); + await expectAsync(formErrorsHarness.getFormErrors()).toBeResolvedTo([ + { errorName: 'required' }, + ]); }); - it('should get number of errors', async () => { - const { formErrorsHarness, fixture } = await setupTest(); - - fixture.detectChanges(); - - await expectAsync(formErrorsHarness.getNumberOfErrors()).toBeResolvedTo(0); - - fixture.componentInstance.errors = { - required: true, - minlength: true, - }; - fixture.detectChanges(); - - await expectAsync(formErrorsHarness.getNumberOfErrors()).toBeResolvedTo(2); - }); - - it('should return whether first class errors are fired', async () => { + it('should return an array of current errors', async () => { const { formErrorsHarness, fixture } = await setupTest(); fixture.detectChanges(); - await expectAsync(formErrorsHarness.hasRequiredError()).toBeResolvedTo( - false, - ); - await expectAsync(formErrorsHarness.hasMaxLengthError()).toBeResolvedTo( - false, - ); - await expectAsync(formErrorsHarness.hasMinLengthError()).toBeResolvedTo( - false, - ); - await expectAsync( - formErrorsHarness.hasCharacterCountError(), - ).toBeResolvedTo(false); - await expectAsync(formErrorsHarness.hasDateError()).toBeResolvedTo(false); - await expectAsync(formErrorsHarness.hasEmailError()).toBeResolvedTo(false); - await expectAsync(formErrorsHarness.hasPhoneFieldError()).toBeResolvedTo( - false, - ); - await expectAsync(formErrorsHarness.hasTimeError()).toBeResolvedTo(false); - await expectAsync(formErrorsHarness.hasUrlError()).toBeResolvedTo(false); + await expectAsync(formErrorsHarness.getFormErrors()).toBeResolvedTo([]); fixture.componentInstance.errors = { required: true, minlength: true, maxlength: true, - skyCharacterCounter: true, skyDate: true, skyEmail: true, skyPhoneField: true, @@ -115,24 +93,15 @@ describe('Form errors harness', () => { }; fixture.detectChanges(); - await expectAsync(formErrorsHarness.hasRequiredError()).toBeResolvedTo( - true, - ); - await expectAsync(formErrorsHarness.hasMaxLengthError()).toBeResolvedTo( - true, - ); - await expectAsync(formErrorsHarness.hasMinLengthError()).toBeResolvedTo( - true, - ); - await expectAsync( - formErrorsHarness.hasCharacterCountError(), - ).toBeResolvedTo(true); - await expectAsync(formErrorsHarness.hasDateError()).toBeResolvedTo(true); - await expectAsync(formErrorsHarness.hasEmailError()).toBeResolvedTo(true); - await expectAsync(formErrorsHarness.hasPhoneFieldError()).toBeResolvedTo( - true, - ); - await expectAsync(formErrorsHarness.hasTimeError()).toBeResolvedTo(true); - await expectAsync(formErrorsHarness.hasUrlError()).toBeResolvedTo(true); + await expectAsync(formErrorsHarness.getFormErrors()).toBeResolvedTo([ + { errorName: 'required' }, + { errorName: 'maxlength' }, + { errorName: 'minlength' }, + { errorName: 'date' }, + { errorName: 'email' }, + { errorName: 'phone' }, + { errorName: 'time' }, + { errorName: 'url' }, + ]); }); }); diff --git a/libs/components/forms/testing/src/form-error/form-errors-harness.ts b/libs/components/forms/testing/src/form-error/form-errors-harness.ts index 462e5d3575..c72fe0a17e 100644 --- a/libs/components/forms/testing/src/form-error/form-errors-harness.ts +++ b/libs/components/forms/testing/src/form-error/form-errors-harness.ts @@ -10,20 +10,6 @@ export class SkyFormErrorsHarness extends SkyComponentHarness { */ public static hostSelector = 'sky-form-errors'; - #getFormError = this.locatorForAll('sky-form-error'); - - async #getFormErrorsClasses(): Promise { - const formErrorHarnesses = await this.locatorForAll( - SkyFormErrorHarness.with({}), - )(); - - return Promise.all( - formErrorHarnesses.map((formError) => { - return formError.getFirstClassError(); - }), - ); - } - /** * Gets a `HarnessPredicate` that can be used to search for a * `SkyFormErrorsHarness` that meets certain criteria @@ -34,85 +20,28 @@ export class SkyFormErrorsHarness extends SkyComponentHarness { return SkyFormErrorsHarness.getDataSkyIdPredicate(filters); } - /* - * Gets total number of errors. - */ - public async getNumberOfErrors(): Promise { - return (await this.#getFormError()).length; - } - - /* - * Gets if the required error has triggered. - */ - public async hasRequiredError(): Promise { - return (await this.#getFormErrorsClasses()).includes( - 'sky-form-error-required', - ); - } - - /* - * Gets if the maximum length error has triggered. - */ - public async hasMaxLengthError(): Promise { - return (await this.#getFormErrorsClasses()).includes( - 'sky-form-error-maxlength', - ); - } - - /* - * Gets if the minimum length has triggered. - */ - public async hasMinLengthError(): Promise { - return (await this.#getFormErrorsClasses()).includes( - 'sky-form-error-minlength', - ); - } - - /* - * Gets if the character count error has triggered. - */ - public async hasCharacterCountError(): Promise { - return (await this.#getFormErrorsClasses()).includes( - 'sky-form-error-character-counter', - ); - } - - /* - * Gets if the date error has triggered. - */ - public async hasDateError(): Promise { - return (await this.#getFormErrorsClasses()).includes('sky-form-error-date'); - } - - /* - * Gets if the email error has triggered. + /** + * Gets an array of all errors fired. */ - public async hasEmailError(): Promise { - return (await this.#getFormErrorsClasses()).includes( - 'sky-form-error-email', - ); - } + public async getFormErrors(): Promise<{ errorName: string | null }[]> { + const formErrorHarnesses = await this.locatorForAll( + SkyFormErrorHarness.with({}), + )(); - /* - * Gets if the phone field error has triggered. - */ - public async hasPhoneFieldError(): Promise { - return (await this.#getFormErrorsClasses()).includes( - 'sky-form-error-phone', + return Promise.all( + formErrorHarnesses.map(async (formError) => { + return { errorName: await formError.getErrorName() }; + }), ); } - /* - * Gets if the time field error has triggered. - */ - public async hasTimeError(): Promise { - return (await this.#getFormErrorsClasses()).includes('sky-form-error-time'); - } - - /* - * Gets if the URL error has triggered. + /** + * Whether an error with the given name has fired. */ - public async hasUrlError(): Promise { - return (await this.#getFormErrorsClasses()).includes('sky-form-error-url'); + public async hasError(errorName: string): Promise { + const formErrors = await this.getFormErrors(); + return !!formErrors.find((error) => { + return error.errorName === errorName; + }); } } diff --git a/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.html b/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.html index 9419510535..e8e5bf744e 100644 --- a/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.html +++ b/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.html @@ -40,4 +40,53 @@
+
+ + + + + + + + + + + + + + + + + + + + + This is a customer error + +
+ Help content from template diff --git a/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.ts b/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.ts index baa02a6c51..3f9b9beaa7 100644 --- a/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.ts +++ b/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.ts @@ -11,6 +11,7 @@ import { }) export class InputBoxHarnessTestComponent { public myForm: UntypedFormGroup; + public directiveErrorForm: UntypedFormGroup; @ViewChild('helpContentTemplate', { read: TemplateRef, @@ -32,5 +33,10 @@ export class InputBoxHarnessTestComponent { firstName: new UntypedFormControl('John'), lastName: new UntypedFormControl('Doe'), }); + this.directiveErrorForm = formBuilder.group({ + easyModeDatepicker: new UntypedFormControl('123'), + easyModeTimepicker: new UntypedFormControl('abc'), + easyModePhoneField: new UntypedFormControl('abc'), + }); } } diff --git a/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.module.ts b/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.module.ts index 26b4933f3d..08ca311bf2 100644 --- a/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.module.ts +++ b/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.module.ts @@ -1,8 +1,10 @@ import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { SkyIdModule } from '@skyux/core'; +import { SkyDatepickerModule, SkyTimepickerModule } from '@skyux/datetime'; import { SkyInputBoxModule } from '@skyux/forms'; import { SkyStatusIndicatorModule } from '@skyux/indicators'; +import { SkyPhoneFieldModule } from '@skyux/phone-field'; import { InputBoxHarnessTestComponent } from './input-box-harness-test.component'; @@ -13,6 +15,9 @@ import { InputBoxHarnessTestComponent } from './input-box-harness-test.component SkyIdModule, SkyInputBoxModule, SkyStatusIndicatorModule, + SkyDatepickerModule, + SkyTimepickerModule, + SkyPhoneFieldModule, ], declarations: [InputBoxHarnessTestComponent], }) diff --git a/libs/components/forms/testing/src/input-box/input-box-harness.spec.ts b/libs/components/forms/testing/src/input-box/input-box-harness.spec.ts index b349563143..8539749f63 100644 --- a/libs/components/forms/testing/src/input-box/input-box-harness.spec.ts +++ b/libs/components/forms/testing/src/input-box/input-box-harness.spec.ts @@ -2,6 +2,7 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Validators } from '@angular/forms'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { SkyValidators } from '@skyux/validation'; import { InputBoxHarnessTestComponent } from './fixtures/input-box-harness-test.component'; import { InputBoxHarnessTestModule } from './fixtures/input-box-harness-test.module'; @@ -138,6 +139,127 @@ describe('Input box harness', () => { await expectAsync(customError.getText()).toBeResolvedTo('Test error'); }); + it('should return whether custom form error has fired', async () => { + const { inputBoxHarness } = await setupTest({ + dataSkyId: 'custom-error-easy-mode', + }); + + await expectAsync( + inputBoxHarness.hasCustomFormError('custom'), + ).toBeResolvedTo(true); + }); + + it('should return whether required error has fired', async () => { + const { component, fixture, inputBoxHarness } = await setupTest({ + dataSkyId: 'my-input-box-last-name-easy-mode', + }); + + const control = component.myForm.controls['lastName']; + control.addValidators(Validators.required); + control.setValue(''); + control.markAsDirty(); + + fixture.detectChanges(); + + await expectAsync(inputBoxHarness.hasRequiredError()).toBeResolvedTo(true); + }); + + it('should return whether minimum length error has fired', async () => { + const { component, fixture, inputBoxHarness } = await setupTest({ + dataSkyId: 'my-input-box-last-name-easy-mode', + }); + + const control = component.myForm.controls['lastName']; + control.addValidators(Validators.minLength(2)); + control.setValue('a'); + control.markAsDirty(); + + fixture.detectChanges(); + + await expectAsync(inputBoxHarness.hasMinLengthError()).toBeResolvedTo(true); + }); + + it('should return whether maximum length error has fired', async () => { + const { component, fixture, inputBoxHarness } = await setupTest({ + dataSkyId: 'my-input-box-last-name-easy-mode', + }); + + const control = component.myForm.controls['lastName']; + control.addValidators(Validators.maxLength(1)); + control.setValue('abc'); + control.markAsDirty(); + + fixture.detectChanges(); + + await expectAsync(inputBoxHarness.hasMaxLengthError()).toBeResolvedTo(true); + }); + + it('should return whether email validator error has fired', async () => { + const { component, fixture, inputBoxHarness } = await setupTest({ + dataSkyId: 'my-input-box-last-name-easy-mode', + }); + + const control = component.myForm.controls['lastName']; + control.addValidators(SkyValidators.email); + control.setValue('abc'); + control.markAsDirty(); + + fixture.detectChanges(); + + await expectAsync(inputBoxHarness.hasEmailError()).toBeResolvedTo(true); + }); + + it('should return whether url validator error has fired', async () => { + const { component, fixture, inputBoxHarness } = await setupTest({ + dataSkyId: 'my-input-box-last-name-easy-mode', + }); + + const control = component.myForm.controls['lastName']; + control.addValidators(SkyValidators.url); + control.setValue('abc'); + control.markAsDirty(); + + fixture.detectChanges(); + + await expectAsync(inputBoxHarness.hasUrlError()).toBeResolvedTo(true); + }); + + it('should return whether date picker validator error has fired', async () => { + const { fixture, inputBoxHarness } = await setupTest({ + dataSkyId: 'datepicker-easy-mode', + }); + + fixture.detectChanges(); + + await expectAsync(inputBoxHarness.hasDateError()).toBeResolvedTo(true); + }); + + it('should return whether time picker validator error has fired', async () => { + const { component, fixture, inputBoxHarness } = await setupTest({ + dataSkyId: 'timepicker-easy-mode', + }); + + const control = component.directiveErrorForm.controls['easyModeTimepicker']; + control.markAsDirty(); + fixture.detectChanges(); + + await expectAsync(inputBoxHarness.hasTimeError()).toBeResolvedTo(true); + }); + + it('should return whether phone field validator error has fired', async () => { + const { component, fixture, inputBoxHarness } = await setupTest({ + dataSkyId: 'phone-field-easy-mode', + }); + + const control = component.directiveErrorForm.controls['easyModePhoneField']; + control.markAsDirty(); + fixture.detectChanges(); + + await expectAsync(inputBoxHarness.hasPhoneFieldError()).toBeResolvedTo( + true, + ); + }); + it('should return character counter indicator', async () => { const { component, fixture, inputBoxHarness } = await setupTest({ dataSkyId: DATA_SKY_ID_EASY_MODE, diff --git a/libs/components/forms/testing/src/input-box/input-box-harness.ts b/libs/components/forms/testing/src/input-box/input-box-harness.ts index 01aefb6fcc..dc00ac57c8 100644 --- a/libs/components/forms/testing/src/input-box/input-box-harness.ts +++ b/libs/components/forms/testing/src/input-box/input-box-harness.ts @@ -9,6 +9,7 @@ import { SkyStatusIndicatorHarness } from '@skyux/indicators/testing'; import { SkyPopoverHarness } from '@skyux/popovers/testing'; import { SkyCharacterCounterIndicatorHarness } from '../character-counter/character-counter-indicator-harness'; +import { SkyFormErrorsHarness } from '../public-api'; import { SkyInputBoxHarnessFilters } from './input-box-harness-filters'; @@ -25,6 +26,10 @@ export class SkyInputBoxHarness extends SkyComponentHarness { #getLabel = this.locatorForOptional('.sky-control-label'); #getWrapper = this.locatorFor('.sky-input-box'); + async #getFormError(): Promise { + return this.locatorFor(SkyFormErrorsHarness)(); + } + /** * Gets a `HarnessPredicate` that can be used to search for a * `SkyInputBoxHarness` that meets certain criteria. @@ -79,6 +84,69 @@ export class SkyInputBoxHarness extends SkyComponentHarness { return errors; } + /** + * Whether the custom error is triggered. + */ + public async hasCustomFormError(errorName: string): Promise { + return (await this.#getFormError()).hasError(errorName); + } + + /** + * Whether the required field is empty. + */ + public async hasRequiredError(): Promise { + return (await this.#getFormError()).hasError('required'); + } + + /** + * Whether the field has more characters than allowed. + */ + public async hasMaxLengthError(): Promise { + return (await this.#getFormError()).hasError('maxlength'); + } + + /** + * Whether the field has fewer characters than allowed. + */ + public async hasMinLengthError(): Promise { + return (await this.#getFormError()).hasError('minlength'); + } + + /* + * Whether the field is set to an invalid email address. + */ + public async hasEmailError(): Promise { + return (await this.#getFormError()).hasError('email'); + } + + /* + * Whether the field is set to an invalid URL. + */ + public async hasUrlError(): Promise { + return (await this.#getFormError()).hasError('url'); + } + + /* + * Whether the field is set to an invalid date. + */ + public async hasDateError(): Promise { + return (await this.#getFormError()).hasError('date'); + } + + /* + * Whether the field is set to an invalid phone number. + */ + public async hasPhoneFieldError(): Promise { + return (await this.#getFormError()).hasError('phone'); + } + + /* + * Whether the field is set to an invalid time. + */ + public async hasTimeError(): Promise { + return (await this.#getFormError()).hasError('time'); + } + /** * Indicates whether the input box has disabled styles applied. */ From bda3d36eb01ff09f3783a747d17f634a488d421f Mon Sep 17 00:00:00 2001 From: Erika McVey <50454925+Blackbaud-ErikaMcVey@users.noreply.github.com> Date: Mon, 5 Feb 2024 09:57:43 -0500 Subject: [PATCH 2/2] address PR feedback --- .../forms/input-box/basic/demo.component.html | 11 ++-- .../input-box/basic/demo.component.spec.ts | 6 +- .../forms/input-box/basic/demo.component.ts | 4 +- .../forms/input-box/input-box.component.html | 8 ++- libs/components/forms/src/index.ts | 5 +- .../form-error/form-error.component.spec.ts | 46 ++++++++++++++ .../form-error/form-error.component.ts | 45 +++++++------- .../modules/form-error/form-error.module.ts | 9 +++ .../form-error/form-errors-enabled-token.ts | 8 +++ .../modules/form-error/form-errors-token.ts | 3 - .../form-error/form-errors.component.html | 62 +++++++++++-------- .../modules/form-error/form-errors.module.ts | 3 +- .../input-box/input-box.component.html | 3 +- .../modules/input-box/input-box.component.ts | 4 +- .../lib/modules/input-box/input-box.module.ts | 10 +-- .../src/form-error/form-error-harness.ts | 2 +- .../form-error/form-errors-harness.spec.ts | 8 +-- .../src/form-error/form-errors-harness.ts | 4 +- .../input-box-harness-test.component.html | 2 +- .../src/input-box/input-box-harness.ts | 2 +- 20 files changed, 158 insertions(+), 87 deletions(-) create mode 100644 libs/components/forms/src/lib/modules/form-error/form-error.component.spec.ts create mode 100644 libs/components/forms/src/lib/modules/form-error/form-error.module.ts create mode 100644 libs/components/forms/src/lib/modules/form-error/form-errors-enabled-token.ts delete mode 100644 libs/components/forms/src/lib/modules/form-error/form-errors-token.ts diff --git a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.html b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.html index 46842d9304..66fe5b1cdb 100644 --- a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.html +++ b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.html @@ -78,15 +78,14 @@

New member form

- + - Blur is not a color. - + *ngIf="favoriteColor.errors?.['invalid']" + errorName="invalid" + errorText="Invalid Color is not a color" + /> diff --git a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.spec.ts index a6690a2409..ba0cf2f438 100644 --- a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.spec.ts @@ -88,7 +88,7 @@ describe('Basic input box demo', () => { }); describe('favorite color field', () => { - it('should not allow blur to be selected', async () => { + it('should not allow invalid color to be selected', async () => { const harness = await setupTest({ dataSkyId: 'input-box-favorite-color', }); @@ -97,10 +97,10 @@ describe('Basic input box demo', () => { '.input-box-favorite-color-select', ) as HTMLSelectElement; - selectEl.value = 'blur'; + selectEl.value = 'invalid'; selectEl.dispatchEvent(new Event('change')); - await expectAsync(harness.hasCustomFormError('color')).toBeResolvedTo( + await expectAsync(harness.hasCustomFormError('invalid')).toBeResolvedTo( true, ); }); diff --git a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.ts b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.ts index 17dbd1c267..3529ee4acc 100644 --- a/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/forms/input-box/basic/demo.component.ts @@ -44,8 +44,8 @@ export class DemoComponent { constructor() { this.favoriteColor = new FormControl('none', [ (control): ValidationErrors | null => { - if (control.value === 'blur') { - return { color: true }; + if (control.value === 'invalid') { + return { invalid: true }; } return null; diff --git a/apps/playground/src/app/components/forms/input-box/input-box.component.html b/apps/playground/src/app/components/forms/input-box/input-box.component.html index 2a5f1e10e7..413f6eb57d 100644 --- a/apps/playground/src/app/components/forms/input-box/input-box.component.html +++ b/apps/playground/src/app/components/forms/input-box/input-box.component.html @@ -251,9 +251,11 @@ hintText="type in blue" > - - Input must be blue. - + + `, +}) +class FormErrorWithTokenComponent {} + +@Component({ + standalone: true, + imports: [SkyFormErrorsModule, SkyFormErrorModule], + template: ` + + `, +}) +class FormErrorWithoutTokenComponent {} + +describe('Form error component', () => { + it('renders an error message when form errors enabled token is provided', () => { + const fixture = TestBed.createComponent(FormErrorWithTokenComponent); + + fixture.detectChanges(); + + expect( + fixture.nativeElement.querySelector('.sky-form-error'), + ).toBeVisible(); + }); + + it('throws an error when form errors enabled token is not provided', () => { + expect(() => + TestBed.createComponent(FormErrorWithoutTokenComponent), + ).toThrowError( + 'The `sky-form-error` component is not supported in the provided context.', + ); + }); +}); diff --git a/libs/components/forms/src/lib/modules/form-error/form-error.component.ts b/libs/components/forms/src/lib/modules/form-error/form-error.component.ts index 679f12e147..6773084805 100644 --- a/libs/components/forms/src/lib/modules/form-error/form-error.component.ts +++ b/libs/components/forms/src/lib/modules/form-error/form-error.component.ts @@ -1,18 +1,16 @@ import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, - ChangeDetectorRef, Component, - HostBinding, Input, inject, } from '@angular/core'; import { SkyStatusIndicatorModule } from '@skyux/indicators'; -import { FORM_ERRORS } from './form-errors-token'; +import { SKY_FORM_ERRORS_ENABLED } from './form-errors-enabled-token'; /** - * @internal + * Displays default and custom input error messages for SKY UX form components. */ @Component({ selector: 'sky-form-error', @@ -25,7 +23,7 @@ import { FORM_ERRORS } from './form-errors-token'; descriptionType="error" indicatorType="danger" > - + {{ errorText }} `, styles: [ @@ -39,26 +37,27 @@ import { FORM_ERRORS } from './form-errors-token'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class SkyFormErrorComponent { - @Input() - public set errorName(value: string) { - this.#_errorName = value; - this.#updateClasses(); - } - - public get errorName(): string { - return this.#_errorName; - } - - @HostBinding('class') - protected cssClass = ''; + /** + * The name of the error. + */ + @Input({ required: true }) + public errorName!: string; - #_errorName = ''; + /** + * The error message to display. + */ + @Input({ required: true }) + public errorText!: string; - protected readonly formErrors = inject(FORM_ERRORS, { optional: true }); - readonly #changeDetector = inject(ChangeDetectorRef); + protected readonly formErrors = inject(SKY_FORM_ERRORS_ENABLED, { + optional: true, + }); - #updateClasses(): void { - this.cssClass = `sky-form-error-${this.errorName} sky-form-error-indicator`; - this.#changeDetector.markForCheck(); + constructor() { + if (!this.formErrors) { + throw new Error( + 'The `sky-form-error` component is not supported in the provided context.', + ); + } } } diff --git a/libs/components/forms/src/lib/modules/form-error/form-error.module.ts b/libs/components/forms/src/lib/modules/form-error/form-error.module.ts new file mode 100644 index 0000000000..0224e3456f --- /dev/null +++ b/libs/components/forms/src/lib/modules/form-error/form-error.module.ts @@ -0,0 +1,9 @@ +import { NgModule } from '@angular/core'; + +import { SkyFormErrorComponent } from './form-error.component'; + +@NgModule({ + imports: [SkyFormErrorComponent], + exports: [SkyFormErrorComponent], +}) +export class SkyFormErrorModule {} diff --git a/libs/components/forms/src/lib/modules/form-error/form-errors-enabled-token.ts b/libs/components/forms/src/lib/modules/form-error/form-errors-enabled-token.ts new file mode 100644 index 0000000000..33ab025185 --- /dev/null +++ b/libs/components/forms/src/lib/modules/form-error/form-errors-enabled-token.ts @@ -0,0 +1,8 @@ +import { InjectionToken } from '@angular/core'; + +/** + * @internal + */ +export const SKY_FORM_ERRORS_ENABLED = new InjectionToken( + 'SKY_FORM_ERRORS_ENABLED', +); diff --git a/libs/components/forms/src/lib/modules/form-error/form-errors-token.ts b/libs/components/forms/src/lib/modules/form-error/form-errors-token.ts deleted file mode 100644 index 8cde04f9be..0000000000 --- a/libs/components/forms/src/lib/modules/form-error/form-errors-token.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { InjectionToken } from '@angular/core'; - -export const FORM_ERRORS = new InjectionToken('FORM_ERRORS'); diff --git a/libs/components/forms/src/lib/modules/form-error/form-errors.component.html b/libs/components/forms/src/lib/modules/form-error/form-errors.component.html index 850a0bda11..365cb38250 100644 --- a/libs/components/forms/src/lib/modules/form-error/form-errors.component.html +++ b/libs/components/forms/src/lib/modules/form-error/form-errors.component.html @@ -1,46 +1,56 @@ - - {{ 'skyux_form_error_required' | skyLibResources : labelText }} - + - {{ + [errorText]=" 'skyux_form_error_maxlength' | skyLibResources : labelText : maxLengthError.requiredLength - }} - + " + /> - {{ + [errorText]=" 'skyux_form_error_minlength' | skyLibResources : labelText : minLengthError.requiredLength - }} - + " + /> - - {{ 'skyux_form_error_date' | skyLibResources }} - + - - {{ 'skyux_form_error_email' | skyLibResources }} - + - - {{ 'skyux_form_error_phone' | skyLibResources }} - + - - {{ 'skyux_form_error_time' | skyLibResources }} - + - - {{ 'skyux_form_error_url' | skyLibResources }} - + diff --git a/libs/components/forms/src/lib/modules/form-error/form-errors.module.ts b/libs/components/forms/src/lib/modules/form-error/form-errors.module.ts index 1f4ec9af83..8dcdd053c6 100644 --- a/libs/components/forms/src/lib/modules/form-error/form-errors.module.ts +++ b/libs/components/forms/src/lib/modules/form-error/form-errors.module.ts @@ -1,12 +1,13 @@ import { NgModule } from '@angular/core'; +import { SkyFormErrorComponent } from './form-error.component'; import { SkyFormErrorsComponent } from './form-errors.component'; /** * @internal */ @NgModule({ - imports: [SkyFormErrorsComponent], + imports: [SkyFormErrorsComponent, SkyFormErrorComponent], exports: [SkyFormErrorsComponent], }) export class SkyFormErrorsModule {} diff --git a/libs/components/forms/src/lib/modules/input-box/input-box.component.html b/libs/components/forms/src/lib/modules/input-box/input-box.component.html index 633402a7d4..8f0f00991e 100644 --- a/libs/components/forms/src/lib/modules/input-box/input-box.component.html +++ b/libs/components/forms/src/lib/modules/input-box/input-box.component.html @@ -175,8 +175,7 @@ [labelText]="labelText" [showErrors]="controlDir?.touched || controlDir?.dirty" > - - + diff --git a/libs/components/forms/src/lib/modules/input-box/input-box.component.ts b/libs/components/forms/src/lib/modules/input-box/input-box.component.ts index f0c47a4ca6..b0752d4391 100644 --- a/libs/components/forms/src/lib/modules/input-box/input-box.component.ts +++ b/libs/components/forms/src/lib/modules/input-box/input-box.component.ts @@ -31,7 +31,7 @@ import { SkyContentInfoProvider, SkyIdService } from '@skyux/core'; import { ReplaySubject } from 'rxjs'; -import { FORM_ERRORS } from '../form-error/form-errors-token'; +import { SKY_FORM_ERRORS_ENABLED } from '../form-error/form-errors-enabled-token'; import { SkyInputBoxAdapterService } from './input-box-adapter.service'; import { SkyInputBoxControlDirective } from './input-box-control.directive'; @@ -50,7 +50,7 @@ import { SkyInputBoxPopulateArgs } from './input-box-populate-args'; SkyInputBoxAdapterService, SkyInputBoxHostService, { - provide: FORM_ERRORS, + provide: SKY_FORM_ERRORS_ENABLED, useValue: true, }, ], diff --git a/libs/components/forms/src/lib/modules/input-box/input-box.module.ts b/libs/components/forms/src/lib/modules/input-box/input-box.module.ts index 768718ea68..60735b390d 100644 --- a/libs/components/forms/src/lib/modules/input-box/input-box.module.ts +++ b/libs/components/forms/src/lib/modules/input-box/input-box.module.ts @@ -3,8 +3,8 @@ import { NgModule } from '@angular/core'; import { SkyThemeModule } from '@skyux/theme'; import { SkyCharacterCounterModule } from '../character-counter/character-counter.module'; -import { SkyFormErrorComponent } from '../form-error/form-error.component'; -import { SkyFormErrorsComponent } from '../form-error/form-errors.component'; +import { SkyFormErrorModule } from '../form-error/form-error.module'; +import { SkyFormErrorsModule } from '../form-error/form-errors.module'; import { SkyInputBoxControlDirective } from './input-box-control.directive'; import { SkyInputBoxHelpInlineComponent } from './input-box-help-inline.component'; @@ -15,8 +15,8 @@ import { SkyInputBoxComponent } from './input-box.component'; imports: [ CommonModule, SkyCharacterCounterModule, - SkyFormErrorComponent, - SkyFormErrorsComponent, + SkyFormErrorsModule, + SkyFormErrorModule, SkyInputBoxControlDirective, SkyInputBoxHelpInlineComponent, SkyThemeModule, @@ -24,7 +24,7 @@ import { SkyInputBoxComponent } from './input-box.component'; exports: [ SkyInputBoxComponent, SkyInputBoxControlDirective, - SkyFormErrorComponent, + SkyFormErrorModule, ], }) export class SkyInputBoxModule {} diff --git a/libs/components/forms/testing/src/form-error/form-error-harness.ts b/libs/components/forms/testing/src/form-error/form-error-harness.ts index 7dcada5095..bcbd4d1a8a 100644 --- a/libs/components/forms/testing/src/form-error/form-error-harness.ts +++ b/libs/components/forms/testing/src/form-error/form-error-harness.ts @@ -19,7 +19,7 @@ export class SkyFormErrorHarness extends SkyComponentHarness { return SkyFormErrorHarness.getDataSkyIdPredicate(filters); } - /* + /** * Gets the error name. */ public async getErrorName(): Promise { diff --git a/libs/components/forms/testing/src/form-error/form-errors-harness.spec.ts b/libs/components/forms/testing/src/form-error/form-errors-harness.spec.ts index a7692d5c44..48353abe3f 100644 --- a/libs/components/forms/testing/src/form-error/form-errors-harness.spec.ts +++ b/libs/components/forms/testing/src/form-error/form-errors-harness.spec.ts @@ -5,8 +5,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ValidationErrors } from '@angular/forms'; // eslint-disable-next-line @nx/enforce-module-boundaries import { - FORM_ERRORS, - SkyFormErrorComponent, + SKY_FORM_ERRORS_ENABLED, + SkyFormErrorModule, SkyFormErrorsModule, } from '@skyux/forms'; @@ -17,7 +17,7 @@ import { SkyFormErrorsHarness } from './form-errors-harness'; selector: 'sky-form-errors-test', providers: [ { - provide: FORM_ERRORS, + provide: SKY_FORM_ERRORS_ENABLED, useValue: true, }, ], @@ -43,7 +43,7 @@ describe('Form errors harness', () => { }> { await TestBed.configureTestingModule({ declarations: [TestComponent], - imports: [SkyFormErrorsModule, SkyFormErrorComponent], + imports: [SkyFormErrorsModule, SkyFormErrorModule], }).compileComponents(); const fixture = TestBed.createComponent(TestComponent); diff --git a/libs/components/forms/testing/src/form-error/form-errors-harness.ts b/libs/components/forms/testing/src/form-error/form-errors-harness.ts index c72fe0a17e..6411541317 100644 --- a/libs/components/forms/testing/src/form-error/form-errors-harness.ts +++ b/libs/components/forms/testing/src/form-error/form-errors-harness.ts @@ -21,7 +21,7 @@ export class SkyFormErrorsHarness extends SkyComponentHarness { } /** - * Gets an array of all errors fired. + * Gets a list of all errors fired. */ public async getFormErrors(): Promise<{ errorName: string | null }[]> { const formErrorHarnesses = await this.locatorForAll( @@ -40,7 +40,7 @@ export class SkyFormErrorsHarness extends SkyComponentHarness { */ public async hasError(errorName: string): Promise { const formErrors = await this.getFormErrors(); - return !!formErrors.find((error) => { + return formErrors.some((error) => { return error.errorName === errorName; }); } diff --git a/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.html b/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.html index e8e5bf744e..a1fff97fec 100644 --- a/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.html +++ b/libs/components/forms/testing/src/input-box/fixtures/input-box-harness-test.component.html @@ -85,7 +85,7 @@ labelText="easyModeCustomError" > - This is a customer error + diff --git a/libs/components/forms/testing/src/input-box/input-box-harness.ts b/libs/components/forms/testing/src/input-box/input-box-harness.ts index dc00ac57c8..9288756e5f 100644 --- a/libs/components/forms/testing/src/input-box/input-box-harness.ts +++ b/libs/components/forms/testing/src/input-box/input-box-harness.ts @@ -9,7 +9,7 @@ import { SkyStatusIndicatorHarness } from '@skyux/indicators/testing'; import { SkyPopoverHarness } from '@skyux/popovers/testing'; import { SkyCharacterCounterIndicatorHarness } from '../character-counter/character-counter-indicator-harness'; -import { SkyFormErrorsHarness } from '../public-api'; +import { SkyFormErrorsHarness } from '../form-error/form-errors-harness'; import { SkyInputBoxHarnessFilters } from './input-box-harness-filters';