-
Notifications
You must be signed in to change notification settings - Fork 6.8k
/
Copy pathdate-range-input-harness.ts
153 lines (133 loc) · 6.2 KB
/
date-range-input-harness.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {HarnessPredicate, parallel, TestKey} from '@angular/cdk/testing';
import {MatDatepickerInputHarnessBase, getInputPredicate} from './datepicker-input-harness-base';
import {DatepickerTriggerHarnessBase} from './datepicker-trigger-harness-base';
import {
DatepickerInputHarnessFilters,
DateRangeInputHarnessFilters,
} from './datepicker-harness-filters';
/** Harness for interacting with a standard Material date range start input in tests. */
export class MatStartDateHarness extends MatDatepickerInputHarnessBase {
static hostSelector = '.mat-start-date';
/**
* Gets a `HarnessPredicate` that can be used to search for a `MatStartDateHarness`
* that meets certain criteria.
* @param options Options for filtering which input instances are considered a match.
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: DatepickerInputHarnessFilters = {}): HarnessPredicate<MatStartDateHarness> {
return getInputPredicate(MatStartDateHarness, options);
}
}
/** Harness for interacting with a standard Material date range end input in tests. */
export class MatEndDateHarness extends MatDatepickerInputHarnessBase {
static hostSelector = '.mat-end-date';
/**
* Gets a `HarnessPredicate` that can be used to search for a `MatEndDateHarness`
* that meets certain criteria.
* @param options Options for filtering which input instances are considered a match.
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: DatepickerInputHarnessFilters = {}): HarnessPredicate<MatEndDateHarness> {
return getInputPredicate(MatEndDateHarness, options);
}
}
/** Harness for interacting with a standard Material date range input in tests. */
export class MatDateRangeInputHarness extends DatepickerTriggerHarnessBase {
static hostSelector = '.mat-date-range-input';
private readonly floatingLabelSelector = '.mdc-floating-label';
/**
* Gets a `HarnessPredicate` that can be used to search for a `MatDateRangeInputHarness`
* that meets certain criteria.
* @param options Options for filtering which input instances are considered a match.
* @return a `HarnessPredicate` configured with the given options.
*/
static with(
options: DateRangeInputHarnessFilters = {},
): HarnessPredicate<MatDateRangeInputHarness> {
return new HarnessPredicate(MatDateRangeInputHarness, options)
.addOption('value', options.value, (harness, value) =>
HarnessPredicate.stringMatches(harness.getValue(), value),
)
.addOption('label', options.label, (harness, label) => {
return HarnessPredicate.stringMatches(harness.getLabel(), label);
});
}
/** Gets the combined value of the start and end inputs, including the separator. */
async getValue(): Promise<string> {
const [start, end, separator] = await parallel(() => [
this.getStartInput().then(input => input.getValue()),
this.getEndInput().then(input => input.getValue()),
this.getSeparator(),
]);
return start + `${end ? ` ${separator} ${end}` : ''}`;
}
/** Gets the inner start date input inside the range input. */
async getStartInput(): Promise<MatStartDateHarness> {
// Don't pass in filters here since the start input is required and there can only be one.
return this.locatorFor(MatStartDateHarness)();
}
/** Gets the inner start date input inside the range input. */
async getEndInput(): Promise<MatEndDateHarness> {
// Don't pass in filters here since the end input is required and there can only be one.
return this.locatorFor(MatEndDateHarness)();
}
/** Gets the floating label text for the range input, if it exists. */
async getLabel(): Promise<string | null> {
// Copied from MatFormFieldControlHarness since this class cannot extend two classes
const documentRootLocator = await this.documentRootLocatorFactory();
const labelId = await (await this.host()).getAttribute('aria-labelledby');
const hostId = await (await this.host()).getAttribute('id');
if (labelId) {
// First option, try to fetch the label using the `aria-labelledby`
// attribute.
const labelEl = await await documentRootLocator.locatorForOptional(
`${this.floatingLabelSelector}[id="${labelId}"]`,
)();
return labelEl ? labelEl.text() : null;
} else if (hostId) {
// Fallback option, try to match the id of the input with the `for`
// attribute of the label.
const labelEl = await await documentRootLocator.locatorForOptional(
`${this.floatingLabelSelector}[for="${hostId}"]`,
)();
return labelEl ? labelEl.text() : null;
}
return null;
}
/** Gets the separator text between the values of the two inputs. */
async getSeparator(): Promise<string> {
return (await this.locatorFor('.mat-date-range-input-separator')()).text();
}
/** Gets whether the range input is disabled. */
async isDisabled(): Promise<boolean> {
// We consider the input as disabled if both of the sub-inputs are disabled.
const [startDisabled, endDisabled] = await parallel(() => [
this.getStartInput().then(input => input.isDisabled()),
this.getEndInput().then(input => input.isDisabled()),
]);
return startDisabled && endDisabled;
}
/** Gets whether the range input is required. */
async isRequired(): Promise<boolean> {
return (await this.host()).hasClass('mat-date-range-input-required');
}
/** Opens the calendar associated with the input. */
async isCalendarOpen(): Promise<boolean> {
// `aria-owns` is set on both inputs only if there's an
// open range picker so we can use it as an indicator.
const startHost = await (await this.getStartInput()).host();
return (await startHost.getAttribute('aria-owns')) != null;
}
protected async _openCalendar(): Promise<void> {
// Alt + down arrow is the combination for opening the calendar with the keyboard.
const startHost = await (await this.getStartInput()).host();
return startHost.sendKeys({alt: true}, TestKey.DOWN_ARROW);
}
}