@vijaypjavvadi/bdd2pw 3.6.0 → 3.8.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 +133 -0
- package/dist/index.js +25 -6
- package/dist/index.js.map +1 -1
- package/dist/transformers/domains/education.d.ts +15 -0
- package/dist/transformers/domains/education.js +223 -0
- package/dist/transformers/domains/education.js.map +1 -0
- package/dist/transformers/domains/gov.d.ts +15 -0
- package/dist/transformers/domains/gov.js +196 -0
- package/dist/transformers/domains/gov.js.map +1 -0
- package/dist/transformers/domains/retail.d.ts +15 -0
- package/dist/transformers/domains/retail.js +213 -0
- package/dist/transformers/domains/retail.js.map +1 -0
- package/dist/transformers/domains/telecom.d.ts +15 -0
- package/dist/transformers/domains/telecom.js +195 -0
- package/dist/transformers/domains/telecom.js.map +1 -0
- package/dist/transformers/stepMatcher.d.ts +1 -1
- package/dist/transformers/stepMatcher.js +8 -0
- package/dist/transformers/stepMatcher.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* v3.8.0 — Government / civic services domain rule pack.
|
|
4
|
+
*
|
|
5
|
+
* Opt-in via `ScaffoldOptions.domains: ["gov"]`. Covers common
|
|
6
|
+
* citizen-facing dialects: forms, eligibility, case management,
|
|
7
|
+
* benefit amounts, identity verification, FOIA, residency,
|
|
8
|
+
* agency assignment, intake, accessibility.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.GOV_RULES = void 0;
|
|
12
|
+
const SUBJ = "(?:I|user|User|the user|the User|the applicant|the citizen|the caseworker)";
|
|
13
|
+
const MONEY = `\\$?["']?\\$?([\\d,]+(?:\\.\\d{1,2})?)["']?`;
|
|
14
|
+
exports.GOV_RULES = [
|
|
15
|
+
// GOV:01 — `I submit form "DS-11"` / `I submit the "Application X" form`
|
|
16
|
+
{
|
|
17
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?submit(?:s)? (?:the )?(?:form ["']([^"']+)["']|["']([^"']+)["'] form)$`, "i"),
|
|
18
|
+
build: (m, step) => {
|
|
19
|
+
const formName = m[1] ?? m[2];
|
|
20
|
+
return {
|
|
21
|
+
step,
|
|
22
|
+
customBody: [
|
|
23
|
+
`// Submit the named form; use the form's accessible name as the click target.`,
|
|
24
|
+
`await page.getByRole("button", { name: new RegExp(\`submit.*${formName.replace(/[\\W]/g, ".?")}\`, "i") }).first().click();`,
|
|
25
|
+
].join("\n"),
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
// GOV:02 — `the form ID is "..."`
|
|
30
|
+
{
|
|
31
|
+
pattern: /^(?:the )?form(?: ID| number)? is ["']?([A-Z0-9-]+)["']?$/i,
|
|
32
|
+
build: (m, step) => ({
|
|
33
|
+
step,
|
|
34
|
+
customBody: `await expect(page.locator("[data-testid='form-id'], [aria-label='Form ID']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
35
|
+
}),
|
|
36
|
+
},
|
|
37
|
+
// GOV:03 — `the applicant is "eligible"` / `"ineligible"` / `"pending review"`
|
|
38
|
+
{
|
|
39
|
+
pattern: /^(?:the )?(?:applicant|claimant|household) is ["']([^"']+)["']$/i,
|
|
40
|
+
build: (m, step) => ({
|
|
41
|
+
step,
|
|
42
|
+
customBody: `await expect(page.locator("[data-testid='eligibility-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
43
|
+
}),
|
|
44
|
+
},
|
|
45
|
+
// GOV:04 — `the case number is "..."` / `the case ID is "..."`
|
|
46
|
+
{
|
|
47
|
+
pattern: /^(?:the )?case(?: number| ID)? is ["']?([A-Z0-9-]+)["']?$/i,
|
|
48
|
+
build: (m, step) => ({
|
|
49
|
+
step,
|
|
50
|
+
customBody: `await expect(page.locator("[data-testid='case-number'], [data-testid='case-id']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
51
|
+
}),
|
|
52
|
+
},
|
|
53
|
+
// GOV:05 — `the case status is "open"` / `"closed"` / `"under review"`
|
|
54
|
+
{
|
|
55
|
+
pattern: /^(?:the )?case status is ["']([^"']+)["']$/i,
|
|
56
|
+
build: (m, step) => ({
|
|
57
|
+
step,
|
|
58
|
+
customBody: `await expect(page.locator("[data-testid='case-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
// GOV:06 — `the benefit amount is "$X"` / `the monthly benefit is "$X"`
|
|
62
|
+
{
|
|
63
|
+
pattern: new RegExp(`^(?:the )?(?:monthly |annual )?benefit(?: amount)? is ${MONEY}$`, "i"),
|
|
64
|
+
build: (m, step) => ({
|
|
65
|
+
step,
|
|
66
|
+
customBody: `await expect(page.locator("[data-testid='benefit-amount']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
67
|
+
}),
|
|
68
|
+
},
|
|
69
|
+
// GOV:07 — `the document type is "passport"` / `"driver's license"` / `"birth certificate"`
|
|
70
|
+
{
|
|
71
|
+
pattern: /^(?:the )?(?:document|ID) type is ["']([^"']+)["']$/i,
|
|
72
|
+
build: (m, step) => ({
|
|
73
|
+
step,
|
|
74
|
+
customBody: `await expect(page.locator("[data-testid='document-type'], [data-testid='id-type']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
75
|
+
}),
|
|
76
|
+
},
|
|
77
|
+
// GOV:08 — `I upload "passport.pdf"` (file upload)
|
|
78
|
+
{
|
|
79
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?upload(?:s)? ["']([^"']+)["']$`, "i"),
|
|
80
|
+
build: (m, step) => ({
|
|
81
|
+
step,
|
|
82
|
+
customBody: [
|
|
83
|
+
`await page.setInputFiles(`,
|
|
84
|
+
` "[data-testid='file-input'], input[type='file']",`,
|
|
85
|
+
` ${JSON.stringify(m[1])},`,
|
|
86
|
+
`);`,
|
|
87
|
+
].join("\n"),
|
|
88
|
+
}),
|
|
89
|
+
},
|
|
90
|
+
// GOV:09 — `the FOIA request status is "..."`
|
|
91
|
+
{
|
|
92
|
+
pattern: /^(?:the )?FOIA(?: request)? status is ["']([^"']+)["']$/i,
|
|
93
|
+
build: (m, step) => ({
|
|
94
|
+
step,
|
|
95
|
+
customBody: `await expect(page.locator("[data-testid='foia-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
96
|
+
}),
|
|
97
|
+
},
|
|
98
|
+
// GOV:10 — `the response is "redacted"` / `"released"` / `"denied"`
|
|
99
|
+
{
|
|
100
|
+
pattern: /^(?:the )?(?:FOIA )?response is ["']([^"']+)["']$/i,
|
|
101
|
+
build: (m, step) => ({
|
|
102
|
+
step,
|
|
103
|
+
customBody: `await expect(page.locator("[data-testid='foia-response']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
104
|
+
}),
|
|
105
|
+
},
|
|
106
|
+
// GOV:11 — `the residency status is "permanent resident"` / `"citizen"` / `"visa holder"`
|
|
107
|
+
{
|
|
108
|
+
pattern: /^(?:the )?residency status is ["']([^"']+)["']$/i,
|
|
109
|
+
build: (m, step) => ({
|
|
110
|
+
step,
|
|
111
|
+
customBody: `await expect(page.locator("[data-testid='residency-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
112
|
+
}),
|
|
113
|
+
},
|
|
114
|
+
// GOV:12 — `the agency is "..."` / `the assigned agency is "..."`
|
|
115
|
+
{
|
|
116
|
+
pattern: /^(?:the )?(?:assigned )?agency is ["']([^"']+)["']$/i,
|
|
117
|
+
build: (m, step) => ({
|
|
118
|
+
step,
|
|
119
|
+
customBody: `await expect(page.locator("[data-testid='agency-name']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
120
|
+
}),
|
|
121
|
+
},
|
|
122
|
+
// GOV:13 — `the program is "SNAP"` / `"Medicaid"` / `"unemployment"`
|
|
123
|
+
{
|
|
124
|
+
pattern: /^(?:the )?(?:benefit )?program is ["']([^"']+)["']$/i,
|
|
125
|
+
build: (m, step) => ({
|
|
126
|
+
step,
|
|
127
|
+
customBody: `await expect(page.locator("[data-testid='program-name']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
128
|
+
}),
|
|
129
|
+
},
|
|
130
|
+
// GOV:14 — `the intake date is "2026-01-15"`
|
|
131
|
+
{
|
|
132
|
+
pattern: /^(?:the )?(?:intake|filing|application) date is ["']?(\d{4}-\d{2}-\d{2}|\d{1,2}\/\d{1,2}\/\d{2,4})["']?$/i,
|
|
133
|
+
build: (m, step) => ({
|
|
134
|
+
step,
|
|
135
|
+
customBody: `await expect(page.locator("[data-testid='intake-date']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
136
|
+
}),
|
|
137
|
+
},
|
|
138
|
+
// GOV:15 — `the application is "approved"` / `"denied"` / `"pending"` / `"appealed"`
|
|
139
|
+
{
|
|
140
|
+
pattern: /^(?:the )?application is ["']([^"']+)["']$/i,
|
|
141
|
+
build: (m, step) => ({
|
|
142
|
+
step,
|
|
143
|
+
customBody: `await expect(page.locator("[data-testid='application-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
144
|
+
}),
|
|
145
|
+
},
|
|
146
|
+
// GOV:16 — `the page meets WCAG "AA"` / `"AAA"`
|
|
147
|
+
{
|
|
148
|
+
pattern: /^(?:the )?(?:page|form|site) meets WCAG ["']?(A|AA|AAA)["']?(?:\s+compliance)?$/i,
|
|
149
|
+
build: (m, step) => ({
|
|
150
|
+
step,
|
|
151
|
+
customBody: [
|
|
152
|
+
`// Accessibility marker — checks the conformance level reported`,
|
|
153
|
+
`// by the audit panel or aria-live attestation. Real WCAG audits`,
|
|
154
|
+
`// happen offline; this just confirms the UI advertises the claim.`,
|
|
155
|
+
`await expect(page.locator("[data-testid='wcag-conformance'], [aria-label='WCAG conformance']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
156
|
+
].join("\n"),
|
|
157
|
+
}),
|
|
158
|
+
},
|
|
159
|
+
// GOV:17 — `the appeal is "filed"` / `"denied"` / `"granted"`
|
|
160
|
+
{
|
|
161
|
+
pattern: /^(?:the )?appeal is ["']([^"']+)["']$/i,
|
|
162
|
+
build: (m, step) => ({
|
|
163
|
+
step,
|
|
164
|
+
customBody: `await expect(page.locator("[data-testid='appeal-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
165
|
+
}),
|
|
166
|
+
},
|
|
167
|
+
// GOV:18 — `the deadline is "2026-09-30"`
|
|
168
|
+
{
|
|
169
|
+
pattern: /^(?:the )?deadline is ["']?(\d{4}-\d{2}-\d{2}|\d{1,2}\/\d{1,2}\/\d{2,4})["']?$/i,
|
|
170
|
+
build: (m, step) => ({
|
|
171
|
+
step,
|
|
172
|
+
customBody: `await expect(page.locator("[data-testid='deadline']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
173
|
+
}),
|
|
174
|
+
},
|
|
175
|
+
// GOV:19 — `I schedule an appointment for "2026-06-10"`
|
|
176
|
+
{
|
|
177
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?schedule(?:s)? (?:an? )?appointment (?:for|on) ["']?(\\d{4}-\\d{2}-\\d{2})["']?$`, "i"),
|
|
178
|
+
build: (m, step) => ({
|
|
179
|
+
step,
|
|
180
|
+
customBody: [
|
|
181
|
+
`await page.getByRole("button", { name: /schedule.*appointment/i }).click();`,
|
|
182
|
+
`await page.getByLabel(/appointment date/i).fill(${JSON.stringify(m[1])});`,
|
|
183
|
+
`await page.getByRole("button", { name: /confirm|submit/i }).click();`,
|
|
184
|
+
].join("\n"),
|
|
185
|
+
}),
|
|
186
|
+
},
|
|
187
|
+
// GOV:20 — `the audit log records a "view-case" event`
|
|
188
|
+
{
|
|
189
|
+
pattern: /^(?:the )?audit log records (?:a |an )?["']([^"']+)["'] event(?: for the case)?$/i,
|
|
190
|
+
build: (m, step) => ({
|
|
191
|
+
step,
|
|
192
|
+
customBody: `await expect(page.locator("[data-testid='audit-log']")).toContainText(${JSON.stringify(m[1])});`,
|
|
193
|
+
}),
|
|
194
|
+
},
|
|
195
|
+
];
|
|
196
|
+
//# sourceMappingURL=gov.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gov.js","sourceRoot":"","sources":["../../../src/transformers/domains/gov.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v3.8.0 — Retail / e-commerce domain rule pack.
|
|
3
|
+
*
|
|
4
|
+
* Opt-in via `ScaffoldOptions.domains: ["retail"]`. Covers the
|
|
5
|
+
* common shopping-flow dialects: cart, pricing, checkout, SKUs,
|
|
6
|
+
* inventory, shipping, promo codes, products, reviews, wishlist,
|
|
7
|
+
* order status.
|
|
8
|
+
*/
|
|
9
|
+
import type { PageObjectIR, StepBinding, StepIR } from "../../types";
|
|
10
|
+
interface Rule {
|
|
11
|
+
pattern: RegExp;
|
|
12
|
+
build(m: RegExpMatchArray, step: StepIR, pom: PageObjectIR, pageVar: string): StepBinding | null;
|
|
13
|
+
}
|
|
14
|
+
export declare const RETAIL_RULES: Rule[];
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* v3.8.0 — Retail / e-commerce domain rule pack.
|
|
4
|
+
*
|
|
5
|
+
* Opt-in via `ScaffoldOptions.domains: ["retail"]`. Covers the
|
|
6
|
+
* common shopping-flow dialects: cart, pricing, checkout, SKUs,
|
|
7
|
+
* inventory, shipping, promo codes, products, reviews, wishlist,
|
|
8
|
+
* order status.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.RETAIL_RULES = void 0;
|
|
12
|
+
const SUBJ = "(?:I|user|User|the user|the User|the customer|the shopper)";
|
|
13
|
+
const MONEY = `\\$?["']?\\$?([\\d,]+(?:\\.\\d{1,2})?)["']?`;
|
|
14
|
+
exports.RETAIL_RULES = [
|
|
15
|
+
// RETAIL:01 — `I add "Widget" to the cart`
|
|
16
|
+
{
|
|
17
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?add(?:s)? ["']([^"']+)["'] to (?:the |my )?cart$`, "i"),
|
|
18
|
+
build: (m, step) => ({
|
|
19
|
+
step,
|
|
20
|
+
customBody: [
|
|
21
|
+
`await page.getByRole("button", { name: /add.*to.*cart/i }).filter({ has: page.locator(\`text=\${${JSON.stringify(m[1])}}\`) }).first().click();`,
|
|
22
|
+
`// Some sites require a click on the product card first; the .filter chains it through the product context.`,
|
|
23
|
+
].join("\n"),
|
|
24
|
+
}),
|
|
25
|
+
},
|
|
26
|
+
// RETAIL:02 — `the cart has N items`
|
|
27
|
+
{
|
|
28
|
+
pattern: /^(?:the )?cart has (\d+) items?$/i,
|
|
29
|
+
build: (m, step) => ({
|
|
30
|
+
step,
|
|
31
|
+
customBody: [
|
|
32
|
+
`const _itemCount = await page.locator("[data-testid='cart-item'], .cart-item").count();`,
|
|
33
|
+
`expect(_itemCount).toBe(${m[1]});`,
|
|
34
|
+
].join("\n"),
|
|
35
|
+
}),
|
|
36
|
+
},
|
|
37
|
+
// RETAIL:03 — `the cart is empty`
|
|
38
|
+
{
|
|
39
|
+
pattern: /^(?:the )?cart is (not )?empty$/i,
|
|
40
|
+
build: (m, step) => {
|
|
41
|
+
const matcher = m[1] ? "toBeGreaterThan" : "toBe";
|
|
42
|
+
const expected = m[1] ? "0" : "0";
|
|
43
|
+
return {
|
|
44
|
+
step,
|
|
45
|
+
customBody: [
|
|
46
|
+
`const _cartCount = await page.locator("[data-testid='cart-item'], .cart-item").count();`,
|
|
47
|
+
`expect(_cartCount).${matcher}(${expected});`,
|
|
48
|
+
].join("\n"),
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
// RETAIL:04 — `the price is "$19.99"`
|
|
53
|
+
{
|
|
54
|
+
pattern: new RegExp(`^(?:the )?price is ${MONEY}$`, "i"),
|
|
55
|
+
build: (m, step) => ({
|
|
56
|
+
step,
|
|
57
|
+
customBody: `await expect(page.locator("[data-testid='price'], .price, [itemprop='price']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
// RETAIL:05 — `the subtotal is "$X"` / `the total is "$X"` / `the tax is "$X"`
|
|
61
|
+
{
|
|
62
|
+
pattern: new RegExp(`^(?:the )?(subtotal|total|tax|order total|grand total) is ${MONEY}$`, "i"),
|
|
63
|
+
build: (m, step) => {
|
|
64
|
+
const kind = m[1].toLowerCase().replace(/\s+/g, "-");
|
|
65
|
+
return {
|
|
66
|
+
step,
|
|
67
|
+
customBody: `await expect(page.locator(\`[data-testid='\${${JSON.stringify(kind)}}'], [data-testid='${kind}']\`).first()).toContainText(${JSON.stringify(m[2])});`,
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
// RETAIL:06 — `I complete the checkout`
|
|
72
|
+
{
|
|
73
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?(?:complete(?:s)?|place(?:s)?|submit(?:s)?) (?:the )?(?:checkout|order)$`, "i"),
|
|
74
|
+
build: (_m, step) => ({
|
|
75
|
+
step,
|
|
76
|
+
customBody: [
|
|
77
|
+
`await page.getByRole("button", { name: /(?:place|complete|submit).*order|checkout/i }).first().click();`,
|
|
78
|
+
].join("\n"),
|
|
79
|
+
}),
|
|
80
|
+
},
|
|
81
|
+
// RETAIL:07 — `the SKU is "ABC-12345"`
|
|
82
|
+
{
|
|
83
|
+
pattern: /^(?:the )?SKU is ["']?([A-Z0-9-]+)["']?$/i,
|
|
84
|
+
build: (m, step) => ({
|
|
85
|
+
step,
|
|
86
|
+
customBody: `await expect(page.locator("[data-testid='sku'], [data-sku]").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
87
|
+
}),
|
|
88
|
+
},
|
|
89
|
+
// RETAIL:08 — `the item is "in stock"` / `"out of stock"` / `"low stock"`
|
|
90
|
+
{
|
|
91
|
+
pattern: /^(?:the )?(?:item|product) is ["']?(in stock|out of stock|low stock|backordered|sold out)["']?$/i,
|
|
92
|
+
build: (m, step) => ({
|
|
93
|
+
step,
|
|
94
|
+
customBody: `await expect(page.locator("[data-testid='stock-status'], .stock-status").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
95
|
+
}),
|
|
96
|
+
},
|
|
97
|
+
// RETAIL:09 — `the shipping address is "..."`
|
|
98
|
+
{
|
|
99
|
+
pattern: /^(?:the )?shipping address is ["']([^"']+)["']$/i,
|
|
100
|
+
build: (m, step) => ({
|
|
101
|
+
step,
|
|
102
|
+
customBody: `await expect(page.locator("[data-testid='shipping-address']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
103
|
+
}),
|
|
104
|
+
},
|
|
105
|
+
// RETAIL:10 — `the estimated delivery is "2026-06-01"` / "2-3 business days"
|
|
106
|
+
{
|
|
107
|
+
pattern: /^(?:the )?(?:estimated )?delivery(?: date)? is ["']([^"']+)["']$/i,
|
|
108
|
+
build: (m, step) => ({
|
|
109
|
+
step,
|
|
110
|
+
customBody: `await expect(page.locator("[data-testid='estimated-delivery'], .delivery-date").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
111
|
+
}),
|
|
112
|
+
},
|
|
113
|
+
// RETAIL:11 — `I apply promo code "SAVE10"`
|
|
114
|
+
{
|
|
115
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?(?:apply(?:ies)?|enter(?:s)?) (?:promo|discount|coupon) code ["']([^"']+)["']$`, "i"),
|
|
116
|
+
build: (m, step) => ({
|
|
117
|
+
step,
|
|
118
|
+
customBody: [
|
|
119
|
+
`await page.getByLabel(/promo|discount|coupon/i).fill(${JSON.stringify(m[1])});`,
|
|
120
|
+
`await page.getByRole("button", { name: /apply/i }).click();`,
|
|
121
|
+
].join("\n"),
|
|
122
|
+
}),
|
|
123
|
+
},
|
|
124
|
+
// RETAIL:12 — `the discount is "$10"` / "10%"
|
|
125
|
+
{
|
|
126
|
+
pattern: /^(?:the )?discount is ["']?\$?([\d.]+%?)["']?$/i,
|
|
127
|
+
build: (m, step) => ({
|
|
128
|
+
step,
|
|
129
|
+
customBody: `await expect(page.locator("[data-testid='discount']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
130
|
+
}),
|
|
131
|
+
},
|
|
132
|
+
// RETAIL:13 — `the product name is "X"` / `the product's name is "X"` / `the product is "X"`
|
|
133
|
+
{
|
|
134
|
+
pattern: /^(?:the )?product(?:(?:'s)?\s+name)? is ["']([^"']+)["']$/i,
|
|
135
|
+
build: (m, step) => ({
|
|
136
|
+
step,
|
|
137
|
+
customBody: `await expect(page.locator("[data-testid='product-name'], h1[itemprop='name']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
138
|
+
}),
|
|
139
|
+
},
|
|
140
|
+
// RETAIL:14 — `the rating is N stars`
|
|
141
|
+
{
|
|
142
|
+
pattern: /^(?:the )?rating is (\d(?:\.\d)?)(?:\s*stars?)?$/i,
|
|
143
|
+
build: (m, step) => ({
|
|
144
|
+
step,
|
|
145
|
+
customBody: [
|
|
146
|
+
`const _rating = await page.locator("[data-testid='rating'], [itemprop='ratingValue']").first().innerText();`,
|
|
147
|
+
`expect(Number(_rating.replace(/[^\\d.]/g, ""))).toBe(${m[1]});`,
|
|
148
|
+
].join("\n"),
|
|
149
|
+
}),
|
|
150
|
+
},
|
|
151
|
+
// RETAIL:15 — `there are N reviews`
|
|
152
|
+
{
|
|
153
|
+
pattern: /^there (?:are|is) (\d+) reviews?$/i,
|
|
154
|
+
build: (m, step) => ({
|
|
155
|
+
step,
|
|
156
|
+
customBody: [
|
|
157
|
+
`const _reviewCount = await page.locator("[data-testid='review'], .review-item").count();`,
|
|
158
|
+
`expect(_reviewCount).toBe(${m[1]});`,
|
|
159
|
+
].join("\n"),
|
|
160
|
+
}),
|
|
161
|
+
},
|
|
162
|
+
// RETAIL:16 — `I save "X" to my wishlist`
|
|
163
|
+
{
|
|
164
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?(?:save(?:s)?|add(?:s)?) ["']([^"']+)["'] to (?:my |the )?wishlist$`, "i"),
|
|
165
|
+
build: (m, step) => ({
|
|
166
|
+
step,
|
|
167
|
+
customBody: [
|
|
168
|
+
`// Find the product card by name, then click its wishlist toggle.`,
|
|
169
|
+
`const _card = page.locator("[data-testid='product-card']").filter({ hasText: ${JSON.stringify(m[1])} }).first();`,
|
|
170
|
+
`await _card.getByRole("button", { name: /wishlist|favorite|save/i }).click();`,
|
|
171
|
+
].join("\n"),
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
// RETAIL:17 — `the order status is "shipped"` / `"delivered"` / `"pending"` / `"cancelled"`
|
|
175
|
+
{
|
|
176
|
+
pattern: /^(?:the )?order status is ["']([^"']+)["']$/i,
|
|
177
|
+
build: (m, step) => ({
|
|
178
|
+
step,
|
|
179
|
+
customBody: `await expect(page.locator("[data-testid='order-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
180
|
+
}),
|
|
181
|
+
},
|
|
182
|
+
// RETAIL:18 — `the order number is "..."`
|
|
183
|
+
{
|
|
184
|
+
pattern: /^(?:the )?order(?: number| ID) is ["']?([A-Z0-9-]+)["']?$/i,
|
|
185
|
+
build: (m, step) => ({
|
|
186
|
+
step,
|
|
187
|
+
customBody: `await expect(page.locator("[data-testid='order-number']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
188
|
+
}),
|
|
189
|
+
},
|
|
190
|
+
// RETAIL:19 — `I select "Medium" size` / `I select "Red" color`
|
|
191
|
+
{
|
|
192
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?select(?:s)? ["']([^"']+)["'] (size|color|colour|variant)$`, "i"),
|
|
193
|
+
build: (m, step) => {
|
|
194
|
+
const attr = m[2].toLowerCase();
|
|
195
|
+
return {
|
|
196
|
+
step,
|
|
197
|
+
customBody: `await page.getByRole("button", { name: new RegExp(${JSON.stringify(m[1])}, "i") }).filter({ has: page.locator(\`[data-${attr}]\`) }).first().click();`,
|
|
198
|
+
};
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
// RETAIL:20 — `I remove "X" from the cart`
|
|
202
|
+
{
|
|
203
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?remove(?:s)? ["']([^"']+)["'] from (?:the |my )?cart$`, "i"),
|
|
204
|
+
build: (m, step) => ({
|
|
205
|
+
step,
|
|
206
|
+
customBody: [
|
|
207
|
+
`const _row = page.locator("[data-testid='cart-item']").filter({ hasText: ${JSON.stringify(m[1])} }).first();`,
|
|
208
|
+
`await _row.getByRole("button", { name: /remove|delete/i }).click();`,
|
|
209
|
+
].join("\n"),
|
|
210
|
+
}),
|
|
211
|
+
},
|
|
212
|
+
];
|
|
213
|
+
//# sourceMappingURL=retail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retail.js","sourceRoot":"","sources":["../../../src/transformers/domains/retail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v3.8.0 — Telecom / mobile-carrier domain rule pack.
|
|
3
|
+
*
|
|
4
|
+
* Opt-in via `ScaffoldOptions.domains: ["telecom"]`. Covers
|
|
5
|
+
* subscriber accounts, plan tiers, MSISDN, port-in, data/voice/SMS
|
|
6
|
+
* usage, billing, service status, signal strength, device IMEI,
|
|
7
|
+
* call/SMS counts.
|
|
8
|
+
*/
|
|
9
|
+
import type { PageObjectIR, StepBinding, StepIR } from "../../types";
|
|
10
|
+
interface Rule {
|
|
11
|
+
pattern: RegExp;
|
|
12
|
+
build(m: RegExpMatchArray, step: StepIR, pom: PageObjectIR, pageVar: string): StepBinding | null;
|
|
13
|
+
}
|
|
14
|
+
export declare const TELECOM_RULES: Rule[];
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* v3.8.0 — Telecom / mobile-carrier domain rule pack.
|
|
4
|
+
*
|
|
5
|
+
* Opt-in via `ScaffoldOptions.domains: ["telecom"]`. Covers
|
|
6
|
+
* subscriber accounts, plan tiers, MSISDN, port-in, data/voice/SMS
|
|
7
|
+
* usage, billing, service status, signal strength, device IMEI,
|
|
8
|
+
* call/SMS counts.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.TELECOM_RULES = void 0;
|
|
12
|
+
const SUBJ = "(?:I|user|User|the user|the User|the subscriber|the customer|the agent)";
|
|
13
|
+
const MONEY = `\\$?["']?\\$?([\\d,]+(?:\\.\\d{1,2})?)["']?`;
|
|
14
|
+
exports.TELECOM_RULES = [
|
|
15
|
+
// TEL:01 — `the subscriber is "active"` / `"suspended"` / `"cancelled"` / `"churned"`
|
|
16
|
+
{
|
|
17
|
+
pattern: /^(?:the )?subscriber is ["']?(active|suspended|cancell?ed|churned|pending|disconnected)["']?$/i,
|
|
18
|
+
build: (m, step) => ({
|
|
19
|
+
step,
|
|
20
|
+
customBody: `await expect(page.locator("[data-testid='subscriber-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
21
|
+
}),
|
|
22
|
+
},
|
|
23
|
+
// TEL:02 — `the plan tier is "Premium"` / `"Basic"` / `"Pro"`
|
|
24
|
+
{
|
|
25
|
+
pattern: /^(?:the )?plan(?: tier)? is ["']([^"']+)["']$/i,
|
|
26
|
+
build: (m, step) => ({
|
|
27
|
+
step,
|
|
28
|
+
customBody: `await expect(page.locator("[data-testid='plan-tier']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
29
|
+
}),
|
|
30
|
+
},
|
|
31
|
+
// TEL:03 — `the monthly price is "$50"` / `the monthly bill is "$N"`
|
|
32
|
+
{
|
|
33
|
+
pattern: new RegExp(`^(?:the )?(?:monthly )?(?:price|bill|rate) is ${MONEY}$`, "i"),
|
|
34
|
+
build: (m, step) => ({
|
|
35
|
+
step,
|
|
36
|
+
customBody: `await expect(page.locator("[data-testid='monthly-price'], [data-testid='monthly-bill']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
37
|
+
}),
|
|
38
|
+
},
|
|
39
|
+
// TEL:04 — `the MSISDN is "..."` / `the phone number is "..."`
|
|
40
|
+
{
|
|
41
|
+
pattern: /^(?:the )?(?:MSISDN|phone number|mobile number) is ["']?(\+?[\d -]{7,20})["']?$/i,
|
|
42
|
+
build: (m, step) => ({
|
|
43
|
+
step,
|
|
44
|
+
customBody: `await expect(page.locator("[data-testid='msisdn'], [data-testid='phone-number']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
// TEL:05 — `the port-in is "in progress"` / `"complete"` / `"failed"`
|
|
48
|
+
{
|
|
49
|
+
pattern: /^(?:the )?(?:port-in|port out|number port) (?:status )?is ["']([^"']+)["']$/i,
|
|
50
|
+
build: (m, step) => ({
|
|
51
|
+
step,
|
|
52
|
+
customBody: `await expect(page.locator("[data-testid='port-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
53
|
+
}),
|
|
54
|
+
},
|
|
55
|
+
// TEL:06 — `the data usage is "5 GB"` / `"500 MB"`
|
|
56
|
+
{
|
|
57
|
+
pattern: /^(?:the )?data usage is ["']?(\d+(?:\.\d+)?\s*(?:GB|MB|TB))["']?$/i,
|
|
58
|
+
build: (m, step) => ({
|
|
59
|
+
step,
|
|
60
|
+
customBody: `await expect(page.locator("[data-testid='data-usage']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
61
|
+
}),
|
|
62
|
+
},
|
|
63
|
+
// TEL:07 — `the data allowance is "10 GB"`
|
|
64
|
+
{
|
|
65
|
+
pattern: /^(?:the )?data (?:allowance|cap|limit) is ["']?(\d+(?:\.\d+)?\s*(?:GB|MB|TB)|unlimited)["']?$/i,
|
|
66
|
+
build: (m, step) => ({
|
|
67
|
+
step,
|
|
68
|
+
customBody: `await expect(page.locator("[data-testid='data-allowance']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
69
|
+
}),
|
|
70
|
+
},
|
|
71
|
+
// TEL:08 — `the voice usage is "120 min"` / `"2 hours"`
|
|
72
|
+
{
|
|
73
|
+
pattern: /^(?:the )?voice usage is ["']?(\d+(?:\.\d+)?\s*(?:min|hours?|m|h))["']?$/i,
|
|
74
|
+
build: (m, step) => ({
|
|
75
|
+
step,
|
|
76
|
+
customBody: `await expect(page.locator("[data-testid='voice-usage']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
77
|
+
}),
|
|
78
|
+
},
|
|
79
|
+
// TEL:09 — `the SMS count is N` / `the messages count is N`
|
|
80
|
+
{
|
|
81
|
+
pattern: /^(?:the )?(?:SMS|message|text) count is (\d+)$/i,
|
|
82
|
+
build: (m, step) => ({
|
|
83
|
+
step,
|
|
84
|
+
customBody: [
|
|
85
|
+
`const _smsCount = await page.locator("[data-testid='sms-count']").first().innerText();`,
|
|
86
|
+
`expect(Number(_smsCount.replace(/\\D/g, ""))).toBe(${m[1]});`,
|
|
87
|
+
].join("\n"),
|
|
88
|
+
}),
|
|
89
|
+
},
|
|
90
|
+
// TEL:10 — `the bill is "$75.50"` / `the outstanding balance is "$X"`
|
|
91
|
+
{
|
|
92
|
+
pattern: new RegExp(`^(?:the )?(?:bill|outstanding balance|amount due) is ${MONEY}$`, "i"),
|
|
93
|
+
build: (m, step) => ({
|
|
94
|
+
step,
|
|
95
|
+
customBody: `await expect(page.locator("[data-testid='bill-amount'], [data-testid='balance-due']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
96
|
+
}),
|
|
97
|
+
},
|
|
98
|
+
// TEL:11 — `the service is "active"` / `"suspended"`
|
|
99
|
+
{
|
|
100
|
+
pattern: /^(?:the )?service is ["']?(active|suspended|disconnected|pending|barred)["']?$/i,
|
|
101
|
+
build: (m, step) => ({
|
|
102
|
+
step,
|
|
103
|
+
customBody: `await expect(page.locator("[data-testid='service-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
104
|
+
}),
|
|
105
|
+
},
|
|
106
|
+
// TEL:12 — `the signal is "strong"` / `"weak"` / `"no signal"`
|
|
107
|
+
{
|
|
108
|
+
pattern: /^(?:the )?signal(?: strength)? is ["']?(strong|weak|moderate|poor|no signal|full bars)["']?$/i,
|
|
109
|
+
build: (m, step) => ({
|
|
110
|
+
step,
|
|
111
|
+
customBody: `await expect(page.locator("[data-testid='signal-strength']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
112
|
+
}),
|
|
113
|
+
},
|
|
114
|
+
// TEL:13 — `the device IMEI is "..."`
|
|
115
|
+
{
|
|
116
|
+
pattern: /^(?:the )?device IMEI is ["']?(\d{15})["']?$/i,
|
|
117
|
+
build: (m, step) => ({
|
|
118
|
+
step,
|
|
119
|
+
customBody: `await expect(page.locator("[data-testid='imei'], [data-testid='device-imei']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
120
|
+
}),
|
|
121
|
+
},
|
|
122
|
+
// TEL:14 — `the SIM ICCID is "..."`
|
|
123
|
+
{
|
|
124
|
+
pattern: /^(?:the )?(?:SIM )?ICCID is ["']?(\d{18,20})["']?$/i,
|
|
125
|
+
build: (m, step) => ({
|
|
126
|
+
step,
|
|
127
|
+
customBody: `await expect(page.locator("[data-testid='iccid']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
128
|
+
}),
|
|
129
|
+
},
|
|
130
|
+
// TEL:15 — `the call duration is N minutes`
|
|
131
|
+
{
|
|
132
|
+
pattern: /^(?:the )?call duration is (\d+(?:\.\d+)?)(?: minutes?| min| m)?$/i,
|
|
133
|
+
build: (m, step) => ({
|
|
134
|
+
step,
|
|
135
|
+
customBody: [
|
|
136
|
+
`const _duration = await page.locator("[data-testid='call-duration']").first().innerText();`,
|
|
137
|
+
`expect(Number(_duration.replace(/[^\\d.]/g, ""))).toBe(${m[1]});`,
|
|
138
|
+
].join("\n"),
|
|
139
|
+
}),
|
|
140
|
+
},
|
|
141
|
+
// TEL:16 — `I activate the SIM` / `I activate device`
|
|
142
|
+
{
|
|
143
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?activate(?:s)? (?:the )?(SIM|device|line)$`, "i"),
|
|
144
|
+
build: (_m, step) => ({
|
|
145
|
+
step,
|
|
146
|
+
customBody: [
|
|
147
|
+
`await page.getByRole("button", { name: /activate/i }).first().click();`,
|
|
148
|
+
`await page.getByRole("button", { name: /confirm/i }).click();`,
|
|
149
|
+
].join("\n"),
|
|
150
|
+
}),
|
|
151
|
+
},
|
|
152
|
+
// TEL:17 — `I suspend the service` / `I cancel the service`
|
|
153
|
+
{
|
|
154
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?(suspend|cancel|reactivate|resume)(?:s)? (?:the )?(?:service|account|line)$`, "i"),
|
|
155
|
+
build: (m, step) => {
|
|
156
|
+
const action = m[1].toLowerCase();
|
|
157
|
+
return {
|
|
158
|
+
step,
|
|
159
|
+
customBody: [
|
|
160
|
+
`await page.getByRole("button", { name: new RegExp(${JSON.stringify(action)}, "i") }).first().click();`,
|
|
161
|
+
`await page.getByRole("button", { name: /confirm/i }).click();`,
|
|
162
|
+
].join("\n"),
|
|
163
|
+
};
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
// TEL:18 — `the roaming is "enabled"` / `"disabled"`
|
|
167
|
+
{
|
|
168
|
+
pattern: /^(?:the )?(?:international )?roaming is ["']?(enabled|disabled|active|inactive|on|off)["']?$/i,
|
|
169
|
+
build: (m, step) => ({
|
|
170
|
+
step,
|
|
171
|
+
customBody: `await expect(page.locator("[data-testid='roaming-status']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
// TEL:19 — `the account number is "..."`
|
|
175
|
+
{
|
|
176
|
+
pattern: /^(?:the )?account(?: number)? is ["']?([A-Z0-9-]+)["']?$/i,
|
|
177
|
+
build: (m, step) => ({
|
|
178
|
+
step,
|
|
179
|
+
customBody: `await expect(page.locator("[data-testid='account-number']").first()).toContainText(${JSON.stringify(m[1])});`,
|
|
180
|
+
}),
|
|
181
|
+
},
|
|
182
|
+
// TEL:20 — `I add line "555-1234" to the plan`
|
|
183
|
+
{
|
|
184
|
+
pattern: new RegExp(`^(?:${SUBJ}\\s+)?add(?:s)? line ["']([^"']+)["'] to (?:the |my )?plan$`, "i"),
|
|
185
|
+
build: (m, step) => ({
|
|
186
|
+
step,
|
|
187
|
+
customBody: [
|
|
188
|
+
`await page.getByRole("button", { name: /add line/i }).click();`,
|
|
189
|
+
`await page.getByLabel(/phone|MSISDN|number/i).fill(${JSON.stringify(m[1])});`,
|
|
190
|
+
`await page.getByRole("button", { name: /confirm|save/i }).click();`,
|
|
191
|
+
].join("\n"),
|
|
192
|
+
}),
|
|
193
|
+
},
|
|
194
|
+
];
|
|
195
|
+
//# sourceMappingURL=telecom.js.map
|