testing.mjs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. export { MatFormFieldControlHarness } from './testing/control.mjs';
  2. import { ComponentHarness, HarnessPredicate, parallel } from '@angular/cdk/testing';
  3. import { M as MatInputHarness } from '../input-harness-oQzj5EsQ.mjs';
  4. import { MatSelectHarness } from '../select/testing.mjs';
  5. import { M as MatDatepickerInputHarness, c as MatDateRangeInputHarness } from '../date-range-input-harness-Bp1T4oUe.mjs';
  6. import '@angular/cdk/coercion';
  7. import '../option-harness-BFcc-M_4.mjs';
  8. import '../core/testing.mjs';
  9. /** Harness for interacting with a `mat-error` in tests. */
  10. class MatErrorHarness extends ComponentHarness {
  11. static hostSelector = '.mat-mdc-form-field-error';
  12. /**
  13. * Gets a `HarnessPredicate` that can be used to search for an error with specific
  14. * attributes.
  15. * @param options Options for filtering which error instances are considered a match.
  16. * @return a `HarnessPredicate` configured with the given options.
  17. */
  18. static with(options = {}) {
  19. return MatErrorHarness._getErrorPredicate(this, options);
  20. }
  21. static _getErrorPredicate(type, options) {
  22. return new HarnessPredicate(type, options).addOption('text', options.text, (harness, text) => HarnessPredicate.stringMatches(harness.getText(), text));
  23. }
  24. /** Gets a promise for the error's label text. */
  25. async getText() {
  26. return (await this.host()).text();
  27. }
  28. }
  29. class MatFormFieldHarness extends ComponentHarness {
  30. _prefixContainer = this.locatorForOptional('.mat-mdc-form-field-text-prefix');
  31. _suffixContainer = this.locatorForOptional('.mat-mdc-form-field-text-suffix');
  32. _label = this.locatorForOptional('.mdc-floating-label');
  33. _hints = this.locatorForAll('.mat-mdc-form-field-hint');
  34. _inputControl = this.locatorForOptional(MatInputHarness);
  35. _selectControl = this.locatorForOptional(MatSelectHarness);
  36. _datepickerInputControl = this.locatorForOptional(MatDatepickerInputHarness);
  37. _dateRangeInputControl = this.locatorForOptional(MatDateRangeInputHarness);
  38. _textField = this.locatorFor('.mat-mdc-text-field-wrapper');
  39. _errorHarness = MatErrorHarness;
  40. static hostSelector = '.mat-mdc-form-field';
  41. /**
  42. * Gets a `HarnessPredicate` that can be used to search for a form field with specific
  43. * attributes.
  44. * @param options Options for filtering which form field instances are considered a match.
  45. * @return a `HarnessPredicate` configured with the given options.
  46. */
  47. static with(options = {}) {
  48. return new HarnessPredicate(this, options)
  49. .addOption('floatingLabelText', options.floatingLabelText, async (harness, text) => HarnessPredicate.stringMatches(await harness.getLabel(), text))
  50. .addOption('hasErrors', options.hasErrors, async (harness, hasErrors) => (await harness.hasErrors()) === hasErrors)
  51. .addOption('isValid', options.isValid, async (harness, isValid) => (await harness.isControlValid()) === isValid);
  52. }
  53. /** Gets the appearance of the form-field. */
  54. async getAppearance() {
  55. const textFieldEl = await this._textField();
  56. if (await textFieldEl.hasClass('mdc-text-field--outlined')) {
  57. return 'outline';
  58. }
  59. return 'fill';
  60. }
  61. /** Whether the form-field has a label. */
  62. async hasLabel() {
  63. return (await this._label()) !== null;
  64. }
  65. /** Whether the label is currently floating. */
  66. async isLabelFloating() {
  67. const labelEl = await this._label();
  68. return labelEl !== null ? await labelEl.hasClass('mdc-floating-label--float-above') : false;
  69. }
  70. /** Gets the label of the form-field. */
  71. async getLabel() {
  72. const labelEl = await this._label();
  73. return labelEl ? labelEl.text() : null;
  74. }
  75. /** Whether the form-field has errors. */
  76. async hasErrors() {
  77. return (await this.getTextErrors()).length > 0;
  78. }
  79. /** Whether the form-field is disabled. */
  80. async isDisabled() {
  81. return (await this.host()).hasClass('mat-form-field-disabled');
  82. }
  83. /** Whether the form-field is currently autofilled. */
  84. async isAutofilled() {
  85. return (await this.host()).hasClass('mat-form-field-autofilled');
  86. }
  87. // Implementation of the "getControl" method overload signatures.
  88. async getControl(type) {
  89. if (type) {
  90. return this.locatorForOptional(type)();
  91. }
  92. const [select, input, datepickerInput, dateRangeInput] = await parallel(() => [
  93. this._selectControl(),
  94. this._inputControl(),
  95. this._datepickerInputControl(),
  96. this._dateRangeInputControl(),
  97. ]);
  98. // Match the datepicker inputs first since they can also have a `MatInput`.
  99. return datepickerInput || dateRangeInput || select || input;
  100. }
  101. /** Gets the theme color of the form-field. */
  102. async getThemeColor() {
  103. const hostEl = await this.host();
  104. const [isAccent, isWarn] = await parallel(() => {
  105. return [hostEl.hasClass('mat-accent'), hostEl.hasClass('mat-warn')];
  106. });
  107. if (isAccent) {
  108. return 'accent';
  109. }
  110. else if (isWarn) {
  111. return 'warn';
  112. }
  113. return 'primary';
  114. }
  115. /** Gets error messages which are currently displayed in the form-field. */
  116. async getTextErrors() {
  117. const errors = await this.getErrors();
  118. return parallel(() => errors.map(e => e.getText()));
  119. }
  120. /** Gets all of the error harnesses in the form field. */
  121. async getErrors(filter = {}) {
  122. return this.locatorForAll(this._errorHarness.with(filter))();
  123. }
  124. /** Gets hint messages which are currently displayed in the form-field. */
  125. async getTextHints() {
  126. const hints = await this._hints();
  127. return parallel(() => hints.map(e => e.text()));
  128. }
  129. /** Gets the text inside the prefix element. */
  130. async getPrefixText() {
  131. const prefix = await this._prefixContainer();
  132. return prefix ? prefix.text() : '';
  133. }
  134. /** Gets the text inside the suffix element. */
  135. async getSuffixText() {
  136. const suffix = await this._suffixContainer();
  137. return suffix ? suffix.text() : '';
  138. }
  139. /**
  140. * Whether the form control has been touched. Returns "null"
  141. * if no form control is set up.
  142. */
  143. async isControlTouched() {
  144. if (!(await this._hasFormControl())) {
  145. return null;
  146. }
  147. return (await this.host()).hasClass('ng-touched');
  148. }
  149. /**
  150. * Whether the form control is dirty. Returns "null"
  151. * if no form control is set up.
  152. */
  153. async isControlDirty() {
  154. if (!(await this._hasFormControl())) {
  155. return null;
  156. }
  157. return (await this.host()).hasClass('ng-dirty');
  158. }
  159. /**
  160. * Whether the form control is valid. Returns "null"
  161. * if no form control is set up.
  162. */
  163. async isControlValid() {
  164. if (!(await this._hasFormControl())) {
  165. return null;
  166. }
  167. return (await this.host()).hasClass('ng-valid');
  168. }
  169. /**
  170. * Whether the form control is pending validation. Returns "null"
  171. * if no form control is set up.
  172. */
  173. async isControlPending() {
  174. if (!(await this._hasFormControl())) {
  175. return null;
  176. }
  177. return (await this.host()).hasClass('ng-pending');
  178. }
  179. /** Checks whether the form-field control has set up a form control. */
  180. async _hasFormControl() {
  181. const hostEl = await this.host();
  182. // If no form "NgControl" is bound to the form-field control, the form-field
  183. // is not able to forward any control status classes. Therefore if either the
  184. // "ng-touched" or "ng-untouched" class is set, we know that it has a form control
  185. const [isTouched, isUntouched] = await parallel(() => [
  186. hostEl.hasClass('ng-touched'),
  187. hostEl.hasClass('ng-untouched'),
  188. ]);
  189. return isTouched || isUntouched;
  190. }
  191. }
  192. export { MatErrorHarness, MatFormFieldHarness };
  193. //# sourceMappingURL=testing.mjs.map