Skip to content

fix(material/form-field): handle datepicker inputs in harness #22403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('FormFieldHarnessExample', () => {
expect(await formField.getTextHints()).toEqual(['Hint']);

fixture.componentInstance.requiredControl.setValue('');
await (await formField.getControl())?.blur();
await ((await formField.getControl() as MatInputHarness))?.blur();
expect(await formField.getTextErrors()).toEqual(['Error']);
expect(await formField.getTextHints()).toEqual([]);
});
Expand Down
4 changes: 4 additions & 0 deletions src/material-experimental/mdc-form-field/testing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ts_library(
"//src/cdk/testing",
"//src/material-experimental/mdc-input/testing",
"//src/material-experimental/mdc-select/testing",
"//src/material/datepicker/testing",
"//src/material/form-field/testing",
"//src/material/form-field/testing/control",
],
Expand All @@ -32,11 +33,14 @@ ng_test_library(
deps = [
":testing",
"//src/material-experimental/mdc-autocomplete",
"//src/material-experimental/mdc-core",
"//src/material-experimental/mdc-form-field",
"//src/material-experimental/mdc-input",
"//src/material-experimental/mdc-input/testing",
"//src/material-experimental/mdc-select",
"//src/material-experimental/mdc-select/testing",
"//src/material/datepicker",
"//src/material/datepicker/testing",
"//src/material/form-field/testing:harness_tests_lib",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,29 @@ import {MatInputHarness} from '@angular/material-experimental/mdc-input/testing'
import {MatSelectModule} from '@angular/material-experimental/mdc-select';
import {MatSelectHarness} from '@angular/material-experimental/mdc-select/testing';
import {runHarnessTests} from '@angular/material/form-field/testing/shared.spec';
import {MatDatepickerModule} from '@angular/material/datepicker';
import {MatNativeDateModule} from '@angular/material-experimental/mdc-core';
import {
MatDatepickerInputHarness,
MatDateRangeInputHarness,
} from '@angular/material/datepicker/testing';
import {MatFormFieldHarness} from './form-field-harness';

describe('MDC-based MatFormFieldHarness', () => {
runHarnessTests(
[MatFormFieldModule, MatAutocompleteModule, MatInputModule, MatSelectModule], {
[
MatFormFieldModule,
MatAutocompleteModule,
MatInputModule,
MatSelectModule,
MatNativeDateModule,
MatDatepickerModule
], {
formFieldHarness: MatFormFieldHarness as any,
inputHarness: MatInputHarness,
selectHarness: MatSelectHarness,
datepickerInputHarness: MatDatepickerInputHarness,
dateRangeInputHarness: MatDateRangeInputHarness,
isMdcImplementation: true,
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ import {
} from '@angular/material/form-field/testing';
import {MatInputHarness} from '@angular/material-experimental/mdc-input/testing';
import {MatSelectHarness} from '@angular/material-experimental/mdc-select/testing';
import {
MatDatepickerInputHarness,
MatDateRangeInputHarness,
} from '@angular/material/datepicker/testing';

// TODO(devversion): support datepicker harness once developed (COMP-203).
// Also support chip list harness.
// TODO(devversion): support support chip list harness
/** Possible harnesses of controls which can be bound to a form-field. */
export type FormFieldControlHarness = MatInputHarness|MatSelectHarness;
export type FormFieldControlHarness =
MatInputHarness|MatSelectHarness|MatDatepickerInputHarness|MatDateRangeInputHarness;

/** Harness for interacting with a MDC-based form-field's in tests. */
export class MatFormFieldHarness extends _MatFormFieldHarnessBase<FormFieldControlHarness> {
Expand All @@ -44,6 +48,8 @@ export class MatFormFieldHarness extends _MatFormFieldHarnessBase<FormFieldContr
protected _hints = this.locatorForAll('.mat-mdc-form-field-hint');
protected _inputControl = this.locatorForOptional(MatInputHarness);
protected _selectControl = this.locatorForOptional(MatSelectHarness);
protected _datepickerInputControl = this.locatorForOptional(MatDatepickerInputHarness);
protected _dateRangeInputControl = this.locatorForOptional(MatDateRangeInputHarness);
private _mdcTextField = this.locatorFor('.mat-mdc-text-field-wrapper');

/** Gets the appearance of the form-field. */
Expand Down
1 change: 1 addition & 0 deletions src/material/datepicker/testing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ ts_library(
deps = [
"//src/cdk/coercion",
"//src/cdk/testing",
"//src/material/form-field/testing/control",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import {
ComponentHarnessConstructor,
HarnessPredicate,
ComponentHarness,
} from '@angular/cdk/testing';
import {MatFormFieldControlHarness} from '@angular/material/form-field/testing/control';
import {DatepickerInputHarnessFilters} from './datepicker-harness-filters';

/** Sets up the filter predicates for a datepicker input harness. */
Expand All @@ -28,7 +28,7 @@ export function getInputPredicate<T extends MatDatepickerInputHarnessBase>(
}

/** Base class for datepicker input harnesses. */
export abstract class MatDatepickerInputHarnessBase extends ComponentHarness {
export abstract class MatDatepickerInputHarnessBase extends MatFormFieldControlHarness {
/** Whether the input is disabled. */
async isDisabled(): Promise<boolean> {
return (await this.host()).getProperty('disabled')!;
Expand Down
4 changes: 4 additions & 0 deletions src/material/form-field/testing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ ts_library(
module_name = "@angular/material/form-field/testing",
deps = [
"//src/cdk/testing",
"//src/material/datepicker/testing",
"//src/material/form-field/testing/control",
"//src/material/input/testing",
"//src/material/select/testing",
Expand Down Expand Up @@ -45,6 +46,9 @@ ng_test_library(
":harness_tests_lib",
":testing",
"//src/material/autocomplete",
"//src/material/core",
"//src/material/datepicker",
"//src/material/datepicker/testing",
"//src/material/form-field",
"//src/material/input",
"//src/material/input/testing",
Expand Down
17 changes: 16 additions & 1 deletion src/material/form-field/testing/form-field-harness.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import {MatAutocompleteModule} from '@angular/material/autocomplete';
import {MatNativeDateModule} from '@angular/material/core';
import {MatDatepickerModule} from '@angular/material/datepicker';
import {
MatDatepickerInputHarness,
MatDateRangeInputHarness,
} from '@angular/material/datepicker/testing';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatInputModule} from '@angular/material/input';
import {MatInputHarness} from '@angular/material/input/testing';
Expand All @@ -9,10 +15,19 @@ import {MatFormFieldHarness} from './form-field-harness';
import {runHarnessTests} from './shared.spec';

describe('Non-MDC-based MatFormFieldHarness', () => {
runHarnessTests([MatFormFieldModule, MatAutocompleteModule, MatInputModule, MatSelectModule], {
runHarnessTests([
MatFormFieldModule,
MatAutocompleteModule,
MatInputModule,
MatSelectModule,
MatNativeDateModule,
MatDatepickerModule,
], {
formFieldHarness: MatFormFieldHarness,
inputHarness: MatInputHarness,
selectHarness: MatSelectHarness,
datepickerInputHarness: MatDatepickerInputHarness,
dateRangeInputHarness: MatDateRangeInputHarness,
isMdcImplementation: false,
});
});
25 changes: 20 additions & 5 deletions src/material/form-field/testing/form-field-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ import {
parallel,
TestElement
} from '@angular/cdk/testing';
import {
MatDatepickerInputHarness,
MatDateRangeInputHarness,
} from '@angular/material/datepicker/testing';
import {MatFormFieldControlHarness} from '@angular/material/form-field/testing/control';
import {MatInputHarness} from '@angular/material/input/testing';
import {MatSelectHarness} from '@angular/material/select/testing';
import {FormFieldHarnessFilters} from './form-field-harness-filters';

// TODO(devversion): support datepicker harness once developed (COMP-203).
// Also support chip list harness.
// TODO(devversion): support support chip list harness
/** Possible harnesses of controls which can be bound to a form-field. */
export type FormFieldControlHarness = MatInputHarness|MatSelectHarness;
export type FormFieldControlHarness =
MatInputHarness|MatSelectHarness|MatDatepickerInputHarness|MatDateRangeInputHarness;

export abstract class _MatFormFieldHarnessBase<ControlHarness extends MatFormFieldControlHarness>
extends ComponentHarness {
Expand All @@ -34,6 +38,8 @@ export abstract class _MatFormFieldHarnessBase<ControlHarness extends MatFormFie
protected abstract _hints: AsyncFactoryFn<TestElement[]>;
protected abstract _inputControl: AsyncFactoryFn<ControlHarness|null>;
protected abstract _selectControl: AsyncFactoryFn<ControlHarness|null>;
protected abstract _datepickerInputControl: AsyncFactoryFn<ControlHarness|null>;
protected abstract _dateRangeInputControl: AsyncFactoryFn<ControlHarness|null>;

/** Gets the appearance of the form-field. */
abstract getAppearance(): Promise<string>;
Expand Down Expand Up @@ -91,8 +97,15 @@ export abstract class _MatFormFieldHarnessBase<ControlHarness extends MatFormFie
if (type) {
return this.locatorForOptional(type)();
}
const [select, input] = await parallel(() => [this._selectControl(), this._inputControl()]);
return select || input;
const [select, input, datepickerInput, dateRangeInput] = await parallel(() => [
this._selectControl(),
this._inputControl(),
this._datepickerInputControl(),
this._dateRangeInputControl()
]);

// Match the datepicker inputs first since they can also have a `MatInput`.
return datepickerInput || dateRangeInput || select || input;
}

/** Gets the theme color of the form-field. */
Expand Down Expand Up @@ -234,6 +247,8 @@ export class MatFormFieldHarness extends _MatFormFieldHarnessBase<FormFieldContr
protected _hints = this.locatorForAll('mat-hint, .mat-hint');
protected _inputControl = this.locatorForOptional(MatInputHarness);
protected _selectControl = this.locatorForOptional(MatSelectHarness);
protected _datepickerInputControl = this.locatorForOptional(MatDatepickerInputHarness);
protected _dateRangeInputControl = this.locatorForOptional(MatDateRangeInputHarness);

/** Gets the appearance of the form-field. */
async getAppearance(): Promise<'legacy'|'standard'|'fill'|'outline'> {
Expand Down
34 changes: 30 additions & 4 deletions src/material/form-field/testing/shared.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,19 @@ import {MatFormFieldHarness} from './form-field-harness';

/** Shared tests to run on both the original and MDC-based form-field's. */
export function runHarnessTests(
modules: Type<any>[], {formFieldHarness, inputHarness, selectHarness, isMdcImplementation}: {
modules: Type<any>[], {
formFieldHarness,
inputHarness,
selectHarness,
datepickerInputHarness,
dateRangeInputHarness,
isMdcImplementation,
}: {
formFieldHarness: typeof MatFormFieldHarness,
inputHarness: Type<any>,
selectHarness: Type<any>,
datepickerInputHarness: Type<any>,
dateRangeInputHarness: Type<any>
isMdcImplementation: boolean
}) {
let fixture: ComponentFixture<FormFieldHarnessTest>;
Expand All @@ -34,7 +43,7 @@ export function runHarnessTests(

it('should be able to load harnesses', async () => {
const formFields = await loader.getAllHarnesses(formFieldHarness);
expect(formFields.length).toBe(5);
expect(formFields.length).toBe(7);
});

it('should be able to load form-field that matches specific selector', async () => {
Expand All @@ -60,6 +69,8 @@ export function runHarnessTests(
expect(await formFields[2].getControl() instanceof selectHarness).toBe(true);
expect(await formFields[3].getControl() instanceof inputHarness).toBe(true);
expect(await formFields[4].getControl() instanceof inputHarness).toBe(true);
expect(await formFields[5].getControl() instanceof datepickerInputHarness).toBe(true);
expect(await formFields[6].getControl() instanceof dateRangeInputHarness).toBe(true);
});

it('should be able to get custom control of form-field', async () => {
Expand Down Expand Up @@ -189,13 +200,13 @@ export function runHarnessTests(
it('should be able to get the prefix text of a form-field', async () => {
const formFields = await loader.getAllHarnesses(formFieldHarness);
const prefixTexts = await parallel(() => formFields.map(f => f.getPrefixText()));
expect(prefixTexts).toEqual(['prefix_textprefix_text_2', '', '', '', '']);
expect(prefixTexts).toEqual(['prefix_textprefix_text_2', '', '', '', '', '', '']);
});

it('should be able to get the suffix text of a form-field', async () => {
const formFields = await loader.getAllHarnesses(formFieldHarness);
const suffixTexts = await parallel(() => formFields.map(f => f.getSuffixText()));
expect(suffixTexts).toEqual(['suffix_text', '', '', '', '']);
expect(suffixTexts).toEqual(['suffix_text', '', '', '', '', '', '']);
});

it('should be able to check if form field has been touched', async () => {
Expand Down Expand Up @@ -281,6 +292,21 @@ export function runHarnessTests(
<mat-label>Label</mat-label>
<input matInput>
</mat-form-field>

<mat-form-field>
<mat-label>Date</mat-label>
<input matInput [matDatepicker]="datepicker">
<mat-datepicker #datepicker></mat-datepicker>
</mat-form-field>

<mat-form-field>
<mat-label>Date range</mat-label>
<mat-date-range-input [rangePicker]="rangePicker">
<input matStartDate placeholder="Start date"/>
<input matEndDate placeholder="End date"/>
</mat-date-range-input>
<mat-date-range-picker #rangePicker></mat-date-range-picker>
</mat-form-field>
`
})
class FormFieldHarnessTest {
Expand Down
6 changes: 5 additions & 1 deletion tools/public_api_guard/material/form-field/testing.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export declare abstract class _MatFormFieldHarnessBase<ControlHarness extends MatFormFieldControlHarness> extends ComponentHarness {
protected abstract _dateRangeInputControl: AsyncFactoryFn<ControlHarness | null>;
protected abstract _datepickerInputControl: AsyncFactoryFn<ControlHarness | null>;
protected abstract _errors: AsyncFactoryFn<TestElement[]>;
protected abstract _hints: AsyncFactoryFn<TestElement[]>;
protected abstract _inputControl: AsyncFactoryFn<ControlHarness | null>;
Expand Down Expand Up @@ -29,14 +31,16 @@ export declare abstract class _MatFormFieldHarnessBase<ControlHarness extends Ma
abstract isLabelFloating(): Promise<boolean>;
}

export declare type FormFieldControlHarness = MatInputHarness | MatSelectHarness;
export declare type FormFieldControlHarness = MatInputHarness | MatSelectHarness | MatDatepickerInputHarness | MatDateRangeInputHarness;

export interface FormFieldHarnessFilters extends BaseHarnessFilters {
floatingLabelText?: string | RegExp;
hasErrors?: boolean;
}

export declare class MatFormFieldHarness extends _MatFormFieldHarnessBase<FormFieldControlHarness> {
protected _dateRangeInputControl: AsyncFactoryFn<MatDateRangeInputHarness | null>;
protected _datepickerInputControl: AsyncFactoryFn<MatDatepickerInputHarness | null>;
protected _errors: AsyncFactoryFn<TestElement[]>;
protected _hints: AsyncFactoryFn<TestElement[]>;
protected _inputControl: AsyncFactoryFn<MatInputHarness | null>;
Expand Down