66 * found in the LICENSE file at https://angular.io/license
77 */
88
9- import { HarnessPredicate , parallel } from '@angular/cdk/testing' ;
9+ import {
10+ HarnessPredicate ,
11+ parallel ,
12+ ComponentHarness ,
13+ BaseHarnessFilters ,
14+ ComponentHarnessConstructor ,
15+ } from '@angular/cdk/testing' ;
1016import { MatFormFieldControlHarness } from '@angular/material/form-field/testing/control' ;
1117import {
1218 MatOptionHarness ,
@@ -16,29 +22,25 @@ import {
1622} from '@angular/material/core/testing' ;
1723import { SelectHarnessFilters } from './select-harness-filters' ;
1824
19-
20- /** Harness for interacting with a standard mat-select in tests. */
21- export class MatSelectHarness extends MatFormFieldControlHarness {
25+ export abstract class _MatSelectHarnessBase <
26+ OptionType extends ( ComponentHarnessConstructor < Option > & {
27+ with : ( options ?: OptionFilters ) => HarnessPredicate < Option > } ) ,
28+ Option extends ComponentHarness & { click ( ) : Promise < void > } ,
29+ OptionFilters extends BaseHarnessFilters ,
30+ OptionGroupType extends ( ComponentHarnessConstructor < OptionGroup > & {
31+ with : ( options ?: OptionGroupFilters ) => HarnessPredicate < OptionGroup > } ) ,
32+ OptionGroup extends ComponentHarness ,
33+ OptionGroupFilters extends BaseHarnessFilters
34+ > extends MatFormFieldControlHarness {
35+ protected abstract _prefix : string ;
36+ protected abstract _optionClass : OptionType ;
37+ protected abstract _optionGroupClass : OptionGroupType ;
2238 private _documentRootLocator = this . documentRootLocatorFactory ( ) ;
2339 private _backdrop = this . _documentRootLocator . locatorFor ( '.cdk-overlay-backdrop' ) ;
24- private _trigger = this . locatorFor ( '.mat-select-trigger' ) ;
25- private _value = this . locatorFor ( '.mat-select-value' ) ;
26-
27- static hostSelector = '.mat-select' ;
28-
29- /**
30- * Gets a `HarnessPredicate` that can be used to search for a `MatSelectHarness` that meets
31- * certain criteria.
32- * @param options Options for filtering which select instances are considered a match.
33- * @return a `HarnessPredicate` configured with the given options.
34- */
35- static with ( options : SelectHarnessFilters = { } ) : HarnessPredicate < MatSelectHarness > {
36- return new HarnessPredicate ( MatSelectHarness , options ) ;
37- }
3840
3941 /** Gets a boolean promise indicating if the select is disabled. */
4042 async isDisabled ( ) : Promise < boolean > {
41- return ( await this . host ( ) ) . hasClass ( 'mat -select-disabled' ) ;
43+ return ( await this . host ( ) ) . hasClass ( ` ${ this . _prefix } -select-disabled` ) ;
4244 }
4345
4446 /** Gets a boolean promise indicating if the select is valid. */
@@ -48,22 +50,23 @@ export class MatSelectHarness extends MatFormFieldControlHarness {
4850
4951 /** Gets a boolean promise indicating if the select is required. */
5052 async isRequired ( ) : Promise < boolean > {
51- return ( await this . host ( ) ) . hasClass ( 'mat -select-required' ) ;
53+ return ( await this . host ( ) ) . hasClass ( ` ${ this . _prefix } -select-required` ) ;
5254 }
5355
5456 /** Gets a boolean promise indicating if the select is empty (no value is selected). */
5557 async isEmpty ( ) : Promise < boolean > {
56- return ( await this . host ( ) ) . hasClass ( 'mat -select-empty' ) ;
58+ return ( await this . host ( ) ) . hasClass ( ` ${ this . _prefix } -select-empty` ) ;
5759 }
5860
5961 /** Gets a boolean promise indicating if the select is in multi-selection mode. */
6062 async isMultiple ( ) : Promise < boolean > {
61- return ( await this . host ( ) ) . hasClass ( 'mat -select-multiple' ) ;
63+ return ( await this . host ( ) ) . hasClass ( ` ${ this . _prefix } -select-multiple` ) ;
6264 }
6365
6466 /** Gets a promise for the select's value text. */
6567 async getValueText ( ) : Promise < string > {
66- return ( await this . _value ( ) ) . text ( ) ;
68+ const value = await this . locatorFor ( `.${ this . _prefix } -select-value` ) ( ) ;
69+ return value . text ( ) ;
6770 }
6871
6972 /** Focuses the select and returns a void promise that indicates when the action is complete. */
@@ -82,21 +85,19 @@ export class MatSelectHarness extends MatFormFieldControlHarness {
8285 }
8386
8487 /** Gets the options inside the select panel. */
85- async getOptions ( filter : Omit < OptionHarnessFilters , 'ancestor' > = { } ) :
86- Promise < MatOptionHarness [ ] > {
87- return this . _documentRootLocator . locatorForAll ( MatOptionHarness . with ( {
88- ...filter ,
88+ async getOptions ( filter ?: Omit < OptionFilters , 'ancestor' > ) : Promise < Option [ ] > {
89+ return this . _documentRootLocator . locatorForAll ( this . _optionClass . with ( {
90+ ...( filter || { } ) ,
8991 ancestor : await this . _getPanelSelector ( )
90- } ) ) ( ) ;
92+ } as OptionFilters ) ) ( ) ;
9193 }
9294
9395 /** Gets the groups of options inside the panel. */
94- async getOptionGroups ( filter : Omit < OptgroupHarnessFilters , 'ancestor' > = { } ) :
95- Promise < MatOptgroupHarness [ ] > {
96- return this . _documentRootLocator . locatorForAll ( MatOptgroupHarness . with ( {
97- ...filter ,
96+ async getOptionGroups ( filter ?: Omit < OptionGroupFilters , 'ancestor' > ) : Promise < OptionGroup [ ] > {
97+ return this . _documentRootLocator . locatorForAll ( this . _optionGroupClass . with ( {
98+ ...( filter || { } ) ,
9899 ancestor : await this . _getPanelSelector ( )
99- } ) ) ( ) ;
100+ } as OptionGroupFilters ) ) ( ) as Promise < OptionGroup [ ] > ;
100101 }
101102
102103 /** Gets whether the select is open. */
@@ -107,20 +108,20 @@ export class MatSelectHarness extends MatFormFieldControlHarness {
107108 /** Opens the select's panel. */
108109 async open ( ) : Promise < void > {
109110 if ( ! await this . isOpen ( ) ) {
110- return ( await this . _trigger ( ) ) . click ( ) ;
111+ const trigger = await this . locatorFor ( `.${ this . _prefix } -select-trigger` ) ( ) ;
112+ return trigger . click ( ) ;
111113 }
112114 }
113115
114116 /**
115117 * Clicks the options that match the passed-in filter. If the select is in multi-selection
116118 * mode all options will be clicked, otherwise the harness will pick the first matching option.
117119 */
118- async clickOptions ( filter : OptionHarnessFilters = { } ) : Promise < void > {
120+ async clickOptions ( filter ?: OptionFilters ) : Promise < void > {
119121 await this . open ( ) ;
120122
121- const [ isMultiple , options ] = await parallel ( ( ) => {
122- return [ this . isMultiple ( ) , this . getOptions ( filter ) ] ;
123- } ) ;
123+ const [ isMultiple , options ] =
124+ await parallel ( ( ) => [ this . isMultiple ( ) , this . getOptions ( filter ) ] ) ;
124125
125126 if ( options . length === 0 ) {
126127 throw Error ( 'Select does not have options matching the specified filter' ) ;
@@ -149,3 +150,24 @@ export class MatSelectHarness extends MatFormFieldControlHarness {
149150 return `#${ id } -panel` ;
150151 }
151152}
153+
154+ /** Harness for interacting with a standard mat-select in tests. */
155+ export class MatSelectHarness extends _MatSelectHarnessBase <
156+ typeof MatOptionHarness , MatOptionHarness , OptionHarnessFilters ,
157+ typeof MatOptgroupHarness , MatOptgroupHarness , OptgroupHarnessFilters
158+ > {
159+ static hostSelector = '.mat-select' ;
160+ protected _prefix = 'mat' ;
161+ protected _optionClass = MatOptionHarness ;
162+ protected _optionGroupClass = MatOptgroupHarness ;
163+
164+ /**
165+ * Gets a `HarnessPredicate` that can be used to search for a `MatSelectHarness` that meets
166+ * certain criteria.
167+ * @param options Options for filtering which select instances are considered a match.
168+ * @return a `HarnessPredicate` configured with the given options.
169+ */
170+ static with ( options : SelectHarnessFilters = { } ) : HarnessPredicate < MatSelectHarness > {
171+ return new HarnessPredicate ( MatSelectHarness , options ) ;
172+ }
173+ }
0 commit comments