Skip to content

Commit ec266be

Browse files
crisbetoannieyw
authored andcommitted
fix(material/form-field): handle datepicker inputs in harness (#22403)
Resolves a TODO about supporting datepicker inputs in the form field harness. Also fixes an error that is thrown when the date range input is combined with an MDC-based form field. (cherry picked from commit f9cc564)
1 parent 62b2142 commit ec266be

File tree

11 files changed

+108
-18
lines changed

11 files changed

+108
-18
lines changed

src/components-examples/material/form-field/form-field-harness/form-field-harness-example.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('FormFieldHarnessExample', () => {
4747
expect(await formField.getTextHints()).toEqual(['Hint']);
4848

4949
fixture.componentInstance.requiredControl.setValue('');
50-
await (await formField.getControl())?.blur();
50+
await ((await formField.getControl() as MatInputHarness))?.blur();
5151
expect(await formField.getTextErrors()).toEqual(['Error']);
5252
expect(await formField.getTextHints()).toEqual([]);
5353
});

src/material-experimental/mdc-form-field/testing/BUILD.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ ts_library(
1313
"//src/cdk/testing",
1414
"//src/material-experimental/mdc-input/testing",
1515
"//src/material-experimental/mdc-select/testing",
16+
"//src/material/datepicker/testing",
1617
"//src/material/form-field/testing",
1718
"//src/material/form-field/testing/control",
1819
],
@@ -32,11 +33,14 @@ ng_test_library(
3233
deps = [
3334
":testing",
3435
"//src/material-experimental/mdc-autocomplete",
36+
"//src/material-experimental/mdc-core",
3537
"//src/material-experimental/mdc-form-field",
3638
"//src/material-experimental/mdc-input",
3739
"//src/material-experimental/mdc-input/testing",
3840
"//src/material-experimental/mdc-select",
3941
"//src/material-experimental/mdc-select/testing",
42+
"//src/material/datepicker",
43+
"//src/material/datepicker/testing",
4044
"//src/material/form-field/testing:harness_tests_lib",
4145
],
4246
)

src/material-experimental/mdc-form-field/testing/form-field-harness.spec.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,29 @@ import {MatInputHarness} from '@angular/material-experimental/mdc-input/testing'
55
import {MatSelectModule} from '@angular/material-experimental/mdc-select';
66
import {MatSelectHarness} from '@angular/material-experimental/mdc-select/testing';
77
import {runHarnessTests} from '@angular/material/form-field/testing/shared.spec';
8+
import {MatDatepickerModule} from '@angular/material/datepicker';
9+
import {MatNativeDateModule} from '@angular/material-experimental/mdc-core';
10+
import {
11+
MatDatepickerInputHarness,
12+
MatDateRangeInputHarness,
13+
} from '@angular/material/datepicker/testing';
814
import {MatFormFieldHarness} from './form-field-harness';
915

1016
describe('MDC-based MatFormFieldHarness', () => {
1117
runHarnessTests(
12-
[MatFormFieldModule, MatAutocompleteModule, MatInputModule, MatSelectModule], {
18+
[
19+
MatFormFieldModule,
20+
MatAutocompleteModule,
21+
MatInputModule,
22+
MatSelectModule,
23+
MatNativeDateModule,
24+
MatDatepickerModule
25+
], {
1326
formFieldHarness: MatFormFieldHarness as any,
1427
inputHarness: MatInputHarness,
1528
selectHarness: MatSelectHarness,
29+
datepickerInputHarness: MatDatepickerInputHarness,
30+
dateRangeInputHarness: MatDateRangeInputHarness,
1631
isMdcImplementation: true,
1732
});
1833
});

src/material-experimental/mdc-form-field/testing/form-field-harness.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ import {
1313
} from '@angular/material/form-field/testing';
1414
import {MatInputHarness} from '@angular/material-experimental/mdc-input/testing';
1515
import {MatSelectHarness} from '@angular/material-experimental/mdc-select/testing';
16+
import {
17+
MatDatepickerInputHarness,
18+
MatDateRangeInputHarness,
19+
} from '@angular/material/datepicker/testing';
1620

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

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

4955
/** Gets the appearance of the form-field. */

src/material/datepicker/testing/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ ts_library(
1212
deps = [
1313
"//src/cdk/coercion",
1414
"//src/cdk/testing",
15+
"//src/material/form-field/testing/control",
1516
],
1617
)
1718

src/material/datepicker/testing/datepicker-input-harness-base.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
import {
1010
ComponentHarnessConstructor,
1111
HarnessPredicate,
12-
ComponentHarness,
1312
} from '@angular/cdk/testing';
13+
import {MatFormFieldControlHarness} from '@angular/material/form-field/testing/control';
1414
import {DatepickerInputHarnessFilters} from './datepicker-harness-filters';
1515

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

3030
/** Base class for datepicker input harnesses. */
31-
export abstract class MatDatepickerInputHarnessBase extends ComponentHarness {
31+
export abstract class MatDatepickerInputHarnessBase extends MatFormFieldControlHarness {
3232
/** Whether the input is disabled. */
3333
async isDisabled(): Promise<boolean> {
3434
return (await this.host()).getProperty('disabled')!;

src/material/form-field/testing/BUILD.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ts_library(
1111
module_name = "@angular/material/form-field/testing",
1212
deps = [
1313
"//src/cdk/testing",
14+
"//src/material/datepicker/testing",
1415
"//src/material/form-field/testing/control",
1516
"//src/material/input/testing",
1617
"//src/material/select/testing",
@@ -45,6 +46,9 @@ ng_test_library(
4546
":harness_tests_lib",
4647
":testing",
4748
"//src/material/autocomplete",
49+
"//src/material/core",
50+
"//src/material/datepicker",
51+
"//src/material/datepicker/testing",
4852
"//src/material/form-field",
4953
"//src/material/input",
5054
"//src/material/input/testing",

src/material/form-field/testing/form-field-harness.spec.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
import {MatAutocompleteModule} from '@angular/material/autocomplete';
2+
import {MatNativeDateModule} from '@angular/material/core';
3+
import {MatDatepickerModule} from '@angular/material/datepicker';
4+
import {
5+
MatDatepickerInputHarness,
6+
MatDateRangeInputHarness,
7+
} from '@angular/material/datepicker/testing';
28
import {MatFormFieldModule} from '@angular/material/form-field';
39
import {MatInputModule} from '@angular/material/input';
410
import {MatInputHarness} from '@angular/material/input/testing';
@@ -9,10 +15,19 @@ import {MatFormFieldHarness} from './form-field-harness';
915
import {runHarnessTests} from './shared.spec';
1016

1117
describe('Non-MDC-based MatFormFieldHarness', () => {
12-
runHarnessTests([MatFormFieldModule, MatAutocompleteModule, MatInputModule, MatSelectModule], {
18+
runHarnessTests([
19+
MatFormFieldModule,
20+
MatAutocompleteModule,
21+
MatInputModule,
22+
MatSelectModule,
23+
MatNativeDateModule,
24+
MatDatepickerModule,
25+
], {
1326
formFieldHarness: MatFormFieldHarness,
1427
inputHarness: MatInputHarness,
1528
selectHarness: MatSelectHarness,
29+
datepickerInputHarness: MatDatepickerInputHarness,
30+
dateRangeInputHarness: MatDateRangeInputHarness,
1631
isMdcImplementation: false,
1732
});
1833
});

src/material/form-field/testing/form-field-harness.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,19 @@ import {
1515
parallel,
1616
TestElement
1717
} from '@angular/cdk/testing';
18+
import {
19+
MatDatepickerInputHarness,
20+
MatDateRangeInputHarness,
21+
} from '@angular/material/datepicker/testing';
1822
import {MatFormFieldControlHarness} from '@angular/material/form-field/testing/control';
1923
import {MatInputHarness} from '@angular/material/input/testing';
2024
import {MatSelectHarness} from '@angular/material/select/testing';
2125
import {FormFieldHarnessFilters} from './form-field-harness-filters';
2226

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

2832
export abstract class _MatFormFieldHarnessBase<ControlHarness extends MatFormFieldControlHarness>
2933
extends ComponentHarness {
@@ -34,6 +38,8 @@ export abstract class _MatFormFieldHarnessBase<ControlHarness extends MatFormFie
3438
protected abstract _hints: AsyncFactoryFn<TestElement[]>;
3539
protected abstract _inputControl: AsyncFactoryFn<ControlHarness|null>;
3640
protected abstract _selectControl: AsyncFactoryFn<ControlHarness|null>;
41+
protected abstract _datepickerInputControl: AsyncFactoryFn<ControlHarness|null>;
42+
protected abstract _dateRangeInputControl: AsyncFactoryFn<ControlHarness|null>;
3743

3844
/** Gets the appearance of the form-field. */
3945
abstract getAppearance(): Promise<string>;
@@ -91,8 +97,15 @@ export abstract class _MatFormFieldHarnessBase<ControlHarness extends MatFormFie
9197
if (type) {
9298
return this.locatorForOptional(type)();
9399
}
94-
const [select, input] = await parallel(() => [this._selectControl(), this._inputControl()]);
95-
return select || input;
100+
const [select, input, datepickerInput, dateRangeInput] = await parallel(() => [
101+
this._selectControl(),
102+
this._inputControl(),
103+
this._datepickerInputControl(),
104+
this._dateRangeInputControl()
105+
]);
106+
107+
// Match the datepicker inputs first since they can also have a `MatInput`.
108+
return datepickerInput || dateRangeInput || select || input;
96109
}
97110

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

238253
/** Gets the appearance of the form-field. */
239254
async getAppearance(): Promise<'legacy'|'standard'|'fill'|'outline'> {

src/material/form-field/testing/shared.spec.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,19 @@ import {MatFormFieldHarness} from './form-field-harness';
99

1010
/** Shared tests to run on both the original and MDC-based form-field's. */
1111
export function runHarnessTests(
12-
modules: Type<any>[], {formFieldHarness, inputHarness, selectHarness, isMdcImplementation}: {
12+
modules: Type<any>[], {
13+
formFieldHarness,
14+
inputHarness,
15+
selectHarness,
16+
datepickerInputHarness,
17+
dateRangeInputHarness,
18+
isMdcImplementation,
19+
}: {
1320
formFieldHarness: typeof MatFormFieldHarness,
1421
inputHarness: Type<any>,
1522
selectHarness: Type<any>,
23+
datepickerInputHarness: Type<any>,
24+
dateRangeInputHarness: Type<any>
1625
isMdcImplementation: boolean
1726
}) {
1827
let fixture: ComponentFixture<FormFieldHarnessTest>;
@@ -34,7 +43,7 @@ export function runHarnessTests(
3443

3544
it('should be able to load harnesses', async () => {
3645
const formFields = await loader.getAllHarnesses(formFieldHarness);
37-
expect(formFields.length).toBe(5);
46+
expect(formFields.length).toBe(7);
3847
});
3948

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

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

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

201212
it('should be able to check if form field has been touched', async () => {
@@ -281,6 +292,21 @@ export function runHarnessTests(
281292
<mat-label>Label</mat-label>
282293
<input matInput>
283294
</mat-form-field>
295+
296+
<mat-form-field>
297+
<mat-label>Date</mat-label>
298+
<input matInput [matDatepicker]="datepicker">
299+
<mat-datepicker #datepicker></mat-datepicker>
300+
</mat-form-field>
301+
302+
<mat-form-field>
303+
<mat-label>Date range</mat-label>
304+
<mat-date-range-input [rangePicker]="rangePicker">
305+
<input matStartDate placeholder="Start date"/>
306+
<input matEndDate placeholder="End date"/>
307+
</mat-date-range-input>
308+
<mat-date-range-picker #rangePicker></mat-date-range-picker>
309+
</mat-form-field>
284310
`
285311
})
286312
class FormFieldHarnessTest {

tools/public_api_guard/material/form-field/testing.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
export declare abstract class _MatFormFieldHarnessBase<ControlHarness extends MatFormFieldControlHarness> extends ComponentHarness {
2+
protected abstract _dateRangeInputControl: AsyncFactoryFn<ControlHarness | null>;
3+
protected abstract _datepickerInputControl: AsyncFactoryFn<ControlHarness | null>;
24
protected abstract _errors: AsyncFactoryFn<TestElement[]>;
35
protected abstract _hints: AsyncFactoryFn<TestElement[]>;
46
protected abstract _inputControl: AsyncFactoryFn<ControlHarness | null>;
@@ -29,14 +31,16 @@ export declare abstract class _MatFormFieldHarnessBase<ControlHarness extends Ma
2931
abstract isLabelFloating(): Promise<boolean>;
3032
}
3133

32-
export declare type FormFieldControlHarness = MatInputHarness | MatSelectHarness;
34+
export declare type FormFieldControlHarness = MatInputHarness | MatSelectHarness | MatDatepickerInputHarness | MatDateRangeInputHarness;
3335

3436
export interface FormFieldHarnessFilters extends BaseHarnessFilters {
3537
floatingLabelText?: string | RegExp;
3638
hasErrors?: boolean;
3739
}
3840

3941
export declare class MatFormFieldHarness extends _MatFormFieldHarnessBase<FormFieldControlHarness> {
42+
protected _dateRangeInputControl: AsyncFactoryFn<MatDateRangeInputHarness | null>;
43+
protected _datepickerInputControl: AsyncFactoryFn<MatDatepickerInputHarness | null>;
4044
protected _errors: AsyncFactoryFn<TestElement[]>;
4145
protected _hints: AsyncFactoryFn<TestElement[]>;
4246
protected _inputControl: AsyncFactoryFn<MatInputHarness | null>;

0 commit comments

Comments
 (0)