@protontech/autofill 0.0.35481761 → 0.0.36026908

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.
Files changed (47) hide show
  1. package/features/v1/abstract.field.d.ts +38 -38
  2. package/features/v1/field-predicates.d.ts +8 -0
  3. package/features/v1/field-predicates.js +42 -0
  4. package/features/v1/field.email.d.ts +1169 -1169
  5. package/features/v1/field.otp.d.ts +23826 -23826
  6. package/features/v1/field.password.d.ts +33195 -33195
  7. package/features/v1/field.username-hidden.d.ts +337 -337
  8. package/features/v1/field.username.d.ts +14189 -14189
  9. package/features/v1/fields.sorted.gen.d.ts +482 -482
  10. package/features/v1/forms.sorted.gen.d.ts +245 -245
  11. package/features/v1/index.d.ts +1772 -1772
  12. package/models/perceptron/params/email-model.json +4 -4
  13. package/models/perceptron/params/login-model.json +84 -84
  14. package/models/perceptron/params/new-password-model.json +16 -16
  15. package/models/perceptron/params/otp-model.json +25 -25
  16. package/models/perceptron/params/password-change-model.json +74 -74
  17. package/models/perceptron/params/password-model.json +19 -19
  18. package/models/perceptron/params/recovery-model.json +82 -82
  19. package/models/perceptron/params/register-model.json +97 -97
  20. package/models/perceptron/params/username-hidden-model.json +8 -8
  21. package/models/perceptron/params/username-model.json +6 -6
  22. package/package.json +3 -3
  23. package/rules/v1/index.js +3 -3
  24. package/utils/credit-card.d.ts +0 -1
  25. package/utils/credit-card.js +2 -9
  26. package/utils/field.d.ts +4 -5
  27. package/utils/field.js +6 -17
  28. package/utils/identity.d.ts +0 -2
  29. package/utils/identity.js +2 -23
  30. package/dictionary/generate.d.ts +0 -1
  31. package/dictionary/generate.js +0 -51
  32. package/features/feature.spec.d.ts +0 -1
  33. package/features/feature.spec.js +0 -108
  34. package/features/v1/index.spec.d.ts +0 -1
  35. package/features/v1/index.spec.js +0 -44
  36. package/scripts/gen-sorted-features.d.ts +0 -1
  37. package/scripts/gen-sorted-features.js +0 -128
  38. package/utils/credit-card.samples.spec.d.ts +0 -1
  39. package/utils/credit-card.samples.spec.js +0 -452
  40. package/utils/credit-card.spec.d.ts +0 -1
  41. package/utils/credit-card.spec.js +0 -296
  42. package/utils/identity.samples.spec.d.ts +0 -1
  43. package/utils/identity.samples.spec.js +0 -28
  44. package/utils/re.spec.d.ts +0 -1
  45. package/utils/re.spec.js +0 -62
  46. package/utils/shadow-dom.spec.d.ts +0 -1
  47. package/utils/shadow-dom.spec.js +0 -215
