@rachelallyson/hero-hook-form 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/dist/cypress/index.d.ts +141 -0
- package/dist/cypress/index.js +897 -0
- package/dist/index.d.ts +730 -5
- package/dist/index.js +1892 -225
- package/dist/react/index.d.ts +730 -5
- package/dist/react/index.js +1892 -225
- package/package.json +10 -3
- package/README.md +0 -412
|
@@ -0,0 +1,897 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __esm = (fn, res) => function __init() {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
};
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
17
|
+
|
|
18
|
+
// src/cypress/utils.ts
|
|
19
|
+
function withRetry(operation, config = DEFAULT_CONFIG) {
|
|
20
|
+
if (!config.retry) {
|
|
21
|
+
return operation();
|
|
22
|
+
}
|
|
23
|
+
let attempts = 0;
|
|
24
|
+
const maxAttempts = config.maxRetries + 1;
|
|
25
|
+
const retryOperation = () => {
|
|
26
|
+
attempts++;
|
|
27
|
+
return operation().then(
|
|
28
|
+
(result) => {
|
|
29
|
+
return result;
|
|
30
|
+
},
|
|
31
|
+
(error) => {
|
|
32
|
+
if (attempts < maxAttempts) {
|
|
33
|
+
cy.log(`Retry attempt ${attempts}/${maxAttempts} for operation`);
|
|
34
|
+
cy.wait(config.retryDelay);
|
|
35
|
+
return retryOperation();
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
return retryOperation();
|
|
42
|
+
}
|
|
43
|
+
function findFieldByLabel(label) {
|
|
44
|
+
return `label:contains("${label}")`;
|
|
45
|
+
}
|
|
46
|
+
function findFieldByPlaceholder(placeholder) {
|
|
47
|
+
return `input[placeholder*="${placeholder}"], textarea[placeholder*="${placeholder}"]`;
|
|
48
|
+
}
|
|
49
|
+
function findFieldByType(type) {
|
|
50
|
+
return HERO_UI_SELECTORS.inputs[type] || `input[type="${type}"]`;
|
|
51
|
+
}
|
|
52
|
+
function buildHeroUISelector(type, subtype) {
|
|
53
|
+
switch (type) {
|
|
54
|
+
case "input":
|
|
55
|
+
return subtype ? HERO_UI_SELECTORS.inputs[subtype] : "input";
|
|
56
|
+
case "textarea":
|
|
57
|
+
return HERO_UI_SELECTORS.textarea;
|
|
58
|
+
case "dropdown":
|
|
59
|
+
return subtype === "trigger" ? HERO_UI_SELECTORS.dropdown.trigger : HERO_UI_SELECTORS.dropdown.option;
|
|
60
|
+
case "checkbox":
|
|
61
|
+
return subtype === "role" ? HERO_UI_SELECTORS.checkbox.role : HERO_UI_SELECTORS.checkbox.input;
|
|
62
|
+
case "switch":
|
|
63
|
+
return subtype === "role" ? HERO_UI_SELECTORS.switch.role : HERO_UI_SELECTORS.switch.input;
|
|
64
|
+
case "radio":
|
|
65
|
+
return subtype === "group" ? HERO_UI_SELECTORS.radio.group : HERO_UI_SELECTORS.radio.input;
|
|
66
|
+
case "slider":
|
|
67
|
+
return HERO_UI_SELECTORS.slider;
|
|
68
|
+
case "button":
|
|
69
|
+
return subtype ? HERO_UI_SELECTORS.button[subtype] : HERO_UI_SELECTORS.button.generic;
|
|
70
|
+
default:
|
|
71
|
+
return "input";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function waitForStable(selector, timeout = 1e3) {
|
|
75
|
+
return cy.get(selector, { timeout }).should("be.visible");
|
|
76
|
+
}
|
|
77
|
+
function forceClickWithRetry(selector, config = DEFAULT_CONFIG) {
|
|
78
|
+
return withRetry(() => {
|
|
79
|
+
return cy.get(selector).click({ force: true });
|
|
80
|
+
}, config);
|
|
81
|
+
}
|
|
82
|
+
function typeWithClear(selector, value, options = {}) {
|
|
83
|
+
const element = cy.get(selector);
|
|
84
|
+
if (options.clear !== false) {
|
|
85
|
+
element.clear({ force: true });
|
|
86
|
+
}
|
|
87
|
+
return element.type(value, { force: true });
|
|
88
|
+
}
|
|
89
|
+
function logFormState() {
|
|
90
|
+
cy.get("form").then(($form) => {
|
|
91
|
+
const formData = {};
|
|
92
|
+
$form.find("input, textarea, select").each((index, element) => {
|
|
93
|
+
const $el = Cypress.$(element);
|
|
94
|
+
const name = $el.attr("name") || `field_${index}`;
|
|
95
|
+
const type = $el.attr("type") || element.tagName.toLowerCase();
|
|
96
|
+
const value = $el.val();
|
|
97
|
+
formData[name] = { type, value };
|
|
98
|
+
});
|
|
99
|
+
cy.log("Form state:", formData);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function extractFormData() {
|
|
103
|
+
return cy.get("form").then(($form) => {
|
|
104
|
+
const formData = {};
|
|
105
|
+
$form.find("input, textarea, select").each((index, element) => {
|
|
106
|
+
const $el = Cypress.$(element);
|
|
107
|
+
const name = $el.attr("name") || `field_${index}`;
|
|
108
|
+
const value = $el.val();
|
|
109
|
+
if (value !== void 0 && value !== "") {
|
|
110
|
+
formData[name] = value;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
return formData;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function elementExists(selector) {
|
|
117
|
+
return cy.get("body").then(($body) => {
|
|
118
|
+
return $body.find(selector).length > 0;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function detectFieldType(value) {
|
|
122
|
+
if (typeof value === "boolean") return "checkbox";
|
|
123
|
+
if (typeof value === "number") return "number";
|
|
124
|
+
if (typeof value === "string") {
|
|
125
|
+
if (value.includes("@")) return "email";
|
|
126
|
+
if (/^\d{3}-\d{3}-\d{4}$/.test(value)) return "tel";
|
|
127
|
+
if (value.toLowerCase().includes("password")) return "password";
|
|
128
|
+
}
|
|
129
|
+
return "text";
|
|
130
|
+
}
|
|
131
|
+
var HERO_UI_SELECTORS, DEFAULT_CONFIG;
|
|
132
|
+
var init_utils = __esm({
|
|
133
|
+
"src/cypress/utils.ts"() {
|
|
134
|
+
"use strict";
|
|
135
|
+
HERO_UI_SELECTORS = {
|
|
136
|
+
inputs: {
|
|
137
|
+
text: 'input[type="text"]',
|
|
138
|
+
email: 'input[type="email"]',
|
|
139
|
+
tel: 'input[type="tel"]',
|
|
140
|
+
password: 'input[type="password"]',
|
|
141
|
+
number: 'input[type="number"]',
|
|
142
|
+
url: 'input[type="url"]',
|
|
143
|
+
search: 'input[type="search"]'
|
|
144
|
+
},
|
|
145
|
+
textarea: "textarea",
|
|
146
|
+
dropdown: {
|
|
147
|
+
trigger: 'button[aria-haspopup="listbox"]',
|
|
148
|
+
option: '[role="option"]'
|
|
149
|
+
},
|
|
150
|
+
checkbox: {
|
|
151
|
+
input: 'input[type="checkbox"]',
|
|
152
|
+
role: '[role="checkbox"]'
|
|
153
|
+
},
|
|
154
|
+
switch: {
|
|
155
|
+
input: 'input[role="switch"]',
|
|
156
|
+
role: '[role="switch"]'
|
|
157
|
+
},
|
|
158
|
+
radio: {
|
|
159
|
+
input: 'input[type="radio"]',
|
|
160
|
+
group: '[role="radiogroup"]'
|
|
161
|
+
},
|
|
162
|
+
slider: 'input[type="range"]',
|
|
163
|
+
button: {
|
|
164
|
+
submit: 'button[type="submit"]',
|
|
165
|
+
reset: 'button[type="reset"]',
|
|
166
|
+
generic: "button"
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
DEFAULT_CONFIG = {
|
|
170
|
+
strict: false,
|
|
171
|
+
timeout: 4e3,
|
|
172
|
+
retry: true,
|
|
173
|
+
maxRetries: 3,
|
|
174
|
+
retryDelay: 100
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// src/cypress/helpers.ts
|
|
180
|
+
function fillInputByType(type, value, index = 0, options = {}) {
|
|
181
|
+
const selector = type === "textarea" ? buildHeroUISelector("textarea") : buildHeroUISelector("input", type);
|
|
182
|
+
const element = index > 0 ? cy.get(selector).eq(index) : cy.get(selector).first();
|
|
183
|
+
return withRetry(() => {
|
|
184
|
+
if (options.clear !== false) {
|
|
185
|
+
element.clear({ force: true });
|
|
186
|
+
}
|
|
187
|
+
return element.type(value, { force: true });
|
|
188
|
+
}, DEFAULT_CONFIG);
|
|
189
|
+
}
|
|
190
|
+
function fillInputByPlaceholder(placeholder, value, options = {}) {
|
|
191
|
+
const selector = `input[placeholder*="${placeholder}"], textarea[placeholder*="${placeholder}"]`;
|
|
192
|
+
return withRetry(() => {
|
|
193
|
+
const element = cy.get(selector);
|
|
194
|
+
if (options.clear !== false) {
|
|
195
|
+
element.clear({ force: true });
|
|
196
|
+
}
|
|
197
|
+
return element.type(value, { force: true });
|
|
198
|
+
}, DEFAULT_CONFIG);
|
|
199
|
+
}
|
|
200
|
+
function fillInputByLabel(label, value, options = {}) {
|
|
201
|
+
return withRetry(() => {
|
|
202
|
+
return cy.contains("label", label).closest("div").find("input, textarea").first().then(($el) => {
|
|
203
|
+
if (options.clear !== false) {
|
|
204
|
+
cy.wrap($el).clear({ force: true });
|
|
205
|
+
}
|
|
206
|
+
return cy.wrap($el).type(value, { force: true });
|
|
207
|
+
});
|
|
208
|
+
}, DEFAULT_CONFIG);
|
|
209
|
+
}
|
|
210
|
+
function fillTextarea(value, index = 0, options = {}) {
|
|
211
|
+
const selector = HERO_UI_SELECTORS.textarea;
|
|
212
|
+
return withRetry(() => {
|
|
213
|
+
const element = index > 0 ? cy.get(selector).eq(index) : cy.get(selector).first();
|
|
214
|
+
if (options.clear !== false) {
|
|
215
|
+
element.clear({ force: true });
|
|
216
|
+
}
|
|
217
|
+
return element.type(value, { force: true });
|
|
218
|
+
}, DEFAULT_CONFIG);
|
|
219
|
+
}
|
|
220
|
+
function selectDropdownOption(optionValue, dropdownIndex = 0) {
|
|
221
|
+
const triggerSelector = HERO_UI_SELECTORS.dropdown.trigger;
|
|
222
|
+
const optionSelector = HERO_UI_SELECTORS.dropdown.option;
|
|
223
|
+
return withRetry(() => {
|
|
224
|
+
const trigger = dropdownIndex > 0 ? cy.get(triggerSelector).eq(dropdownIndex) : cy.get(triggerSelector).first();
|
|
225
|
+
trigger.click();
|
|
226
|
+
cy.get(optionSelector).should("exist");
|
|
227
|
+
if (optionValue) {
|
|
228
|
+
cy.get(optionSelector).contains(optionValue).click({ force: true });
|
|
229
|
+
} else {
|
|
230
|
+
cy.get(optionSelector).first().click({ force: true });
|
|
231
|
+
}
|
|
232
|
+
cy.get(triggerSelector).eq(dropdownIndex).should("have.attr", "aria-expanded", "false");
|
|
233
|
+
return cy.get(triggerSelector).eq(dropdownIndex);
|
|
234
|
+
}, DEFAULT_CONFIG);
|
|
235
|
+
}
|
|
236
|
+
function selectDropdownByLabel(label, optionValue) {
|
|
237
|
+
return withRetry(() => {
|
|
238
|
+
cy.contains("label", label).should("exist");
|
|
239
|
+
return cy.get('button[aria-haspopup="listbox"]').first().click().then(() => {
|
|
240
|
+
cy.get('[role="option"]').should("exist");
|
|
241
|
+
if (optionValue) {
|
|
242
|
+
cy.get('[role="option"]').contains(optionValue).click({ force: true });
|
|
243
|
+
} else {
|
|
244
|
+
cy.get('[role="option"]').first().click({ force: true });
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}, DEFAULT_CONFIG);
|
|
248
|
+
}
|
|
249
|
+
function checkCheckbox(index = 0) {
|
|
250
|
+
const selector = HERO_UI_SELECTORS.checkbox.input;
|
|
251
|
+
const element = index > 0 ? cy.get(selector).eq(index) : cy.get(selector).first();
|
|
252
|
+
return withRetry(() => {
|
|
253
|
+
return element.check();
|
|
254
|
+
}, DEFAULT_CONFIG);
|
|
255
|
+
}
|
|
256
|
+
function checkCheckboxByLabel(label) {
|
|
257
|
+
return withRetry(() => {
|
|
258
|
+
return cy.contains("label", label).closest("div").find('input[type="checkbox"]').check({ force: true });
|
|
259
|
+
}, DEFAULT_CONFIG);
|
|
260
|
+
}
|
|
261
|
+
function checkSwitch(index = 0) {
|
|
262
|
+
const selector = HERO_UI_SELECTORS.switch.input;
|
|
263
|
+
const element = index > 0 ? cy.get(selector).eq(index) : cy.get(selector).first();
|
|
264
|
+
return withRetry(() => {
|
|
265
|
+
return element.check();
|
|
266
|
+
}, DEFAULT_CONFIG);
|
|
267
|
+
}
|
|
268
|
+
function uncheckCheckbox(index = 0) {
|
|
269
|
+
const selector = HERO_UI_SELECTORS.checkbox.input;
|
|
270
|
+
const element = index > 0 ? cy.get(selector).eq(index) : cy.get(selector).first();
|
|
271
|
+
return withRetry(() => {
|
|
272
|
+
return element.uncheck();
|
|
273
|
+
}, DEFAULT_CONFIG);
|
|
274
|
+
}
|
|
275
|
+
function uncheckSwitch(index = 0) {
|
|
276
|
+
const selector = HERO_UI_SELECTORS.switch.input;
|
|
277
|
+
const element = index > 0 ? cy.get(selector).eq(index) : cy.get(selector).first();
|
|
278
|
+
return withRetry(() => {
|
|
279
|
+
return element.uncheck();
|
|
280
|
+
}, DEFAULT_CONFIG);
|
|
281
|
+
}
|
|
282
|
+
function moveSlider(value, index = 0) {
|
|
283
|
+
const selector = HERO_UI_SELECTORS.slider;
|
|
284
|
+
const element = index > 0 ? cy.get(selector).eq(index) : cy.get(selector).first();
|
|
285
|
+
return withRetry(() => {
|
|
286
|
+
return element.invoke("val", value).trigger("change");
|
|
287
|
+
}, DEFAULT_CONFIG);
|
|
288
|
+
}
|
|
289
|
+
function expectValidationError(message) {
|
|
290
|
+
return cy.contains(message).should("be.visible");
|
|
291
|
+
}
|
|
292
|
+
function expectNoValidationErrors() {
|
|
293
|
+
return cy.get("body").should("not.contain", "error").and("not.contain", "invalid");
|
|
294
|
+
}
|
|
295
|
+
function expectFieldError(fieldLabel, errorMessage) {
|
|
296
|
+
return cy.contains("label", fieldLabel).closest("div").should("contain", errorMessage);
|
|
297
|
+
}
|
|
298
|
+
function expectFieldValid(fieldLabel) {
|
|
299
|
+
return cy.contains("label", fieldLabel).closest("div").should("not.contain", "error").and("not.contain", "invalid");
|
|
300
|
+
}
|
|
301
|
+
function triggerValidation(submitButton = false) {
|
|
302
|
+
if (submitButton) {
|
|
303
|
+
return cy.get(HERO_UI_SELECTORS.button.submit).first().click();
|
|
304
|
+
}
|
|
305
|
+
return cy.get("input").first().blur();
|
|
306
|
+
}
|
|
307
|
+
function submitForm() {
|
|
308
|
+
return cy.get(HERO_UI_SELECTORS.button.submit).first().click();
|
|
309
|
+
}
|
|
310
|
+
function submitAndExpectSuccess(successIndicator) {
|
|
311
|
+
cy.get(HERO_UI_SELECTORS.button.submit).first().click();
|
|
312
|
+
if (successIndicator) {
|
|
313
|
+
return cy.contains(successIndicator).should("be.visible");
|
|
314
|
+
}
|
|
315
|
+
return cy.get("body").should("contain.one.of", ["success", "submitted", "complete", "thank you"]);
|
|
316
|
+
}
|
|
317
|
+
function submitAndExpectErrors(errorMessage, formIndex = 0) {
|
|
318
|
+
cy.get(HERO_UI_SELECTORS.button.submit).eq(formIndex).click();
|
|
319
|
+
cy.get("form").should("exist");
|
|
320
|
+
cy.wait(500);
|
|
321
|
+
if (errorMessage) {
|
|
322
|
+
cy.get("body").then(($body) => {
|
|
323
|
+
if ($body.text().includes(errorMessage)) {
|
|
324
|
+
cy.contains(errorMessage).should("be.visible");
|
|
325
|
+
} else {
|
|
326
|
+
cy.log("Expected error message not found:", errorMessage);
|
|
327
|
+
cy.get('[class*="text-danger"], [class*="text-red"], [class*="error"]').then(($errors) => {
|
|
328
|
+
cy.log("Found validation errors:", $errors.length);
|
|
329
|
+
$errors.each((index, error) => {
|
|
330
|
+
cy.log(`Error ${index}:`, error.textContent);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
cy.contains(errorMessage).should("be.visible");
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
return cy.get("form");
|
|
338
|
+
}
|
|
339
|
+
function resetForm() {
|
|
340
|
+
return cy.get("body").then(($body) => {
|
|
341
|
+
if ($body.find(HERO_UI_SELECTORS.button.reset).length > 0) {
|
|
342
|
+
return cy.get(HERO_UI_SELECTORS.button.reset).click();
|
|
343
|
+
}
|
|
344
|
+
return cy.get("input, textarea").each(($el) => {
|
|
345
|
+
cy.wrap($el).clear();
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
function interceptFormSubmission(method, url, alias) {
|
|
350
|
+
cy.intercept(method, url).as(alias);
|
|
351
|
+
return cy.get(HERO_UI_SELECTORS.button.submit).first().click();
|
|
352
|
+
}
|
|
353
|
+
function verifyFormExists() {
|
|
354
|
+
return cy.get("form").should("exist");
|
|
355
|
+
}
|
|
356
|
+
function verifyFieldExists(selector) {
|
|
357
|
+
return cy.get(selector).should("exist");
|
|
358
|
+
}
|
|
359
|
+
function verifyFieldValue(type, value, index = 0) {
|
|
360
|
+
const selector = type === "textarea" ? buildHeroUISelector("textarea") : buildHeroUISelector("input", type);
|
|
361
|
+
const element = index > 0 ? cy.get(selector).eq(index) : cy.get(selector).first();
|
|
362
|
+
return element.should("have.value", value);
|
|
363
|
+
}
|
|
364
|
+
function verifyFieldCount(selector, count) {
|
|
365
|
+
return cy.get(selector).filter(":visible").not('[type="hidden"]').should("have.length", count);
|
|
366
|
+
}
|
|
367
|
+
function getFormData() {
|
|
368
|
+
return extractFormData();
|
|
369
|
+
}
|
|
370
|
+
function fillCompleteForm(formData) {
|
|
371
|
+
return cy.then(() => {
|
|
372
|
+
Object.entries(formData).forEach(([key, value]) => {
|
|
373
|
+
if (value === null || value === void 0) return;
|
|
374
|
+
const fieldType = detectFieldType(value);
|
|
375
|
+
switch (fieldType) {
|
|
376
|
+
case "text":
|
|
377
|
+
case "email":
|
|
378
|
+
case "tel":
|
|
379
|
+
case "password":
|
|
380
|
+
case "number":
|
|
381
|
+
fillInputByType(fieldType, String(value));
|
|
382
|
+
break;
|
|
383
|
+
case "checkbox":
|
|
384
|
+
if (value) {
|
|
385
|
+
checkCheckbox();
|
|
386
|
+
}
|
|
387
|
+
break;
|
|
388
|
+
default:
|
|
389
|
+
cy.get("body").then(($body) => {
|
|
390
|
+
if ($body.find(`label:contains("${key}")`).length > 0) {
|
|
391
|
+
fillInputByLabel(key, String(value));
|
|
392
|
+
} else {
|
|
393
|
+
fillInputByType("text", String(value));
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
return cy.get("form");
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
function testFieldInteraction(fieldType, value) {
|
|
402
|
+
const selector = buildHeroUISelector("input", fieldType);
|
|
403
|
+
return cy.get(selector).first().clear().type(value).should("have.value", value);
|
|
404
|
+
}
|
|
405
|
+
function testFormFlow(steps) {
|
|
406
|
+
return cy.then(() => {
|
|
407
|
+
steps.forEach((step, index) => {
|
|
408
|
+
cy.log(`Executing step ${index + 1}: ${step.type}`);
|
|
409
|
+
switch (step.type) {
|
|
410
|
+
case "fill":
|
|
411
|
+
if (step.field && step.value) {
|
|
412
|
+
fillInputByLabel(step.field, String(step.value));
|
|
413
|
+
}
|
|
414
|
+
break;
|
|
415
|
+
case "select":
|
|
416
|
+
if (step.field && step.value) {
|
|
417
|
+
selectDropdownByLabel(step.field, String(step.value));
|
|
418
|
+
}
|
|
419
|
+
break;
|
|
420
|
+
case "check":
|
|
421
|
+
if (step.field) {
|
|
422
|
+
checkCheckboxByLabel(step.field);
|
|
423
|
+
}
|
|
424
|
+
break;
|
|
425
|
+
case "uncheck":
|
|
426
|
+
if (step.field) {
|
|
427
|
+
cy.contains("label", step.field).closest("div").find(HERO_UI_SELECTORS.checkbox.input).uncheck();
|
|
428
|
+
}
|
|
429
|
+
break;
|
|
430
|
+
case "submit":
|
|
431
|
+
submitForm();
|
|
432
|
+
break;
|
|
433
|
+
case "wait":
|
|
434
|
+
if (step.waitTime) {
|
|
435
|
+
cy.wait(step.waitTime);
|
|
436
|
+
}
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
if (step.expect) {
|
|
440
|
+
cy.get("body").should("contain", step.expect);
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
return cy.get("form");
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
function testRealTimeValidation(fieldLabel, invalidValue, expectedError) {
|
|
447
|
+
fillInputByLabel(fieldLabel, invalidValue);
|
|
448
|
+
cy.contains("label", fieldLabel).closest("div").find("input, textarea, select").blur();
|
|
449
|
+
if (expectedError) {
|
|
450
|
+
return expectFieldError(fieldLabel, expectedError);
|
|
451
|
+
} else {
|
|
452
|
+
return expectFieldError(fieldLabel, "This field is required");
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
function testRequiredFieldValidation(fieldLabel, expectedError) {
|
|
456
|
+
cy.contains("label", fieldLabel).closest("div").find("input, textarea, select").clear().blur();
|
|
457
|
+
if (expectedError) {
|
|
458
|
+
return expectFieldError(fieldLabel, expectedError);
|
|
459
|
+
} else {
|
|
460
|
+
return expectFieldError(fieldLabel, "This field is required");
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
function testEmailValidation(email, shouldBeValid) {
|
|
464
|
+
cy.get('input[type="email"]').first().clear().type(email).blur();
|
|
465
|
+
if (shouldBeValid) {
|
|
466
|
+
return expectFieldValid("Email");
|
|
467
|
+
} else {
|
|
468
|
+
return expectFieldError("Email");
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
function testPhoneValidation(phone, shouldBeValid) {
|
|
472
|
+
cy.get('input[type="tel"]').first().clear().type(phone).blur();
|
|
473
|
+
if (shouldBeValid) {
|
|
474
|
+
return expectFieldValid("Phone");
|
|
475
|
+
} else {
|
|
476
|
+
return expectFieldError("Phone");
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function testPasswordValidation(password, shouldBeValid) {
|
|
480
|
+
cy.get('input[type="password"]').first().clear().type(password).blur();
|
|
481
|
+
if (shouldBeValid) {
|
|
482
|
+
return expectFieldValid("Password");
|
|
483
|
+
} else {
|
|
484
|
+
return expectFieldError("Password");
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
function testRequiredFieldsValidation() {
|
|
488
|
+
submitForm();
|
|
489
|
+
cy.get("form").should("exist");
|
|
490
|
+
return expectValidationError("required") || expectValidationError("Required");
|
|
491
|
+
}
|
|
492
|
+
var formSubmissionHelpers, dynamicFormHelpers, performanceHelpers, typeInferenceHelpers;
|
|
493
|
+
var init_helpers = __esm({
|
|
494
|
+
"src/cypress/helpers.ts"() {
|
|
495
|
+
"use strict";
|
|
496
|
+
init_utils();
|
|
497
|
+
formSubmissionHelpers = {
|
|
498
|
+
/**
|
|
499
|
+
* Submit form and wait for success
|
|
500
|
+
*/
|
|
501
|
+
submitAndWaitForSuccess: (submitButtonText = "Submit") => {
|
|
502
|
+
cy.get('button[type="submit"]').contains(submitButtonText).click();
|
|
503
|
+
cy.get('button[type="submit"]').should("contain", "Submitting");
|
|
504
|
+
cy.get('button[type="submit"]').should("contain", "Success!");
|
|
505
|
+
},
|
|
506
|
+
/**
|
|
507
|
+
* Submit form and wait for error
|
|
508
|
+
*/
|
|
509
|
+
submitAndWaitForError: (submitButtonText = "Submit") => {
|
|
510
|
+
cy.get('button[type="submit"]').contains(submitButtonText).click();
|
|
511
|
+
cy.get('button[type="submit"]').should("contain", "Submitting");
|
|
512
|
+
cy.get('button[type="submit"]').should("contain", "Error");
|
|
513
|
+
},
|
|
514
|
+
/**
|
|
515
|
+
* Reset form to initial state
|
|
516
|
+
*/
|
|
517
|
+
resetForm: (resetButtonText = "Reset") => {
|
|
518
|
+
cy.get('button[type="button"]').contains(resetButtonText).click();
|
|
519
|
+
},
|
|
520
|
+
/**
|
|
521
|
+
* Wait for enhanced form status
|
|
522
|
+
*/
|
|
523
|
+
waitForFormStatus: (status) => {
|
|
524
|
+
if (status === "loading") {
|
|
525
|
+
cy.contains("Submitting form...").should("be.visible");
|
|
526
|
+
} else if (status === "success") {
|
|
527
|
+
cy.contains("Form submitted successfully!").should("be.visible");
|
|
528
|
+
} else if (status === "error") {
|
|
529
|
+
cy.contains("Error submitting form").should("be.visible");
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
/**
|
|
533
|
+
* Dismiss form status message
|
|
534
|
+
*/
|
|
535
|
+
dismissFormStatus: () => {
|
|
536
|
+
cy.get('button[aria-label*="Dismiss"]').click();
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
dynamicFormHelpers = {
|
|
540
|
+
/**
|
|
541
|
+
* Test conditional field visibility
|
|
542
|
+
*/
|
|
543
|
+
testConditionalField: (triggerField, triggerValue, conditionalFieldLabel) => {
|
|
544
|
+
fillInputByLabel(triggerField, triggerValue);
|
|
545
|
+
cy.contains("label", conditionalFieldLabel).should("be.visible");
|
|
546
|
+
},
|
|
547
|
+
/**
|
|
548
|
+
* Test conditional field hiding
|
|
549
|
+
*/
|
|
550
|
+
testConditionalFieldHidden: (triggerField, triggerValue, conditionalFieldLabel) => {
|
|
551
|
+
fillInputByLabel(triggerField, triggerValue);
|
|
552
|
+
cy.contains("label", conditionalFieldLabel).should("not.exist");
|
|
553
|
+
},
|
|
554
|
+
/**
|
|
555
|
+
* Add item to field array
|
|
556
|
+
*/
|
|
557
|
+
addFieldArrayItem: (addButtonText = "Add Item") => {
|
|
558
|
+
cy.get("button").contains(addButtonText).click();
|
|
559
|
+
},
|
|
560
|
+
/**
|
|
561
|
+
* Remove item from field array
|
|
562
|
+
*/
|
|
563
|
+
removeFieldArrayItem: (itemIndex = 0, removeButtonText = "Remove") => {
|
|
564
|
+
cy.get("button").contains(removeButtonText).eq(itemIndex).click();
|
|
565
|
+
},
|
|
566
|
+
/**
|
|
567
|
+
* Test field array limits
|
|
568
|
+
*/
|
|
569
|
+
testFieldArrayLimits: (min, max, addButtonText = "Add Item", removeButtonText = "Remove") => {
|
|
570
|
+
if (min > 0) {
|
|
571
|
+
cy.get("button").contains(removeButtonText).should("not.exist");
|
|
572
|
+
}
|
|
573
|
+
for (let i = 0; i < max; i++) {
|
|
574
|
+
cy.get("button").contains(addButtonText).click();
|
|
575
|
+
}
|
|
576
|
+
cy.get("button").contains(addButtonText).should("not.exist");
|
|
577
|
+
},
|
|
578
|
+
/**
|
|
579
|
+
* Test dynamic section visibility
|
|
580
|
+
*/
|
|
581
|
+
testDynamicSection: (triggerField, triggerValue, sectionTitle) => {
|
|
582
|
+
fillInputByLabel(triggerField, triggerValue);
|
|
583
|
+
cy.contains(sectionTitle).should("be.visible");
|
|
584
|
+
},
|
|
585
|
+
/**
|
|
586
|
+
* Test dynamic section hiding
|
|
587
|
+
*/
|
|
588
|
+
testDynamicSectionHidden: (triggerField, triggerValue, sectionTitle) => {
|
|
589
|
+
fillInputByLabel(triggerField, triggerValue);
|
|
590
|
+
cy.contains(sectionTitle).should("not.exist");
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
performanceHelpers = {
|
|
594
|
+
/**
|
|
595
|
+
* Test debounced validation
|
|
596
|
+
*/
|
|
597
|
+
testDebouncedValidation: (fieldLabel, value, delay = 300) => {
|
|
598
|
+
fillInputByLabel(fieldLabel, value);
|
|
599
|
+
cy.wait(delay);
|
|
600
|
+
cy.get("body").should("contain", "error");
|
|
601
|
+
},
|
|
602
|
+
/**
|
|
603
|
+
* Test form performance with many fields
|
|
604
|
+
*/
|
|
605
|
+
testFormPerformance: (fieldCount) => {
|
|
606
|
+
const startTime = Date.now();
|
|
607
|
+
for (let i = 0; i < fieldCount; i++) {
|
|
608
|
+
fillInputByType("text", `value${i}`);
|
|
609
|
+
}
|
|
610
|
+
const endTime = Date.now();
|
|
611
|
+
const duration = endTime - startTime;
|
|
612
|
+
cy.log(`Form with ${fieldCount} fields took ${duration}ms to fill`);
|
|
613
|
+
expect(duration).to.be.lessThan(5e3);
|
|
614
|
+
},
|
|
615
|
+
/**
|
|
616
|
+
* Test memoization by checking re-renders
|
|
617
|
+
*/
|
|
618
|
+
testMemoization: (componentName) => {
|
|
619
|
+
cy.log(`Testing memoization for ${componentName}`);
|
|
620
|
+
fillInputByType("text", "test");
|
|
621
|
+
cy.log("Memoization test completed");
|
|
622
|
+
},
|
|
623
|
+
/**
|
|
624
|
+
* Add field array item for testing
|
|
625
|
+
*/
|
|
626
|
+
addFieldArrayItem: (addButtonText = "Add Item") => {
|
|
627
|
+
cy.get("button").contains(addButtonText).click();
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
typeInferenceHelpers = {
|
|
631
|
+
/**
|
|
632
|
+
* Test auto-inferred form validation
|
|
633
|
+
*/
|
|
634
|
+
testInferredValidation: (fieldLabel, value, shouldBeValid) => {
|
|
635
|
+
fillInputByLabel(fieldLabel, value);
|
|
636
|
+
if (shouldBeValid) {
|
|
637
|
+
expectFieldValid(fieldLabel);
|
|
638
|
+
} else {
|
|
639
|
+
expectFieldError(fieldLabel);
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
/**
|
|
643
|
+
* Test cross-field validation
|
|
644
|
+
*/
|
|
645
|
+
testCrossFieldValidation: (field1, value1, field2, value2, shouldBeValid) => {
|
|
646
|
+
fillInputByLabel(field1, value1);
|
|
647
|
+
fillInputByLabel(field2, value2);
|
|
648
|
+
cy.get("input").first().blur();
|
|
649
|
+
if (shouldBeValid) {
|
|
650
|
+
expectNoValidationErrors();
|
|
651
|
+
} else {
|
|
652
|
+
expectValidationError("match");
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
/**
|
|
656
|
+
* Test password confirmation validation
|
|
657
|
+
*/
|
|
658
|
+
testPasswordConfirmation: (password, confirmPassword, shouldMatch) => {
|
|
659
|
+
fillInputByLabel("Password", password);
|
|
660
|
+
fillInputByLabel("Confirm Password", confirmPassword);
|
|
661
|
+
if (shouldMatch) {
|
|
662
|
+
expectNoValidationErrors();
|
|
663
|
+
} else {
|
|
664
|
+
expectValidationError("match");
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
// src/cypress/commands.ts
|
|
672
|
+
var commands_exports = {};
|
|
673
|
+
var init_commands = __esm({
|
|
674
|
+
"src/cypress/commands.ts"() {
|
|
675
|
+
"use strict";
|
|
676
|
+
init_helpers();
|
|
677
|
+
Cypress.Commands.add("fillInputByType", fillInputByType);
|
|
678
|
+
Cypress.Commands.add("fillInputByPlaceholder", fillInputByPlaceholder);
|
|
679
|
+
Cypress.Commands.add("fillInputByLabel", fillInputByLabel);
|
|
680
|
+
Cypress.Commands.add("fillTextarea", fillTextarea);
|
|
681
|
+
Cypress.Commands.add("selectDropdownOption", selectDropdownOption);
|
|
682
|
+
Cypress.Commands.add("selectDropdownByLabel", selectDropdownByLabel);
|
|
683
|
+
Cypress.Commands.add("checkCheckbox", checkCheckbox);
|
|
684
|
+
Cypress.Commands.add("checkCheckboxByLabel", checkCheckboxByLabel);
|
|
685
|
+
Cypress.Commands.add("checkSwitch", checkSwitch);
|
|
686
|
+
Cypress.Commands.add("uncheckCheckbox", uncheckCheckbox);
|
|
687
|
+
Cypress.Commands.add("uncheckSwitch", uncheckSwitch);
|
|
688
|
+
Cypress.Commands.add("moveSlider", moveSlider);
|
|
689
|
+
Cypress.Commands.add("expectValidationError", expectValidationError);
|
|
690
|
+
Cypress.Commands.add("expectNoValidationErrors", expectNoValidationErrors);
|
|
691
|
+
Cypress.Commands.add("expectFieldError", expectFieldError);
|
|
692
|
+
Cypress.Commands.add("expectFieldValid", expectFieldValid);
|
|
693
|
+
Cypress.Commands.add("triggerValidation", triggerValidation);
|
|
694
|
+
Cypress.Commands.add("submitAndExpectSuccess", submitAndExpectSuccess);
|
|
695
|
+
Cypress.Commands.add("submitAndExpectErrors", submitAndExpectErrors);
|
|
696
|
+
Cypress.Commands.add("verifyFormExists", verifyFormExists);
|
|
697
|
+
Cypress.Commands.add("verifyFieldExists", verifyFieldExists);
|
|
698
|
+
Cypress.Commands.add("verifyFieldValue", verifyFieldValue);
|
|
699
|
+
Cypress.Commands.add("verifyFieldCount", verifyFieldCount);
|
|
700
|
+
Cypress.Commands.add("getFormData", getFormData);
|
|
701
|
+
Cypress.Commands.add("fillCompleteForm", fillCompleteForm);
|
|
702
|
+
Cypress.Commands.add("testFieldInteraction", testFieldInteraction);
|
|
703
|
+
Cypress.Commands.add("testFormFlow", testFormFlow);
|
|
704
|
+
Cypress.Commands.add("submitForm", submitForm);
|
|
705
|
+
Cypress.Commands.add("resetForm", resetForm);
|
|
706
|
+
Cypress.Commands.add("interceptFormSubmission", interceptFormSubmission);
|
|
707
|
+
Cypress.Commands.add("fillField", fillInputByLabel);
|
|
708
|
+
Cypress.Commands.add("selectOption", selectDropdownByLabel);
|
|
709
|
+
Cypress.Commands.add("fillEmail", (value) => fillInputByType("email", value));
|
|
710
|
+
Cypress.Commands.add("fillPhone", (value) => fillInputByType("tel", value));
|
|
711
|
+
Cypress.Commands.add("fillPassword", (value) => fillInputByType("password", value));
|
|
712
|
+
Cypress.Commands.add("fillText", (value) => fillInputByType("text", value));
|
|
713
|
+
Cypress.Commands.add("logFormState", () => {
|
|
714
|
+
cy.get("form").then(($form) => {
|
|
715
|
+
const formData = {};
|
|
716
|
+
$form.find("input, textarea, select").each((index, element) => {
|
|
717
|
+
const $el = Cypress.$(element);
|
|
718
|
+
const name = $el.attr("name") || `field_${index}`;
|
|
719
|
+
const type = $el.attr("type") || element.tagName.toLowerCase();
|
|
720
|
+
const value = $el.val();
|
|
721
|
+
formData[name] = { type, value };
|
|
722
|
+
});
|
|
723
|
+
cy.log("Form state:", formData);
|
|
724
|
+
});
|
|
725
|
+
});
|
|
726
|
+
Cypress.Commands.add("waitForFormReady", () => {
|
|
727
|
+
cy.get("form").should("exist");
|
|
728
|
+
cy.get("input, textarea, select").should("be.visible");
|
|
729
|
+
});
|
|
730
|
+
Cypress.Commands.add("clearForm", () => {
|
|
731
|
+
cy.get("input, textarea").each(($el) => {
|
|
732
|
+
cy.wrap($el).clear();
|
|
733
|
+
});
|
|
734
|
+
});
|
|
735
|
+
Cypress.Commands.add("verifyFormValid", () => {
|
|
736
|
+
cy.get("form").should("exist");
|
|
737
|
+
cy.get("body").should("not.contain", "error");
|
|
738
|
+
cy.get("body").should("not.contain", "invalid");
|
|
739
|
+
});
|
|
740
|
+
Cypress.Commands.add("screenshotForm", (name) => {
|
|
741
|
+
const screenshotName = name || `form-${Date.now()}`;
|
|
742
|
+
cy.screenshot(screenshotName);
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
// src/cypress/index.ts
|
|
748
|
+
init_utils();
|
|
749
|
+
init_helpers();
|
|
750
|
+
function registerHeroFormCommands() {
|
|
751
|
+
init_commands();
|
|
752
|
+
}
|
|
753
|
+
var SETUP_INSTRUCTIONS = {
|
|
754
|
+
installation: "npm install @rachelallyson/hero-hook-form",
|
|
755
|
+
import: "import '@rachelallyson/hero-hook-form/cypress';",
|
|
756
|
+
usage: `
|
|
757
|
+
// Basic field interactions
|
|
758
|
+
cy.fillInputByType('email', 'test@example.com');
|
|
759
|
+
cy.fillInputByLabel('First Name', 'John');
|
|
760
|
+
cy.selectDropdownByLabel('Country', 'United States');
|
|
761
|
+
cy.checkCheckboxByLabel('Terms and Conditions');
|
|
762
|
+
|
|
763
|
+
// Form submission
|
|
764
|
+
cy.submitForm();
|
|
765
|
+
cy.submitAndExpectSuccess('Thank you for your submission');
|
|
766
|
+
|
|
767
|
+
// Validation testing
|
|
768
|
+
cy.expectValidationError('This field is required');
|
|
769
|
+
cy.expectNoValidationErrors();
|
|
770
|
+
|
|
771
|
+
// Complex form flows
|
|
772
|
+
cy.fillCompleteForm({
|
|
773
|
+
firstName: 'John',
|
|
774
|
+
lastName: 'Doe',
|
|
775
|
+
email: 'john@example.com',
|
|
776
|
+
country: 'United States',
|
|
777
|
+
agreeToTerms: true
|
|
778
|
+
});
|
|
779
|
+
`
|
|
780
|
+
};
|
|
781
|
+
var COMMANDS_REFERENCE = {
|
|
782
|
+
fieldInteractions: [
|
|
783
|
+
"fillInputByType(type, value, index?, options?)",
|
|
784
|
+
"fillInputByPlaceholder(placeholder, value, options?)",
|
|
785
|
+
"fillInputByLabel(label, value, options?)",
|
|
786
|
+
"fillTextarea(value, index?, options?)",
|
|
787
|
+
"selectDropdownOption(optionValue, dropdownIndex?)",
|
|
788
|
+
"selectDropdownByLabel(label, optionValue)",
|
|
789
|
+
"checkCheckbox(index?)",
|
|
790
|
+
"checkCheckboxByLabel(label)",
|
|
791
|
+
"checkSwitch(index?)",
|
|
792
|
+
"uncheckCheckbox(index?)",
|
|
793
|
+
"uncheckSwitch(index?)",
|
|
794
|
+
"moveSlider(value, index?)"
|
|
795
|
+
],
|
|
796
|
+
validation: [
|
|
797
|
+
"expectValidationError(message)",
|
|
798
|
+
"expectNoValidationErrors()",
|
|
799
|
+
"expectFieldError(fieldLabel, errorMessage)",
|
|
800
|
+
"expectFieldValid(fieldLabel)",
|
|
801
|
+
"triggerValidation(submitButton?)"
|
|
802
|
+
],
|
|
803
|
+
submission: [
|
|
804
|
+
"submitForm()",
|
|
805
|
+
"submitAndExpectSuccess(successIndicator?)",
|
|
806
|
+
"submitAndExpectErrors()",
|
|
807
|
+
"resetForm()",
|
|
808
|
+
"interceptFormSubmission(method, url, alias)"
|
|
809
|
+
],
|
|
810
|
+
state: [
|
|
811
|
+
"verifyFormExists()",
|
|
812
|
+
"verifyFieldExists(selector)",
|
|
813
|
+
"verifyFieldValue(selector, value)",
|
|
814
|
+
"verifyFieldCount(selector, count)",
|
|
815
|
+
"getFormData()"
|
|
816
|
+
],
|
|
817
|
+
complex: [
|
|
818
|
+
"fillCompleteForm(formData)",
|
|
819
|
+
"testFieldInteraction(fieldType, value)",
|
|
820
|
+
"testFormFlow(steps)"
|
|
821
|
+
],
|
|
822
|
+
convenience: [
|
|
823
|
+
"fillEmail(value)",
|
|
824
|
+
"fillPhone(value)",
|
|
825
|
+
"fillPassword(value)",
|
|
826
|
+
"fillText(value)"
|
|
827
|
+
],
|
|
828
|
+
debug: [
|
|
829
|
+
"logFormState()",
|
|
830
|
+
"waitForFormReady()",
|
|
831
|
+
"clearForm()",
|
|
832
|
+
"verifyFormValid()",
|
|
833
|
+
"screenshotForm(name?)"
|
|
834
|
+
]
|
|
835
|
+
};
|
|
836
|
+
if (typeof Cypress !== "undefined") {
|
|
837
|
+
registerHeroFormCommands();
|
|
838
|
+
}
|
|
839
|
+
export {
|
|
840
|
+
COMMANDS_REFERENCE,
|
|
841
|
+
DEFAULT_CONFIG,
|
|
842
|
+
HERO_UI_SELECTORS,
|
|
843
|
+
SETUP_INSTRUCTIONS,
|
|
844
|
+
buildHeroUISelector,
|
|
845
|
+
checkCheckbox,
|
|
846
|
+
checkCheckboxByLabel,
|
|
847
|
+
checkSwitch,
|
|
848
|
+
detectFieldType,
|
|
849
|
+
dynamicFormHelpers,
|
|
850
|
+
elementExists,
|
|
851
|
+
expectFieldError,
|
|
852
|
+
expectFieldValid,
|
|
853
|
+
expectNoValidationErrors,
|
|
854
|
+
expectValidationError,
|
|
855
|
+
extractFormData,
|
|
856
|
+
fillCompleteForm,
|
|
857
|
+
fillInputByLabel,
|
|
858
|
+
fillInputByPlaceholder,
|
|
859
|
+
fillInputByType,
|
|
860
|
+
fillTextarea,
|
|
861
|
+
findFieldByLabel,
|
|
862
|
+
findFieldByPlaceholder,
|
|
863
|
+
findFieldByType,
|
|
864
|
+
forceClickWithRetry,
|
|
865
|
+
formSubmissionHelpers,
|
|
866
|
+
getFormData,
|
|
867
|
+
interceptFormSubmission,
|
|
868
|
+
logFormState,
|
|
869
|
+
moveSlider,
|
|
870
|
+
performanceHelpers,
|
|
871
|
+
registerHeroFormCommands,
|
|
872
|
+
resetForm,
|
|
873
|
+
selectDropdownByLabel,
|
|
874
|
+
selectDropdownOption,
|
|
875
|
+
submitAndExpectErrors,
|
|
876
|
+
submitAndExpectSuccess,
|
|
877
|
+
submitForm,
|
|
878
|
+
testEmailValidation,
|
|
879
|
+
testFieldInteraction,
|
|
880
|
+
testFormFlow,
|
|
881
|
+
testPasswordValidation,
|
|
882
|
+
testPhoneValidation,
|
|
883
|
+
testRealTimeValidation,
|
|
884
|
+
testRequiredFieldValidation,
|
|
885
|
+
testRequiredFieldsValidation,
|
|
886
|
+
triggerValidation,
|
|
887
|
+
typeInferenceHelpers,
|
|
888
|
+
typeWithClear,
|
|
889
|
+
uncheckCheckbox,
|
|
890
|
+
uncheckSwitch,
|
|
891
|
+
verifyFieldCount,
|
|
892
|
+
verifyFieldExists,
|
|
893
|
+
verifyFieldValue,
|
|
894
|
+
verifyFormExists,
|
|
895
|
+
waitForStable,
|
|
896
|
+
withRetry
|
|
897
|
+
};
|