@rachelallyson/hero-hook-form 1.2.0 → 2.1.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.
@@ -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
+ };