@@ -1 +0,0 @@
1
- export {};
@@ -1,296 +0,0 @@
1
- import { formatExpirationDate, getExpirationFormat, getInputExpirationMonthFormat, getSelectExpirationMonthFormat, getSelectExpirationYearFormat } from "./credit-card";
2
- Object.defineProperty(HTMLElement.prototype, "innerText", {
3
- get() {
4
- return this.textContent;
5
- },
6
- });
7
- describe("CC Expiration Detection", () => {
8
- afterEach(() => {
9
- document.body.innerHTML = "";
10
- });
11
- describe("Pattern Detection", () => {
12
- test.each([
13
- { pattern: "\\d{2}/\\d{2}", expected: { separator: "/", fullYear: false, monthFirst: true } },
14
- { pattern: "[0-9]{2}/[0-9]{2}", expected: { separator: "/", fullYear: false, monthFirst: true } },
15
- { pattern: "(0[1-9]|1[0-2])\\/[0-9]{2}", expected: { separator: "/", fullYear: false, monthFirst: true } },
16
- { pattern: "\\d{2}/\\d{4}", expected: { separator: "/", fullYear: true, monthFirst: true } },
17
- { pattern: "[0-9]{2}/[0-9]{4}", expected: { separator: "/", fullYear: true, monthFirst: true } },
18
- { pattern: "(0[1-9]|1[0-2])\\/[0-9]{4}", expected: { separator: "/", fullYear: true, monthFirst: true } },
19
- { pattern: "\\d{2}-\\d{2}", expected: { separator: "-", fullYear: false, monthFirst: true } },
20
- { pattern: "[0-9]{2}-[0-9]{2}", expected: { separator: "-", fullYear: false, monthFirst: true } },
21
- { pattern: "\\d{2}-\\d{4}", expected: { separator: "-", fullYear: true, monthFirst: true } },
22
- { pattern: "[0-9]{2}-[0-9]{4}", expected: { separator: "-", fullYear: true, monthFirst: true } },
23
- { pattern: "\\d{4}", expected: { separator: "", fullYear: false, monthFirst: true } },
24
- { pattern: "[0-9]{4}", expected: { separator: "", fullYear: false, monthFirst: true } },
25
- { pattern: "\\d{6}", expected: { separator: "", fullYear: true, monthFirst: true } },
26
- { pattern: "[0-9]{6}", expected: { separator: "", fullYear: true, monthFirst: true } },
27
- { pattern: "\\d{2}/\\d{2}", expected: { separator: "/", fullYear: false, monthFirst: true } },
28
- ])("should detect pattern $pattern", ({ pattern, expected }) => {
29
- const input = document.createElement("input");
30
- input.pattern = pattern;
31
- expect(getExpirationFormat(input)).toEqual(expected);
32
- });
33
- test.each([{ pattern: "[invalid regex" }, { pattern: "*+?" }, { pattern: "(" }, { pattern: "[" }])("should handle invalid regex pattern: $pattern", ({ pattern }) => {
34
- const input = document.createElement("input");
35
- input.pattern = pattern;
36
- expect(getExpirationFormat(input)).toEqual({ separator: "/", fullYear: false, monthFirst: true });
37
- });
38
- });
39
- describe("MaxLength Detection", () => {
40
- test.each([
41
- { maxLength: 4, expected: { separator: "", fullYear: false, monthFirst: true } },
42
- { maxLength: 5, expected: { separator: "/", fullYear: false, monthFirst: true } },
43
- { maxLength: 6, expected: { separator: "", fullYear: true, monthFirst: true } },
44
- { maxLength: 7, expected: { separator: "/", fullYear: true, monthFirst: true } },
45
- ])("should detect maxLength $maxLength", ({ maxLength, expected }) => {
46
- const input = document.createElement("input");
47
- input.maxLength = maxLength;
48
- const result = getExpirationFormat(input);
49
- expect(result).toEqual(expected);
50
- });
51
- test.each([{ maxLength: 1 }, { maxLength: 2 }, { maxLength: 3 }, { maxLength: 8 }, { maxLength: 10 }])("should return default for unmapped maxLength: $maxLength", ({ maxLength }) => {
52
- const input = document.createElement("input");
53
- input.maxLength = maxLength;
54
- expect(getExpirationFormat(input)).toEqual({ separator: "/", fullYear: false, monthFirst: true });
55
- });
56
- });
57
- describe("Attribute Detection", () => {
58
- test.each([
59
- { attr: "placeholder", value: "MM/YY", expected: { separator: "/", fullYear: false, monthFirst: true } },
60
- { attr: "placeholder", value: "MM/YYYY", expected: { separator: "/", fullYear: true, monthFirst: true } },
61
- { attr: "placeholder", value: "MM-YY", expected: { separator: "-", fullYear: false, monthFirst: true } },
62
- { attr: "placeholder", value: "MM-YYYY", expected: { separator: "-", fullYear: true, monthFirst: true } },
63
- { attr: "placeholder", value: "MM YY", expected: { separator: "", fullYear: false, monthFirst: true } },
64
- { attr: "placeholder", value: "MM YYYY", expected: { separator: "", fullYear: true, monthFirst: true } },
65
- { attr: "placeholder", value: "MMYY", expected: { separator: "", fullYear: false, monthFirst: true } },
66
- { attr: "placeholder", value: "MMYYYY", expected: { separator: "", fullYear: true, monthFirst: true } },
67
- { attr: "placeholder", value: "YY/MM", expected: { separator: "/", fullYear: false, monthFirst: false } },
68
- { attr: "placeholder", value: "YYYY/MM", expected: { separator: "/", fullYear: true, monthFirst: false } },
69
- { attr: "placeholder", value: "YY-MM", expected: { separator: "-", fullYear: false, monthFirst: false } },
70
- { attr: "placeholder", value: "YYYY-MM", expected: { separator: "-", fullYear: true, monthFirst: false } },
71
- { attr: "placeholder", value: "YY MM", expected: { separator: "", fullYear: false, monthFirst: false } },
72
- { attr: "placeholder", value: "YYYY MM", expected: { separator: "", fullYear: true, monthFirst: false } },
73
- { attr: "placeholder", value: "YYMM", expected: { separator: "", fullYear: false, monthFirst: false } },
74
- { attr: "placeholder", value: "YYYYMM", expected: { separator: "", fullYear: true, monthFirst: false } },
75
- { attr: "placeholder", value: "MM/AA", expected: { separator: "/", fullYear: false, monthFirst: true } },
76
- { attr: "placeholder", value: "MM/AAAA", expected: { separator: "/", fullYear: true, monthFirst: true } },
77
- { attr: "placeholder", value: "AA/MM", expected: { separator: "/", fullYear: false, monthFirst: false } },
78
- { attr: "placeholder", value: "AAAA/MM", expected: { separator: "/", fullYear: true, monthFirst: false } },
79
- { attr: "name", value: "exp-mm-yyyy", expected: { separator: "-", fullYear: true, monthFirst: true } },
80
- { attr: "id", value: "cardExpMmYy", expected: { separator: "", fullYear: false, monthFirst: true } },
81
- { attr: "className", value: "exp-field mm/yyyy-format", expected: { separator: "/", fullYear: true, monthFirst: true } },
82
- ])('should detect $attr="$value"', ({ attr, value, expected }) => {
83
- const input = document.createElement("input");
84
- if (attr === "className")
85
- input.className = value;
86
- else
87
- input.setAttribute(attr, value);
88
- expect(getExpirationFormat(input)).toEqual(expected);
89
- });
90
- test.each([{ value: "Enter expiration MM/YY date" }, { value: "Card expires MM/YYYY" }, { value: "exp_field_mm_yyyy_format" }, { value: "EXPIRY DATE (MM/YY)" }, { value: "Please enter MM-YYYY" }])('should detect format in mixed text: "$value"', ({ value }) => {
91
- const input = document.createElement("input");
92
- input.placeholder = value;
93
- const result = getExpirationFormat(input);
94
- expect(result === null || result === void 0 ? void 0 : result.separator).toBeDefined();
95
- expect(result === null || result === void 0 ? void 0 : result.fullYear).toBeDefined();
96
- expect(result === null || result === void 0 ? void 0 : result.monthFirst).toBeDefined();
97
- });
98
- test.each([{ value: "email@example.com" }, { value: "Enter your name" }, { value: "Phone number" }, { value: "Address line 1" }, { value: "" }, { value: "XYZZYX" }])('should return default for non-expiry text: "$value"', ({ value }) => {
99
- const input = document.createElement("input");
100
- input.placeholder = value;
101
- const result = getExpirationFormat(input);
102
- expect(result).toEqual({ separator: "/", fullYear: false, monthFirst: true });
103
- });
104
- });
105
- describe("getExpirationFormat - Priority Order", () => {
106
- test("should prioritize attributes over pattern", () => {
107
- const input = document.createElement("input");
108
- input.placeholder = "MM-YYYY";
109
- input.pattern = "\\d{2}/\\d{2}";
110
- const result = getExpirationFormat(input);
111
- expect(result).toEqual({ separator: "-", fullYear: true, monthFirst: true });
112
- });
113
- test("should prioritize pattern over maxLength", () => {
114
- const input = document.createElement("input");
115
- input.pattern = "\\d{2}-\\d{4}";
116
- input.maxLength = 5;
117
- const result = getExpirationFormat(input);
118
- expect(result).toEqual({ separator: "-", fullYear: true, monthFirst: true });
119
- });
120
- test("should use maxLength when no attributes or pattern", () => {
121
- const input = document.createElement("input");
122
- input.maxLength = 7;
123
- const result = getExpirationFormat(input);
124
- expect(result).toEqual({ separator: "/", fullYear: true, monthFirst: true });
125
- });
126
- test("should use default when no indicators present", () => {
127
- const input = document.createElement("input");
128
- const result = getExpirationFormat(input);
129
- expect(result).toEqual({ separator: "/", fullYear: false, monthFirst: true });
130
- });
131
- test("should handle outliers", () => {
132
- const input = document.createElement("input");
133
- input.pattern = "[-+]?[0-9]*[.,]?[0-9]+";
134
- input.maxLength = 2;
135
- input.autocomplete = "cc-exp-month";
136
- input.ariaLabel = "month";
137
- const result = getExpirationFormat(input, false);
138
- expect(result).toEqual(undefined);
139
- });
140
- test("coursera.org > cc-exp format", () => {
141
- document.body.innerHTML = `<div data-field="expiry" class="p-Field"><label class="p-FieldLabel Label Label--empty" for="Field-expiryInput">Expiration date<span class="FadeWrapper"></span><span class="u-visually-hidden"> MM / YY</span></label><div><div><div class="p-Input"><input dir="ltr" type="text" inputmode="numeric" name="expiry" id="Field-expiryInput" placeholder="MM / YY" autocomplete="cc-exp" aria-invalid="false" aria-describedby="Field-expiryError" aria-required="true" class="p-Input-input p-Fieldset-input Input Input--empty p-Input-input--textRight" value=""></div></div></div><div class="AnimateSinglePresence"></div></div>`;
142
- const field = document.querySelector("select, input");
143
- expect(getExpirationFormat(field, true)).toEqual({ fullYear: false, monthFirst: true, separator: "/" });
144
- });
145
- });
146
- describe("getInputExpirationMonthFormat", () => {
147
- test("tesco.com > padded cc-exp-month", () => {
148
- document.body.innerHTML = `<fieldset class="Form__Fieldset-sc-1rpc86b-1 fKhXDo"><legend class="Label-sc-1wdkkfu-0 cEywXb ddl-label has-error">Expiry date</legend><label for="card-expiry-month" hidden="" class="Label-sc-1wdkkfu-0 mZWly sf-hidden">month</label><input type="tel" data-auto="card-expiry-month" name="expiryMonth" id="card-expiry-month" placeholder="MM" maxlength="2" aria-required="true" data-rule="expiryMonthRule" class="Input-sc-gj7hrn-1 expiry-date__ExpiryInput-sc-m6yl5f-0 bSmREw eDVddD has-error" data-errored="true" value="1"><span aria-hidden="true" class="expiry-date__ExpirySeparator-sc-m6yl5f-1 huzqtm">/</span></div></fieldset>`;
149
- const field = document.querySelector("select, input");
150
- expect(getInputExpirationMonthFormat(field)).toEqual({ padding: true });
151
- });
152
- test("orange.md > padded cc-exp-month", () => {
153
- document.body.innerHTML = `<input name="validMONTH" id="expmonth" class="exp-input numberOnly" maxlength="2" tabindex="1" type="tel" placeholder="LL" required="" style="margin-right:10px" value="">`;
154
- const field = document.querySelector("select, input");
155
- expect(getInputExpirationMonthFormat(field)).toEqual({ padding: true });
156
- });
157
- test("iticket.md > padded cc-exp-month", () => {
158
- document.body.innerHTML = `<div class="col-xs-6"><input name="validMONTH" id="expmonth" type="text" size="7" maxlength="2" autocomplete="off" pattern="\d*" value="1" placeholder="LL"><div class="image-help" style="display:none"></div></div>`;
159
- const field = document.querySelector("select, input");
160
- expect(getInputExpirationMonthFormat(field)).toEqual({ padding: true });
161
- });
162
- });
163
- describe("formatExpirationDate", () => {
164
- test.each([
165
- { month: "01", year: "2025", format: { separator: "/", fullYear: false, monthFirst: true }, expected: "01/25" },
166
- { month: "12", year: "2025", format: { separator: "-", fullYear: false, monthFirst: true }, expected: "12-25" },
167
- { month: "03", year: "2025", format: { separator: "", fullYear: false, monthFirst: true }, expected: "0325" },
168
- { month: "01", year: "2025", format: { separator: "/", fullYear: true, monthFirst: true }, expected: "01/2025" },
169
- { month: "12", year: "2025", format: { separator: "-", fullYear: true, monthFirst: true }, expected: "12-2025" },
170
- { month: "03", year: "2025", format: { separator: "", fullYear: true, monthFirst: true }, expected: "032025" },
171
- { month: "01", year: "2025", format: { separator: "/", fullYear: false, monthFirst: false }, expected: "25/01" },
172
- { month: "12", year: "2025", format: { separator: "-", fullYear: false, monthFirst: false }, expected: "25-12" },
173
- { month: "03", year: "2025", format: { separator: "", fullYear: false, monthFirst: false }, expected: "2503" },
174
- { month: "01", year: "2025", format: { separator: "/", fullYear: true, monthFirst: false }, expected: "2025/01" },
175
- { month: "12", year: "2025", format: { separator: "-", fullYear: true, monthFirst: false }, expected: "2025-12" },
176
- { month: "03", year: "2025", format: { separator: "", fullYear: true, monthFirst: false }, expected: "202503" },
177
- ])('should format month="$month" year="$year" with format=$format.separator$format.yearDigits$format.monthFirst to "$expected"', ({ month, year, format, expected }) => {
178
- const result = formatExpirationDate(month, year, format);
179
- expect(result).toBe(expected);
180
- });
181
- test.each([
182
- { month: "1", year: "2025", format: { separator: "/", fullYear: false, monthFirst: true }, expected: "01/25" },
183
- { month: "2", year: "2025", format: { separator: "/", fullYear: false, monthFirst: true }, expected: "02/25" },
184
- { month: "9", year: "2025", format: { separator: "/", fullYear: false, monthFirst: true }, expected: "09/25" },
185
- { month: "10", year: "2025", format: { separator: "/", fullYear: false, monthFirst: true }, expected: "10/25" },
186
- { month: "11", year: "2025", format: { separator: "/", fullYear: false, monthFirst: true }, expected: "11/25" },
187
- { month: "12", year: "2025", format: { separator: "/", fullYear: false, monthFirst: true }, expected: "12/25" },
188
- ])('should pad single digit month "$month" to two digits', ({ month, year, format, expected }) => {
189
- const result = formatExpirationDate(month, year, format);
190
- expect(result).toBe(expected);
191
- });
192
- test.each([
193
- { year: "2020", expected: "20" },
194
- { year: "2025", expected: "25" },
195
- { year: "2030", expected: "30" },
196
- { year: "2099", expected: "99" },
197
- { year: "2000", expected: "00" },
198
- { year: "2001", expected: "01" },
199
- ])('should extract last 2 digits from 4-digit year "$year"', ({ year, expected }) => {
200
- const format = { separator: "/", fullYear: false, monthFirst: true };
201
- const result = formatExpirationDate("01", year, format);
202
- expect(result).toBe(`01/${expected}`);
203
- });
204
- test.each([
205
- { year: "2020", expected: "2020" },
206
- { year: "2025", expected: "2025" },
207
- { year: "2030", expected: "2030" },
208
- { year: "2099", expected: "2099" },
209
- ])('should keep all 4 digits for 4-digit year format "$year"', ({ year, expected }) => {
210
- const format = { separator: "/", fullYear: true, monthFirst: true };
211
- const result = formatExpirationDate("01", year, format);
212
- expect(result).toBe(`01/${expected}`);
213
- });
214
- });
215
- describe("Edge Cases and Integration", () => {
216
- test("should handle case-insensitive attribute detection", () => {
217
- const input = document.createElement("input");
218
- input.placeholder = "mm/yyyy";
219
- const result = getExpirationFormat(input);
220
- expect(result).toEqual({ separator: "/", fullYear: true, monthFirst: true });
221
- });
222
- test("should combine multiple attributes", () => {
223
- const input = document.createElement("input");
224
- input.name = "expiry";
225
- input.className = "mm-yyyy-format";
226
- input.placeholder = "Enter MM-YYYY";
227
- const result = getExpirationFormat(input);
228
- expect(result === null || result === void 0 ? void 0 : result.separator).toBe("-");
229
- expect(result === null || result === void 0 ? void 0 : result.fullYear).toBe(true);
230
- expect(result === null || result === void 0 ? void 0 : result.monthFirst).toBe(true);
231
- });
232
- test("should handle whitespace in attributes", () => {
233
- const input = document.createElement("input");
234
- input.placeholder = " MM / YYYY ";
235
- const result = getExpirationFormat(input);
236
- expect(result === null || result === void 0 ? void 0 : result.separator).toBe("/");
237
- });
238
- test("should prefer first match when multiple formats present", () => {
239
- const input = document.createElement("input");
240
- input.placeholder = "MM/YY or MM-YYYY";
241
- const result = getExpirationFormat(input);
242
- expect(result === null || result === void 0 ? void 0 : result.separator).toBe("/");
243
- expect(result === null || result === void 0 ? void 0 : result.fullYear).toBe(false);
244
- });
245
- });
246
- describe("getSelectExpirationYearFormat", () => {
247
- test.each([
248
- { options: ["2024", "2025", "2026"], expected: { fullYear: true } },
249
- { options: ["2023", "2024", "2025", "2026", "2027"], expected: { fullYear: true } },
250
- { options: ["24", "25", "26"], expected: { fullYear: false } },
251
- { options: ["23", "24", "25", "26", "27"], expected: { fullYear: false } },
252
- ])("should detect format from options $options", ({ options, expected }) => {
253
- const select = document.createElement("select");
254
- options.forEach((value) => {
255
- const option = document.createElement("option");
256
- option.value = value;
257
- select.appendChild(option);
258
- });
259
- expect(getSelectExpirationYearFormat(select)).toEqual(expected);
260
- });
261
- test.each([{ options: [] }, { options: ["", ""] }, { options: ["Select year", "Choose..."] }, { options: ["abc", "def"] }])("should noop for invalid options $options", ({ options }) => {
262
- const select = document.createElement("select");
263
- options.forEach((value) => {
264
- const option = document.createElement("option");
265
- option.value = value;
266
- select.appendChild(option);
267
- });
268
- expect(getSelectExpirationYearFormat(select)).toBeUndefined();
269
- });
270
- });
271
- describe("getSelectExpirationMonthFormat", () => {
272
- test.each([
273
- { options: ["01", "02", "03", "04", "05", "06"], expected: { padding: true } },
274
- { options: ["01", "09", "10", "11", "12"], expected: { padding: true } },
275
- { options: ["1", "2", "3", "4", "5", "6"], expected: { padding: false } },
276
- { options: ["1", "9", "10", "11", "12"], expected: { padding: false } },
277
- ])("should detect format from options $options", ({ options, expected }) => {
278
- const select = document.createElement("select");
279
- options.forEach((value) => {
280
- const option = document.createElement("option");
281
- option.value = value;
282
- select.appendChild(option);
283
- });
284
- expect(getSelectExpirationMonthFormat(select)).toEqual(expected);
285
- });
286
- test.each([{ options: [] }, { options: ["", ""] }, { options: ["Select month", "Choose..."] }, { options: ["abc", "def"] }])("should return noop for invalid options $options", ({ options }) => {
287
- const select = document.createElement("select");
288
- options.forEach((value) => {
289
- const option = document.createElement("option");
290
- option.value = value;
291
- select.appendChild(option);
292
- });
293
- expect(getSelectExpirationMonthFormat(select)).toBeUndefined();
294
- });
295
- });
296
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,28 +0,0 @@
1
- import { IdentityFieldType } from "@protontech/autofill/types";
2
- import { getIdentityFieldType } from "./identity";
3
- const fieldTest = (type, samples) => {
4
- test.each(samples.map((html) => ({ html, preview: html.substring(0, 42) })))("$preview", ({ html }) => {
5
- document.body.innerHTML = html;
6
- const field = document.querySelector("input");
7
- expect(getIdentityFieldType(field)).toBe(type);
8
- });
9
- };
10
- Object.defineProperty(HTMLElement.prototype, "innerText", {
11
- get() {
12
- return this.textContent;
13
- },
14
- });
15
- describe("Identity field samples", () => {
16
- describe("IdentityFieldType.FIRSTNAME", () => {
17
- const samples = [
18
- `<div class="sc-d9ebd515-0 hLmoFN"><label data-ignore-a11y="true" for="shipping_firstname" id="shipping_firstname-label" class="sc-94eb08bc-0 bfsAop sc-d9ebd515-1 dIGbxh">Nombre</label><input autocomplete="on" name="shipping_firstname" maxlength="50" id="shipping_firstname" type="text" aria-invalid="true" aria-required="false" aria-disabled="false" data-test="shipping_firstname" class="sc-7af5671c-1 boqXeD" value=""></div>`,
19
- ];
20
- fieldTest(IdentityFieldType.FIRSTNAME, samples);
21
- });
22
- describe.only("IdentityFieldType.TELEPHONE", () => {
23
- const samples = [
24
- `<div class="sc-d9ebd515-0 hLmoFN"><label data-ignore-a11y="true" for=":rp:" id=":rp:-label" class="sc-94eb08bc-0 dEnlRJ sc-d9ebd515-1 hfkVHI">Número de teléfono.</label><input name="shipping_phoneNumber" autocomplete="on" id=":rp:" placeholder="" type="tel" aria-invalid="true" aria-required="false" aria-disabled="false" aria-describedby=":rp:-help" data-test="shipping_phoneNumber" class="sc-7af5671c-2 iteJpf" value="+34 "></div>`,
25
- ];
26
- fieldTest(IdentityFieldType.TELEPHONE, samples);
27
- });
28
- });
@@ -1 +0,0 @@
1
- export {};
package/utils/re.spec.js DELETED
@@ -1,62 +0,0 @@
1
- import * as matchers from "./re";
2
- const getRandomString = (length) => {
3
- const charList = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+-={}[]|:;\"'<>,.?/~ `";
4
- return Array.from({ length }, () => charList.charAt(Math.floor(Math.random() * charList.length))).join("");
5
- };
6
- const executionTime = (cb) => {
7
- const start = performance.now();
8
- cb();
9
- return performance.now() - start;
10
- };
11
- const STR_TEST_LENGTHS = [25, 50, 100, 250, 500, 1000, 10000, 100000];
12
- const MAX_EXPECTED_REG_EXEC_TIME = 100;
13
- const MATCHERS = [
14
- "matchCaptcha",
15
- "matchConfirmAction",
16
- "matchCreateAction",
17
- "matchEmail",
18
- "matchEmailAttr",
19
- "matchEmailValue",
20
- "matchHidden",
21
- "matchLogin",
22
- "matchTwoFa",
23
- "matchMFA",
24
- "matchMultiStep",
25
- "matchNewsletter",
26
- "matchNewsletterAttr",
27
- "matchOAuth",
28
- "matchOtpAttr",
29
- "matchOtpOutlier",
30
- "matchPasswordConfirm",
31
- "matchPasswordCreate",
32
- "matchPasswordCreateAttr",
33
- "matchPasswordCurrent",
34
- "matchPasswordCurrentAttr",
35
- "matchPasswordOutlier",
36
- "matchPasswordReset",
37
- "matchPasswordResetAttr",
38
- "matchRecovery",
39
- "matchRegister",
40
- "matchRememberMe",
41
- "matchSearchAction",
42
- "matchStepAction",
43
- "matchTOS",
44
- "matchTel",
45
- "matchTelValue",
46
- "matchTrouble",
47
- "matchUsername",
48
- "matchUsernameAttr",
49
- "matchUsernameOutlier",
50
- "matchUsernameValue",
51
- ];
52
- describe("regex performance tests", () => {
53
- MATCHERS.forEach((matcher) => {
54
- describe(`${matcher}`, () => {
55
- STR_TEST_LENGTHS.forEach((length) => {
56
- test(`string of ${length} chars under 100ms`, () => {
57
- expect(executionTime(() => matchers[matcher](getRandomString(length)))).toBeLessThan(MAX_EXPECTED_REG_EXEC_TIME);
58
- });
59
- });
60
- });
61
- });
62
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,215 +0,0 @@
1
- import { isShadowElement, shadowPiercingAncestors, shadowPiercingContains, shallowShadowQuerySelector } from "./shadow-dom";
2
- class WrapperComponent extends HTMLElement {
3
- constructor() {
4
- super();
5
- const shadow = this.attachShadow({ mode: "open" });
6
- shadow.innerHTML = `
7
- <div class="wrapper">
8
- <slot name="header"></slot>
9
- <div class="content">
10
- <p class="text">Shadow content</p>
11
- <slot></slot>
12
- </div>
13
- </div>
14
- `;
15
- }
16
- }
17
- class NestedComponent extends HTMLElement {
18
- constructor() {
19
- super();
20
- const shadow = this.attachShadow({ mode: "open" });
21
- shadow.innerHTML = `
22
- <div class="outer">
23
- <wrapper-component>
24
- <span class="nested-content">Nested content</span>
25
- </wrapper-component>
26
- </div>
27
- `;
28
- }
29
- }
30
- class CardComponent extends HTMLElement {
31
- constructor() {
32
- super();
33
- const shadow = this.attachShadow({ mode: "open" });
34
- shadow.innerHTML = `
35
- <div class="card">
36
- <div class="card-header">
37
- <slot name="header"></slot>
38
- </div>
39
- <div class="card-body">
40
- <slot></slot>
41
- </div>
42
- </div>
43
- `;
44
- }
45
- }
46
- class CustomInput extends HTMLElement {
47
- constructor() {
48
- super();
49
- const shadow = this.attachShadow({ mode: "open" });
50
- shadow.innerHTML = `
51
- <div class="input-wrapper">
52
- <input type="text" class="actual-input">
53
- <div class="validation-message"></div>
54
- </div>
55
- `;
56
- }
57
- }
58
- customElements.define("wrapper-component", WrapperComponent);
59
- customElements.define("nested-component", NestedComponent);
60
- customElements.define("custom-input", CustomInput);
61
- customElements.define("card-component", CardComponent);
62
- describe("Shadow DOM Utilities", () => {
63
- let container;
64
- beforeEach(() => {
65
- document.body.innerHTML = "";
66
- container = document.createElement("div");
67
- container.id = "container";
68
- document.body.appendChild(container);
69
- });
70
- describe("`isShadowElement`", () => {
71
- test("should detect elements inside custom element shadow DOM", () => {
72
- var _a;
73
- container.innerHTML = `<wrapper-component></wrapper-component>`;
74
- const component = container.querySelector("wrapper-component");
75
- const shadowText = (_a = component === null || component === void 0 ? void 0 : component.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".text");
76
- expect(isShadowElement(shadowText)).toBe(true);
77
- });
78
- test("should return `false` for custom element host", () => {
79
- container.innerHTML = `<wrapper-component></wrapper-component>`;
80
- const component = container.querySelector("wrapper-component");
81
- expect(isShadowElement(component)).toBe(false);
82
- });
83
- });
84
- describe("`shadowPiercingAncestors`", () => {
85
- test("should traverse from shadow content to light DOM", () => {
86
- var _a;
87
- container.innerHTML = `<wrapper-component></wrapper-component>`;
88
- const component = container.querySelector("wrapper-component");
89
- const shadowText = (_a = component === null || component === void 0 ? void 0 : component.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".text");
90
- const ancestors = Array.from(shadowPiercingAncestors(shadowText));
91
- const expected = [HTMLParagraphElement, HTMLDivElement, HTMLDivElement, WrapperComponent, HTMLDivElement, HTMLBodyElement, HTMLHtmlElement];
92
- expect(ancestors[0]).toBe(shadowText);
93
- expect(ancestors.length).toEqual(expected.length);
94
- expected.forEach((instance, idx) => expect(ancestors[idx]).toBeInstanceOf(instance));
95
- });
96
- test("should handle nested custom elements", () => {
97
- var _a, _b;
98
- container.innerHTML = `<nested-component></nested-component>`;
99
- const outerComponent = container.querySelector("nested-component");
100
- const innerComponent = (_a = outerComponent === null || outerComponent === void 0 ? void 0 : outerComponent.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector("wrapper-component");
101
- const nestedContent = (_b = innerComponent === null || innerComponent === void 0 ? void 0 : innerComponent.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector(".text");
102
- const ancestors = Array.from(shadowPiercingAncestors(nestedContent));
103
- const expected = [HTMLParagraphElement, HTMLDivElement, HTMLDivElement, WrapperComponent, HTMLDivElement, NestedComponent, HTMLDivElement, HTMLBodyElement, HTMLHtmlElement];
104
- expect(ancestors[0]).toBe(nestedContent);
105
- expect(ancestors.length).toEqual(expected.length);
106
- expected.forEach((instance, idx) => expect(ancestors[idx]).toBeInstanceOf(instance));
107
- });
108
- test("should handle slotted content", () => {
109
- container.innerHTML = `
110
- <wrapper-component>
111
- <span class="slotted">Slotted content</span>
112
- </wrapper-component>
113
- `;
114
- const slottedContent = container.querySelector(".slotted");
115
- const ancestors = Array.from(shadowPiercingAncestors(slottedContent));
116
- const expected = [HTMLSpanElement, WrapperComponent, HTMLDivElement, HTMLBodyElement, HTMLHtmlElement];
117
- expect(ancestors[0]).toBe(slottedContent);
118
- expect(ancestors.length).toEqual(expected.length);
119
- expected.forEach((instance, idx) => expect(ancestors[idx]).toBeInstanceOf(instance));
120
- });
121
- });
122
- describe("`shadowPiercingContains`", () => {
123
- test("should find containment across custom element boundaries", () => {
124
- var _a;
125
- container.innerHTML = `<wrapper-component></wrapper-component>`;
126
- const component = container.querySelector("wrapper-component");
127
- const shadowText = (_a = component === null || component === void 0 ? void 0 : component.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".text");
128
- expect(shadowPiercingContains(container, shadowText)).toBe(true);
129
- expect(shadowPiercingContains(component, shadowText)).toBe(true);
130
- });
131
- test("should work with nested custom elements", () => {
132
- var _a, _b;
133
- container.innerHTML = `<nested-component></nested-component>`;
134
- const outerComponent = container.querySelector("nested-component");
135
- const innerComponent = (_a = outerComponent === null || outerComponent === void 0 ? void 0 : outerComponent.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector("wrapper-component");
136
- const deepContent = (_b = innerComponent === null || innerComponent === void 0 ? void 0 : innerComponent.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector(".text");
137
- expect(shadowPiercingContains(container, deepContent)).toBe(true);
138
- expect(shadowPiercingContains(outerComponent, deepContent)).toBe(true);
139
- });
140
- test("should handle mixed light/shadow DOM", () => {
141
- var _a;
142
- container.innerHTML = `
143
- <div class="wrapper">
144
- <wrapper-component></wrapper-component>
145
- </div>
146
- `;
147
- const wrapper = container.querySelector(".wrapper");
148
- const component = wrapper === null || wrapper === void 0 ? void 0 : wrapper.querySelector("wrapper-component");
149
- const shadowContent = (_a = component === null || component === void 0 ? void 0 : component.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".content");
150
- expect(shadowPiercingContains(container, shadowContent)).toBe(true);
151
- expect(shadowPiercingContains(wrapper, shadowContent)).toBe(true);
152
- });
153
- });
154
- describe("`shallowShadowQuerySelector`", () => {
155
- test("should find elements in custom element shadow DOM", () => {
156
- var _a;
157
- container.innerHTML = `<wrapper-component></wrapper-component>`;
158
- const component = container.querySelector("wrapper-component");
159
- const result = shallowShadowQuerySelector(component, ".text");
160
- const expected = (_a = component === null || component === void 0 ? void 0 : component.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".text");
161
- expect(result).toBe(expected);
162
- });
163
- test("should prioritize light DOM over shadow DOM in custom elements", () => {
164
- container.innerHTML = `
165
- <wrapper-component>
166
- <p class="text">Light DOM text</p>
167
- </wrapper-component>
168
- `;
169
- const component = container.querySelector("wrapper-component");
170
- const result = shallowShadowQuerySelector(component, ".text");
171
- expect(result === null || result === void 0 ? void 0 : result.textContent).toBe("Light DOM text");
172
- });
173
- test("should fall back to shadow DOM when not found in light DOM", () => {
174
- var _a;
175
- container.innerHTML = `<wrapper-component></wrapper-component>`;
176
- const component = container.querySelector("wrapper-component");
177
- const result = shallowShadowQuerySelector(component, ".wrapper");
178
- const expected = (_a = component === null || component === void 0 ? void 0 : component.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".wrapper");
179
- expect(result).toBe(expected);
180
- });
181
- });
182
- describe("Real-world scenarios", () => {
183
- test("should handle form controls with shadow DOM", () => {
184
- var _a;
185
- container.innerHTML = `
186
- <form>
187
- <custom-input></custom-input>
188
- </form>
189
- `;
190
- const form = container.querySelector("form");
191
- const customInput = form === null || form === void 0 ? void 0 : form.querySelector("custom-input");
192
- const actualInput = (_a = customInput === null || customInput === void 0 ? void 0 : customInput.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".actual-input");
193
- expect(shadowPiercingContains(form, actualInput)).toBe(true);
194
- expect(shadowPiercingContains(container, actualInput)).toBe(true);
195
- });
196
- test("should work with component composition", () => {
197
- var _a;
198
- container.innerHTML = `
199
- <card-component>
200
- <h2 slot="header">Title</h2>
201
- <wrapper-component></wrapper-component>
202
- </card-component>
203
- `;
204
- const card = container.querySelector("card-component");
205
- const wrapper = card === null || card === void 0 ? void 0 : card.querySelector("wrapper-component");
206
- const shadowText = (_a = wrapper === null || wrapper === void 0 ? void 0 : wrapper.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".text");
207
- const ancestors = Array.from(shadowPiercingAncestors(shadowText));
208
- const expected = [HTMLParagraphElement, HTMLDivElement, HTMLDivElement, WrapperComponent, CardComponent, HTMLDivElement, HTMLBodyElement, HTMLHtmlElement];
209
- expect(ancestors.length).toEqual(expected.length);
210
- expected.forEach((instance, idx) => expect(ancestors[idx]).toBeInstanceOf(instance));
211
- expect(shadowPiercingContains(container, shadowText)).toBe(true);
212
- expect(shadowPiercingContains(card, shadowText)).toBe(true);
213
- });
214
- });
215
- });