@letsrunit/bdd 0.3.10 → 0.4.1
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/dist/{chunk-A7ZD72RB.js → chunk-D6IA6AFW.js} +177 -196
- package/dist/chunk-D6IA6AFW.js.map +1 -0
- package/dist/define.js +2 -2
- package/dist/define.js.map +1 -1
- package/dist/index.d.ts +54 -4
- package/dist/index.js +1 -1
- package/package.json +5 -5
- package/src/define.ts +4 -3
- package/src/index.ts +2 -1
- package/src/registry.ts +93 -0
- package/src/steps/assert.ts +1 -1
- package/src/steps/clipboard.ts +1 -1
- package/src/steps/form.ts +1 -1
- package/src/steps/index.ts +7 -18
- package/src/steps/keyboard.ts +1 -1
- package/src/steps/mailbox.ts +1 -1
- package/src/steps/mouse.ts +1 -1
- package/src/steps/navigation.ts +1 -1
- package/dist/chunk-A7ZD72RB.js.map +0 -1
- package/src/steps/wrappers.ts +0 -13
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import { locatorParameter, valueParameter, keysParameter, booleanParameter, enumParameter } from '@letsrunit/gherkin';
|
|
2
|
-
import {
|
|
1
|
+
import { locatorParameter, valueParameter, keysParameter, booleanParameter, enumParameter, sanitizeStepDefinition } from '@letsrunit/gherkin';
|
|
2
|
+
import { ParameterTypeRegistry, ParameterType, CucumberExpression, RegularExpression } from '@cucumber/cucumber-expressions';
|
|
3
|
+
import { fuzzyLocator, suppressInterferences, waitForIdle, waitAfterInteraction, setFieldValue } from '@letsrunit/playwright';
|
|
3
4
|
import { expect } from '@playwright/test';
|
|
4
|
-
import {
|
|
5
|
-
import { receiveMail, toEml } from '@letsrunit/mailbox';
|
|
5
|
+
import { eventually, splitUrl, pathRegexp, sleep, textToHtml, asFilename } from '@letsrunit/utils';
|
|
6
6
|
import ISO6391 from 'iso-639-1';
|
|
7
7
|
import metascraper from 'metascraper';
|
|
8
8
|
import metascraperLang from 'metascraper-lang';
|
|
9
|
+
import { receiveMail, toEml } from '@letsrunit/mailbox';
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
var __export = (target, all) => {
|
|
12
|
-
for (var name in all)
|
|
13
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
-
};
|
|
11
|
+
// src/parameters.ts
|
|
15
12
|
var typeDefinitions = [
|
|
16
13
|
locatorParameter(),
|
|
17
14
|
valueParameter(),
|
|
@@ -24,38 +21,82 @@ var typeDefinitions = [
|
|
|
24
21
|
booleanParameter("focus", "blur"),
|
|
25
22
|
enumParameter(["click", "double-click", "right-click", "hover"], /((?:double-|right-)?click|hover)/)
|
|
26
23
|
];
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return
|
|
24
|
+
function createRegistry() {
|
|
25
|
+
const _paramRegistry = new ParameterTypeRegistry();
|
|
26
|
+
const _entries = [];
|
|
27
|
+
for (const t of typeDefinitions) {
|
|
28
|
+
_paramRegistry.defineParameterType(
|
|
29
|
+
new ParameterType(t.name, t.regexp, null, t.transformer, t.useForSnippets)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
/** IStepRegistry-compatible defs (source = String(expression), no raw expr). */
|
|
34
|
+
get defs() {
|
|
35
|
+
return _entries.map(({ type: type2, expression, fn, comment }) => ({
|
|
36
|
+
type: type2,
|
|
37
|
+
source: String(expression),
|
|
38
|
+
fn,
|
|
39
|
+
comment
|
|
40
|
+
}));
|
|
41
|
+
},
|
|
42
|
+
/** Raw step definitions with original expression — used by define.ts for Cucumber registration. */
|
|
43
|
+
get definitions() {
|
|
44
|
+
return _entries.map(({ type: type2, expression, fn, comment }) => ({ type: type2, expression, fn, comment }));
|
|
45
|
+
},
|
|
46
|
+
defineStep(type2, expression, fn, comment) {
|
|
47
|
+
const expr = typeof expression === "string" ? new CucumberExpression(sanitizeStepDefinition(expression), _paramRegistry) : new RegularExpression(expression, _paramRegistry);
|
|
48
|
+
_entries.push({ type: type2, expression, fn, comment, expr });
|
|
49
|
+
},
|
|
50
|
+
defineParameterType(type2) {
|
|
51
|
+
_paramRegistry.defineParameterType(
|
|
52
|
+
new ParameterType(type2.name, type2.regexp, null, type2.transformer, type2.useForSnippets)
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
match(text) {
|
|
56
|
+
for (const entry of _entries) {
|
|
57
|
+
const args = entry.expr.match(text);
|
|
58
|
+
if (args) {
|
|
59
|
+
return {
|
|
60
|
+
def: { type: entry.type, source: String(entry.expression), fn: entry.fn, comment: entry.comment },
|
|
61
|
+
values: args.map((a) => a.getValue(null)),
|
|
62
|
+
args
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
36
69
|
}
|
|
37
|
-
|
|
38
|
-
// src/steps/wrappers.ts
|
|
70
|
+
var registry = createRegistry();
|
|
39
71
|
function Given(expression, fn, comment) {
|
|
40
|
-
|
|
72
|
+
const def = { type: "Given", expression, fn, comment };
|
|
73
|
+
registry.defineStep("Given", expression, fn, comment);
|
|
74
|
+
return def;
|
|
41
75
|
}
|
|
42
76
|
function When(expression, fn, comment) {
|
|
43
|
-
|
|
77
|
+
const def = { type: "When", expression, fn, comment };
|
|
78
|
+
registry.defineStep("When", expression, fn, comment);
|
|
79
|
+
return def;
|
|
44
80
|
}
|
|
45
81
|
function Then(expression, fn, comment) {
|
|
46
|
-
|
|
82
|
+
const def = { type: "Then", expression, fn, comment };
|
|
83
|
+
registry.defineStep("Then", expression, fn, comment);
|
|
84
|
+
return def;
|
|
85
|
+
}
|
|
86
|
+
function expectOrNot(actual, toBe) {
|
|
87
|
+
return toBe ? expect(actual) : expect(actual).not;
|
|
47
88
|
}
|
|
48
89
|
|
|
49
90
|
// src/steps/assert.ts
|
|
50
91
|
var WAIT_TIMEOUT = 5e3;
|
|
51
|
-
|
|
92
|
+
Then(
|
|
52
93
|
"The page {contains|not contains} {locator}",
|
|
53
94
|
async function(visible, selector) {
|
|
54
95
|
const el = await fuzzyLocator(this.page, selector);
|
|
55
96
|
await expectOrNot(el, visible).toBeVisible({ timeout: WAIT_TIMEOUT });
|
|
56
97
|
}
|
|
57
98
|
);
|
|
58
|
-
|
|
99
|
+
Then(
|
|
59
100
|
"{locator} {contains|not contains} {locator}",
|
|
60
101
|
async function(selector, contain2, child) {
|
|
61
102
|
const el = await fuzzyLocator(this.page, selector);
|
|
@@ -63,61 +104,97 @@ var contain = Then(
|
|
|
63
104
|
await expectOrNot(childElement, contain2).toBeAttached({ timeout: WAIT_TIMEOUT });
|
|
64
105
|
}
|
|
65
106
|
);
|
|
107
|
+
var scrapeLang = metascraper([metascraperLang()]);
|
|
108
|
+
async function getLang(page) {
|
|
109
|
+
const html = "html" in page ? page.html : await page.content();
|
|
110
|
+
const url = typeof page.url === "function" ? page.url() : page.url;
|
|
111
|
+
const { lang = null } = await scrapeLang({ html, url });
|
|
112
|
+
if (!lang) return null;
|
|
113
|
+
const code = lang.substring(0, 2);
|
|
114
|
+
const name = ISO6391.getName(code) || code;
|
|
115
|
+
return { code, name };
|
|
116
|
+
}
|
|
66
117
|
|
|
67
|
-
// src/steps/
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
async function copyInput(el) {
|
|
75
|
-
try {
|
|
76
|
-
return await el.inputValue();
|
|
77
|
-
} catch {
|
|
78
|
-
}
|
|
118
|
+
// src/steps/navigation.ts
|
|
119
|
+
async function openPage(world, path) {
|
|
120
|
+
const { page } = world;
|
|
121
|
+
const result = await page.goto(path);
|
|
122
|
+
expect(result?.status()).toBeLessThan(400);
|
|
123
|
+
await waitForIdle(page);
|
|
124
|
+
world.lang ??= await getLang(page) || void 0;
|
|
79
125
|
}
|
|
80
|
-
async function
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
126
|
+
Given("I'm on the homepage", async function() {
|
|
127
|
+
await openPage(this, "/");
|
|
128
|
+
});
|
|
129
|
+
Given("I'm on page {string}", async function(path) {
|
|
130
|
+
await openPage(this, path);
|
|
131
|
+
});
|
|
132
|
+
Given("all popups are closed", async function() {
|
|
133
|
+
await suppressInterferences(this.page, { lang: this.lang?.code });
|
|
134
|
+
});
|
|
135
|
+
Then("I should be on page {string}", async function(expectedPath) {
|
|
136
|
+
await eventually(async () => {
|
|
137
|
+
const { path: actualPath } = splitUrl(this.page.url());
|
|
138
|
+
if (expectedPath.includes(":")) {
|
|
139
|
+
const { regexp, names } = pathRegexp(expectedPath);
|
|
140
|
+
expect(actualPath, `Expected path ${actualPath} to match pattern ${expectedPath}`).toMatch(regexp);
|
|
141
|
+
const match = actualPath.match(regexp);
|
|
142
|
+
this.pathParams = Object.fromEntries(names.map((name, i) => [name, decodeURIComponent(match[i + 1])]));
|
|
143
|
+
} else {
|
|
144
|
+
expect(actualPath).toEqual(expectedPath);
|
|
145
|
+
delete this.pathParams;
|
|
86
146
|
}
|
|
87
|
-
}
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
When("I go back to the previous page", async function() {
|
|
150
|
+
await this.page.goBack();
|
|
151
|
+
await waitForIdle(this.page);
|
|
152
|
+
});
|
|
153
|
+
var TIMEOUT = 2500;
|
|
154
|
+
async function press(el, action) {
|
|
155
|
+
if (action === "hover") {
|
|
156
|
+
await el.hover({ timeout: TIMEOUT });
|
|
157
|
+
} else {
|
|
158
|
+
await el.click({
|
|
159
|
+
button: action === "right-click" ? "right" : "left",
|
|
160
|
+
clickCount: action === "double-click" ? 2 : 1,
|
|
161
|
+
timeout: TIMEOUT
|
|
162
|
+
});
|
|
88
163
|
}
|
|
89
164
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
165
|
+
When(
|
|
166
|
+
"I {click|double-click|right-click|hover} {locator}",
|
|
167
|
+
async function(action, selector) {
|
|
168
|
+
const prevUrl = this.page.url();
|
|
169
|
+
const el = await fuzzyLocator(this.page, selector);
|
|
170
|
+
await press(el, action);
|
|
171
|
+
await waitAfterInteraction(this.page, el, { prevUrl });
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
When(
|
|
175
|
+
"I {click|double-click|right-click|hover} {locator} while holding {keys}",
|
|
176
|
+
async function(action, selector, combo) {
|
|
177
|
+
const prevUrl = this.page.url();
|
|
178
|
+
const el = await fuzzyLocator(this.page, selector);
|
|
179
|
+
const keys = [...combo.modifiers, combo.key];
|
|
180
|
+
for (const m of keys) await this.page.keyboard.down(m);
|
|
181
|
+
await press(el, action);
|
|
182
|
+
for (const m of keys.reverse()) await this.page.keyboard.up(m);
|
|
183
|
+
await waitAfterInteraction(this.page, el, { prevUrl });
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
When("I scroll {locator} into view", async function(selector) {
|
|
99
187
|
const el = await fuzzyLocator(this.page, selector);
|
|
100
|
-
|
|
101
|
-
await el.fill(String(value), { timeout: TIMEOUT });
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// src/steps/form.ts
|
|
105
|
-
var form_exports = {};
|
|
106
|
-
__export(form_exports, {
|
|
107
|
-
check: () => check,
|
|
108
|
-
clear: () => clear,
|
|
109
|
-
focus: () => focus,
|
|
110
|
-
set: () => set,
|
|
111
|
-
setRange: () => setRange
|
|
188
|
+
await el.scrollIntoViewIfNeeded({ timeout: TIMEOUT });
|
|
112
189
|
});
|
|
113
190
|
var TIMEOUT2 = 500;
|
|
114
191
|
var DELAY = 500;
|
|
115
|
-
|
|
192
|
+
When("I set {locator} to {value}", async function(selector, value) {
|
|
116
193
|
const el = await fuzzyLocator(this.page, selector);
|
|
117
194
|
await setFieldValue(el, value, { timeout: TIMEOUT2 });
|
|
118
195
|
await sleep(DELAY);
|
|
119
196
|
});
|
|
120
|
-
|
|
197
|
+
When(
|
|
121
198
|
"I set {locator} to range of {value} to {value}",
|
|
122
199
|
async function(selector, from, to) {
|
|
123
200
|
const el = await fuzzyLocator(this.page, selector);
|
|
@@ -125,12 +202,12 @@ var setRange = When(
|
|
|
125
202
|
await sleep(DELAY);
|
|
126
203
|
}
|
|
127
204
|
);
|
|
128
|
-
|
|
205
|
+
When("I clear {locator}", async function(selector) {
|
|
129
206
|
const el = await fuzzyLocator(this.page, selector);
|
|
130
207
|
await setFieldValue(el, null, { timeout: TIMEOUT2 });
|
|
131
208
|
await sleep(DELAY);
|
|
132
209
|
});
|
|
133
|
-
|
|
210
|
+
When(
|
|
134
211
|
"I {check|uncheck} {locator}",
|
|
135
212
|
async function(check2, selector) {
|
|
136
213
|
const el = await fuzzyLocator(this.page, selector);
|
|
@@ -139,7 +216,7 @@ var check = When(
|
|
|
139
216
|
},
|
|
140
217
|
"For checkbox input or switch component"
|
|
141
218
|
);
|
|
142
|
-
|
|
219
|
+
When("I {focus|blur} {locator}", async function(focus2, selector) {
|
|
143
220
|
const el = await fuzzyLocator(this.page, selector);
|
|
144
221
|
if (focus2) {
|
|
145
222
|
await el.focus({ timeout: TIMEOUT2 });
|
|
@@ -147,33 +224,19 @@ var focus = When("I {focus|blur} {locator}", async function(focus2, selector) {
|
|
|
147
224
|
await el.blur({ timeout: TIMEOUT2 });
|
|
148
225
|
}
|
|
149
226
|
});
|
|
150
|
-
|
|
151
|
-
// src/steps/keyboard.ts
|
|
152
|
-
var keyboard_exports = {};
|
|
153
|
-
__export(keyboard_exports, {
|
|
154
|
-
press: () => press,
|
|
155
|
-
type: () => type
|
|
156
|
-
});
|
|
157
227
|
var DELAY2 = 500;
|
|
158
|
-
|
|
228
|
+
When("I press {keys}", async function(combo) {
|
|
159
229
|
for (const m of combo.modifiers) await this.page.keyboard.down(m);
|
|
160
230
|
await this.page.keyboard.press(combo.key);
|
|
161
231
|
for (const m of combo.modifiers.toReversed()) await this.page.keyboard.up(m);
|
|
162
232
|
await sleep(DELAY2);
|
|
163
233
|
});
|
|
164
|
-
|
|
234
|
+
When("I type {string}", async function(value) {
|
|
165
235
|
await this.page.keyboard.type(value, { delay: 200 });
|
|
166
236
|
await sleep(DELAY2);
|
|
167
237
|
});
|
|
168
|
-
|
|
169
|
-
// src/steps/mailbox.ts
|
|
170
|
-
var mailbox_exports = {};
|
|
171
|
-
__export(mailbox_exports, {
|
|
172
|
-
receive: () => receive,
|
|
173
|
-
view: () => view
|
|
174
|
-
});
|
|
175
238
|
var MAX_RECEIVE_WAIT = 12e4;
|
|
176
|
-
|
|
239
|
+
Given(
|
|
177
240
|
`I'm viewing an email sent to {string} with subject {string}`,
|
|
178
241
|
async function(address, subject) {
|
|
179
242
|
const emails = await receiveMail(address, { full: true, after: this.startTime, subject, limit: 1 });
|
|
@@ -185,7 +248,7 @@ var view = Given(
|
|
|
185
248
|
await this.page.setContent(email.html ?? textToHtml(email.text), { waitUntil: "domcontentloaded" });
|
|
186
249
|
}
|
|
187
250
|
);
|
|
188
|
-
|
|
251
|
+
Then(
|
|
189
252
|
"I received an email sent to {string} with subject {string}",
|
|
190
253
|
async function(address, subject) {
|
|
191
254
|
const emails = await receiveMail(address, {
|
|
@@ -206,119 +269,37 @@ var receive = Then(
|
|
|
206
269
|
});
|
|
207
270
|
}
|
|
208
271
|
);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
clickHold: () => clickHold,
|
|
215
|
-
scroll: () => scroll
|
|
216
|
-
});
|
|
217
|
-
var TIMEOUT3 = 2500;
|
|
218
|
-
async function press2(el, action) {
|
|
219
|
-
if (action === "hover") {
|
|
220
|
-
await el.hover({ timeout: TIMEOUT3 });
|
|
221
|
-
} else {
|
|
222
|
-
await el.click({
|
|
223
|
-
button: action === "right-click" ? "right" : "left",
|
|
224
|
-
clickCount: action === "double-click" ? 2 : 1,
|
|
225
|
-
timeout: TIMEOUT3
|
|
226
|
-
});
|
|
272
|
+
var TIMEOUT3 = 500;
|
|
273
|
+
async function copyInput(el) {
|
|
274
|
+
try {
|
|
275
|
+
return await el.inputValue();
|
|
276
|
+
} catch {
|
|
227
277
|
}
|
|
228
278
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
);
|
|
238
|
-
var clickHold = When(
|
|
239
|
-
"I {click|double-click|right-click|hover} {locator} while holding {keys}",
|
|
240
|
-
async function(action, selector, combo) {
|
|
241
|
-
const prevUrl = this.page.url();
|
|
242
|
-
const el = await fuzzyLocator(this.page, selector);
|
|
243
|
-
const keys = [...combo.modifiers, combo.key];
|
|
244
|
-
for (const m of keys) await this.page.keyboard.down(m);
|
|
245
|
-
await press2(el, action);
|
|
246
|
-
for (const m of keys.reverse()) await this.page.keyboard.up(m);
|
|
247
|
-
await waitAfterInteraction(this.page, el, { prevUrl });
|
|
279
|
+
async function copyLink(el) {
|
|
280
|
+
try {
|
|
281
|
+
const tag = await el.evaluate((n) => n.tagName.toLowerCase());
|
|
282
|
+
const href = tag === "a" ? await el.getAttribute("href") : null;
|
|
283
|
+
if (href) {
|
|
284
|
+
return href.startsWith("mailto:") ? href.replace(/^mailto:/i, "") : href;
|
|
285
|
+
}
|
|
286
|
+
} catch {
|
|
248
287
|
}
|
|
249
|
-
);
|
|
250
|
-
var scroll = When("I scroll {locator} into view", async function(selector) {
|
|
251
|
-
const el = await fuzzyLocator(this.page, selector);
|
|
252
|
-
await el.scrollIntoViewIfNeeded({ timeout: TIMEOUT3 });
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
// src/steps/navigation.ts
|
|
256
|
-
var navigation_exports = {};
|
|
257
|
-
__export(navigation_exports, {
|
|
258
|
-
assertPath: () => assertPath,
|
|
259
|
-
back: () => back,
|
|
260
|
-
navHome: () => navHome,
|
|
261
|
-
navPath: () => navPath,
|
|
262
|
-
popupClosed: () => popupClosed
|
|
263
|
-
});
|
|
264
|
-
var scrapeLang = metascraper([metascraperLang()]);
|
|
265
|
-
async function getLang(page) {
|
|
266
|
-
const html = "html" in page ? page.html : await page.content();
|
|
267
|
-
const url = typeof page.url === "function" ? page.url() : page.url;
|
|
268
|
-
const { lang = null } = await scrapeLang({ html, url });
|
|
269
|
-
if (!lang) return null;
|
|
270
|
-
const code = lang.substring(0, 2);
|
|
271
|
-
const name = ISO6391.getName(code) || code;
|
|
272
|
-
return { code, name };
|
|
273
288
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
async function openPage(world, path) {
|
|
277
|
-
const { page } = world;
|
|
278
|
-
const result = await page.goto(path);
|
|
279
|
-
expect(result?.status()).toBeLessThan(400);
|
|
280
|
-
await waitForIdle(page);
|
|
281
|
-
world.lang ??= await getLang(page) || void 0;
|
|
289
|
+
async function copyText(el) {
|
|
290
|
+
return await el.textContent() ?? null;
|
|
282
291
|
}
|
|
283
|
-
|
|
284
|
-
await
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
await openPage(this, path);
|
|
288
|
-
});
|
|
289
|
-
var popupClosed = Given("all popups are closed", async function() {
|
|
290
|
-
await suppressInterferences(this.page, { lang: this.lang?.code });
|
|
291
|
-
});
|
|
292
|
-
var assertPath = Then("I should be on page {string}", async function(expectedPath) {
|
|
293
|
-
await eventually(async () => {
|
|
294
|
-
const { path: actualPath } = splitUrl(this.page.url());
|
|
295
|
-
if (expectedPath.includes(":")) {
|
|
296
|
-
const { regexp, names } = pathRegexp(expectedPath);
|
|
297
|
-
expect(actualPath, `Expected path ${actualPath} to match pattern ${expectedPath}`).toMatch(regexp);
|
|
298
|
-
const match = actualPath.match(regexp);
|
|
299
|
-
this.pathParams = Object.fromEntries(names.map((name, i) => [name, decodeURIComponent(match[i + 1])]));
|
|
300
|
-
} else {
|
|
301
|
-
expect(actualPath).toEqual(expectedPath);
|
|
302
|
-
delete this.pathParams;
|
|
303
|
-
}
|
|
304
|
-
});
|
|
292
|
+
When("I copy {locator} to the clipboard", async function(selector) {
|
|
293
|
+
const el = await fuzzyLocator(this.page, selector);
|
|
294
|
+
let value = await copyInput(el) ?? await copyLink(el) ?? await copyText(el);
|
|
295
|
+
this.clipboard = { value };
|
|
305
296
|
});
|
|
306
|
-
|
|
307
|
-
await this.page
|
|
308
|
-
|
|
297
|
+
When("I paste from the clipboard into {locator}", async function(selector) {
|
|
298
|
+
const el = await fuzzyLocator(this.page, selector);
|
|
299
|
+
const value = this.clipboard?.value || "";
|
|
300
|
+
await el.fill(String(value), { timeout: TIMEOUT3 });
|
|
309
301
|
});
|
|
310
302
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
...Object.values(navigation_exports),
|
|
315
|
-
...Object.values(mouse_exports),
|
|
316
|
-
...Object.values(form_exports),
|
|
317
|
-
...Object.values(keyboard_exports),
|
|
318
|
-
...Object.values(mailbox_exports),
|
|
319
|
-
...Object.values(clipboard_exports)
|
|
320
|
-
];
|
|
321
|
-
|
|
322
|
-
export { stepsDefinitions, typeDefinitions };
|
|
323
|
-
//# sourceMappingURL=chunk-A7ZD72RB.js.map
|
|
324
|
-
//# sourceMappingURL=chunk-A7ZD72RB.js.map
|
|
303
|
+
export { Given, Then, When, createRegistry, registry, typeDefinitions };
|
|
304
|
+
//# sourceMappingURL=chunk-D6IA6AFW.js.map
|
|
305
|
+
//# sourceMappingURL=chunk-D6IA6AFW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/parameters.ts","../src/registry.ts","../src/utils/test-helpers.ts","../src/steps/assert.ts","../src/utils/get-lang.ts","../src/steps/navigation.ts","../src/steps/mouse.ts","../src/steps/form.ts","../src/steps/keyboard.ts","../src/steps/mailbox.ts","../src/steps/clipboard.ts"],"names":["type","contain","expect","fuzzyLocator","TIMEOUT","check","focus","DELAY","sleep"],"mappings":"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","file":"chunk-D6IA6AFW.js","sourcesContent":["import { booleanParameter, enumParameter, keysParameter, locatorParameter, valueParameter } from '@letsrunit/gherkin';\n\nexport const typeDefinitions = [\n locatorParameter(),\n valueParameter(),\n keysParameter(),\n\n booleanParameter('visible', 'hidden'),\n booleanParameter('enabled', 'disabled', /((?:en|dis)abled)/),\n booleanParameter('checked', 'unchecked', /((?:un)?checked)/),\n booleanParameter('contains', 'not contains', /((?:not )?contains)/),\n\n booleanParameter('check', 'uncheck', /((?:un)?check)/),\n booleanParameter('focus', 'blur'),\n\n enumParameter(['click', 'double-click', 'right-click', 'hover'], /((?:double-|right-)?click|hover)/),\n];\n","import {\n CucumberExpression,\n ParameterType,\n ParameterTypeRegistry,\n RegularExpression,\n} from '@cucumber/cucumber-expressions';\nimport { sanitizeStepDefinition, type ParameterTypeDefinition } from '@letsrunit/gherkin';\nimport { typeDefinitions } from './parameters';\nimport type { StepDefinition, StepHandler, StepType } from './types';\n\ninterface Entry {\n type: StepType;\n expression: string | RegExp;\n fn: StepHandler;\n comment?: string;\n expr: CucumberExpression | RegularExpression;\n}\n\nexport function createRegistry() {\n const _paramRegistry = new ParameterTypeRegistry();\n const _entries: Entry[] = [];\n\n for (const t of typeDefinitions) {\n _paramRegistry.defineParameterType(\n new ParameterType(t.name, t.regexp, null, t.transformer as any, t.useForSnippets),\n );\n }\n\n return {\n /** IStepRegistry-compatible defs (source = String(expression), no raw expr). */\n get defs() {\n return _entries.map(({ type, expression, fn, comment }) => ({\n type,\n source: String(expression),\n fn,\n comment,\n }));\n },\n\n /** Raw step definitions with original expression — used by define.ts for Cucumber registration. */\n get definitions(): StepDefinition[] {\n return _entries.map(({ type, expression, fn, comment }) => ({ type, expression, fn, comment }));\n },\n\n defineStep(type: StepType, expression: string | RegExp, fn: StepHandler, comment?: string): void {\n const expr =\n typeof expression === 'string'\n ? new CucumberExpression(sanitizeStepDefinition(expression), _paramRegistry)\n : new RegularExpression(expression, _paramRegistry);\n _entries.push({ type, expression, fn, comment, expr });\n },\n\n defineParameterType(type: ParameterTypeDefinition<unknown>): void {\n _paramRegistry.defineParameterType(\n new ParameterType(type.name, type.regexp, null, type.transformer, type.useForSnippets),\n );\n },\n\n match(text: string) {\n for (const entry of _entries) {\n const args = entry.expr.match(text);\n if (args) {\n return {\n def: { type: entry.type, source: String(entry.expression), fn: entry.fn, comment: entry.comment },\n values: args.map((a) => a.getValue(null)),\n args,\n };\n }\n }\n return null;\n },\n };\n}\n\nexport const registry = createRegistry();\n\nexport function Given(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {\n const def: StepDefinition = { type: 'Given', expression, fn, comment };\n registry.defineStep('Given', expression, fn, comment);\n return def;\n}\n\nexport function When(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {\n const def: StepDefinition = { type: 'When', expression, fn, comment };\n registry.defineStep('When', expression, fn, comment);\n return def;\n}\n\nexport function Then(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {\n const def: StepDefinition = { type: 'Then', expression, fn, comment };\n registry.defineStep('Then', expression, fn, comment);\n return def;\n}\n","import { expect, type Expect } from '@playwright/test';\n\nexport function expectOrNot<T>(\n actual: T,\n toBe: boolean\n): ReturnType<Expect<T>> | ReturnType<ReturnType<Expect<T>>['not']> {\n return toBe ? expect(actual) : expect(actual).not;\n}\n","import { fuzzyLocator } from '@letsrunit/playwright';\nimport { expectOrNot } from '../utils/test-helpers';\nimport { Then } from '../registry';\n\nconst WAIT_TIMEOUT = 5000;\n\nexport const see = Then(\n 'The page {contains|not contains} {locator}',\n async function (visible: boolean, selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n await expectOrNot(el, visible).toBeVisible({ timeout: WAIT_TIMEOUT });\n },\n);\n\nexport const contain = Then(\n '{locator} {contains|not contains} {locator}',\n async function (selector: string, contain: boolean, child: string) {\n const el = await fuzzyLocator(this.page, selector);\n const childElement = el.locator(child);\n await expectOrNot(childElement, contain).toBeAttached({ timeout: WAIT_TIMEOUT });\n },\n);\n","import type { Snapshot } from '@letsrunit/playwright';\nimport { Page } from '@playwright/test';\nimport ISO6391 from 'iso-639-1';\nimport metascraper from 'metascraper';\nimport metascraperLang from 'metascraper-lang';\n\nconst scrapeLang = metascraper([metascraperLang()]);\n\nexport async function getLang(\n page: Pick<Page, 'content' | 'url'> | Snapshot,\n): Promise<{ code: string; name: string} | null> {\n const html = 'html' in page ? page.html : await page.content();\n const url = typeof page.url === 'function' ? page.url() : page.url;\n\n const { lang = null } = await scrapeLang({ html, url });\n if (!lang) return null;\n\n const code = lang.substring(0, 2);\n const name = ISO6391.getName(code) || code;\n\n return { code, name };\n}\n","import { suppressInterferences, waitForIdle } from '@letsrunit/playwright';\nimport { eventually, pathRegexp, splitUrl } from '@letsrunit/utils';\nimport { expect } from '@playwright/test';\nimport { World } from '../types';\nimport { getLang } from '../utils/get-lang';\nimport { Given, Then, When } from '../registry';\n\nasync function openPage(world: World, path: string): Promise<void> {\n const { page } = world;\n\n const result = await page.goto(path);\n expect(result?.status()).toBeLessThan(400);\n\n await waitForIdle(page);\n\n world.lang ??= (await getLang(page)) || undefined;\n}\n\nexport const navHome = Given(\"I'm on the homepage\", async function () {\n await openPage(this, '/');\n});\n\nexport const navPath = Given(\"I'm on page {string}\", async function (path: string) {\n await openPage(this, path);\n});\n\nexport const popupClosed = Given('all popups are closed', async function (){\n await suppressInterferences(this.page, { lang: this.lang?.code });\n});\n\nexport const assertPath = Then('I should be on page {string}', async function (expectedPath: string) {\n await eventually(async () => {\n const { path: actualPath } = splitUrl(this.page.url());\n\n if (expectedPath.includes(':')) {\n const { regexp, names } = pathRegexp(expectedPath);\n\n expect(actualPath, `Expected path ${actualPath} to match pattern ${expectedPath}`).toMatch(regexp);\n\n const match = actualPath.match(regexp);\n this.pathParams = Object.fromEntries(names.map((name, i) => [name, decodeURIComponent(match![i + 1])]));\n } else {\n expect(actualPath).toEqual(expectedPath);\n delete this.pathParams;\n }\n });\n});\n\nexport const back = When('I go back to the previous page', async function () {\n await this.page.goBack();\n await waitForIdle(this.page);\n});\n","import type { KeyCombo } from '@letsrunit/gherkin';\nimport { fuzzyLocator, waitAfterInteraction } from '@letsrunit/playwright';\nimport type { Locator } from '@playwright/test';\nimport { When } from '../registry';\n\nconst TIMEOUT = 2500;\n\ntype MouseAction = 'click' | 'double-click' | 'right-click' | 'hover';\n\nasync function press(el: Locator, action: MouseAction) {\n if (action === 'hover') {\n await el.hover({ timeout: TIMEOUT });\n } else {\n await el.click({\n button: action === 'right-click' ? 'right' : 'left',\n clickCount: action === 'double-click' ? 2 : 1,\n timeout: TIMEOUT,\n });\n }\n}\n\nexport const click = When(\n 'I {click|double-click|right-click|hover} {locator}',\n async function (action: MouseAction, selector: string) {\n const prevUrl = this.page.url();\n\n const el = await fuzzyLocator(this.page, selector);\n await press(el, action);\n\n await waitAfterInteraction(this.page, el, { prevUrl });\n },\n);\n\nexport const clickHold = When(\n 'I {click|double-click|right-click|hover} {locator} while holding {keys}',\n async function (action: MouseAction, selector: string, combo: KeyCombo) {\n const prevUrl = this.page.url();\n\n const el = await fuzzyLocator(this.page, selector);\n const keys = [...combo.modifiers, combo.key];\n\n for (const m of keys) await this.page.keyboard.down(m);\n await press(el, action);\n for (const m of keys.reverse()) await this.page.keyboard.up(m);\n\n await waitAfterInteraction(this.page, el, { prevUrl });\n },\n);\n\nexport const scroll = When('I scroll {locator} into view', async function (selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n await el.scrollIntoViewIfNeeded({ timeout: TIMEOUT });\n});\n","import { fuzzyLocator, setFieldValue } from '@letsrunit/playwright';\nimport { type Scalar, sleep } from '@letsrunit/utils';\nimport { When } from '../registry';\n\nconst TIMEOUT = 500;\nconst DELAY = 500;\n\nexport const set = When('I set {locator} to {value}', async function (selector: string, value: Scalar | Scalar[]) {\n const el = await fuzzyLocator(this.page, selector);\n await setFieldValue(el, value, { timeout: TIMEOUT });\n await sleep(DELAY);\n});\n\nexport const setRange = When(\n 'I set {locator} to range of {value} to {value}',\n async function (selector: string, from: Scalar, to: Scalar) {\n const el = await fuzzyLocator(this.page, selector);\n await setFieldValue(el, { from, to }, { timeout: TIMEOUT });\n await sleep(DELAY);\n },\n);\n\nexport const clear = When('I clear {locator}', async function (selector) {\n const el = await fuzzyLocator(this.page, selector);\n await setFieldValue(el, null, { timeout: TIMEOUT });\n await sleep(DELAY);\n});\n\nexport const check = When(\n 'I {check|uncheck} {locator}',\n async function (check: boolean, selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n await setFieldValue(el, check, { timeout: TIMEOUT });\n await sleep(DELAY);\n },\n 'For checkbox input or switch component',\n);\n\nexport const focus = When('I {focus|blur} {locator}', async function (focus: boolean, selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n\n if (focus) {\n await el.focus({ timeout: TIMEOUT });\n } else {\n await el.blur({ timeout: TIMEOUT });\n }\n});\n","import type { KeyCombo } from '@letsrunit/gherkin';\nimport { sleep } from '@letsrunit/utils';\nimport { When } from '../registry';\n\nconst DELAY = 500;\n\nexport const press = When('I press {keys}', async function (combo: KeyCombo) {\n // Hold modifiers\n for (const m of combo.modifiers) await this.page.keyboard.down(m);\n\n // Press final key\n await this.page.keyboard.press(combo.key);\n\n // Release modifiers (reverse order)\n for (const m of combo.modifiers.toReversed()) await this.page.keyboard.up(m);\n\n await sleep(DELAY);\n});\n\nexport const type = When('I type {string}', async function (value: string) {\n await this.page.keyboard.type(value, { delay: 200 });\n await sleep(DELAY);\n});\n","import { receiveMail, toEml } from '@letsrunit/mailbox';\nimport { asFilename, textToHtml } from '@letsrunit/utils';\nimport { Given, Then } from '../registry';\n\nconst MAX_RECEIVE_WAIT = 120_000; // 2 minutes\n\nexport const view = Given(\n `I'm viewing an email sent to {string} with subject {string}`,\n async function (address: string, subject: string) {\n const emails = await receiveMail(address, { full: true, after: this.startTime, subject, limit: 1 });\n if (emails.length === 0) {\n throw new Error(`Did not receive an email with subject \"${subject}\"`);\n }\n\n const email = emails[0];\n\n await this.page.goto('about:blank', { waitUntil: 'load' });\n await this.page.setContent(email.html ?? textToHtml(email.text!), { waitUntil: 'domcontentloaded' });\n },\n);\n\nexport const receive = Then(\n 'I received an email sent to {string} with subject {string}',\n async function (address: string, subject: string) {\n const emails = await receiveMail(address, {\n after: this.startTime,\n full: true,\n subject,\n wait: true,\n timeout: MAX_RECEIVE_WAIT,\n limit: 1,\n });\n\n if (emails.length === 0) {\n throw new Error(`Did not receive an email with subject \"${subject}\"`);\n }\n\n const email = emails[0];\n\n this.attach(toEml(email), {\n mediaType: 'message/rfc822',\n fileName: asFilename(email.subject, 'eml'),\n });\n },\n);\n","import { fuzzyLocator } from '@letsrunit/playwright';\nimport type { Locator } from '@playwright/test';\nimport { When } from '../registry';\n\nconst TIMEOUT = 500;\n\nasync function copyInput(el: Locator): Promise<string | undefined> {\n try {\n return await el.inputValue();\n } catch {}\n}\n\nasync function copyLink(el: Locator): Promise<string | undefined> {\n try {\n const tag = await el.evaluate<string>((n: Element) => n.tagName.toLowerCase());\n const href = tag === 'a' ? await el.getAttribute('href') : null;\n if (href) {\n return href.startsWith('mailto:') ? href.replace(/^mailto:/i, '') : href;\n }\n } catch {}\n}\n\nasync function copyText(el: Locator): Promise<string | null> {\n return (await el.textContent()) ?? null;\n}\n\nexport const copy = When('I copy {locator} to the clipboard', async function (selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n let value = (await copyInput(el)) ?? (await copyLink(el)) ?? (await copyText(el));\n\n this.clipboard = { value };\n});\n\nexport const paste = When('I paste from the clipboard into {locator}', async function (selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n const value = this.clipboard?.value || '';\n\n await el.fill(String(value), { timeout: TIMEOUT });\n});\n"]}
|
package/dist/define.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { typeDefinitions,
|
|
1
|
+
import { typeDefinitions, registry } from './chunk-D6IA6AFW.js';
|
|
2
2
|
import { defineParameterType, Given, When, Then, BeforeAll, Before, After } from '@cucumber/cucumber';
|
|
3
3
|
import { createFieldEngine, createDateEngine, browse } from '@letsrunit/playwright';
|
|
4
4
|
import { selectors, chromium } from '@playwright/test';
|
|
@@ -7,7 +7,7 @@ import { sanitizeStepDefinition } from '@letsrunit/gherkin';
|
|
|
7
7
|
for (const type of typeDefinitions) {
|
|
8
8
|
defineParameterType(type);
|
|
9
9
|
}
|
|
10
|
-
for (const step of
|
|
10
|
+
for (const step of registry.definitions) {
|
|
11
11
|
const def = step.type === "Given" ? Given : step.type === "When" ? When : Then;
|
|
12
12
|
def(sanitizeStepDefinition(step.expression), step.fn);
|
|
13
13
|
}
|
package/dist/define.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/define.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"sources":["../src/define.ts"],"names":[],"mappings":";;;;;;AAQA,KAAA,MAAW,QAAQ,eAAA,EAAiB;AAClC,EAAA,mBAAA,CAAoB,IAAI,CAAA;AAC1B;AAEA,KAAA,MAAW,IAAA,IAAQ,SAAS,WAAA,EAAa;AACvC,EAAA,MAAM,GAAA,GAAM,KAAK,IAAA,KAAS,OAAA,GAAU,QAAQ,IAAA,CAAK,IAAA,KAAS,SAAS,IAAA,GAAO,IAAA;AAC1E,EAAA,GAAA,CAAI,sBAAA,CAAuB,IAAA,CAAK,UAAU,CAAA,EAAG,KAAK,EAAE,CAAA;AACtD;AAEA,IAAI,mBAAA,GAAsB,KAAA;AAE1B,SAAA,CAAU,iBAAkB;AAC1B,EAAA,IAAI,mBAAA,EAAqB;AACzB,EAAA,IAAI;AACF,IAAA,MAAM,SAAA,CAAU,QAAA,CAAS,OAAA,EAAS,iBAAiB,CAAA;AACnD,IAAA,MAAM,SAAA,CAAU,QAAA,CAAS,MAAA,EAAQ,gBAAgB,CAAA;AACjD,IAAA,mBAAA,GAAsB,IAAA;AAAA,EACxB,CAAA,CAAA,MAAQ;AAAA,EAAC;AACX,CAAC,CAAA;AAED,MAAA,CAAO,iBAAkB;AACvB,EAAA,MAAM,UAAU,MAAM,QAAA,CAAS,OAAO,EAAE,QAAA,EAAU,MAAM,CAAA;AACxD,EAAA,IAAA,CAAK,QAAA,GAAW,OAAA;AAChB,EAAA,IAAA,CAAK,IAAA,GAAO,MAAM,MAAA,CAAO,OAAA,EAAS,KAAK,UAAU,CAAA;AACjD,EAAA,IAAA,CAAK,SAAA,GAAY,KAAK,GAAA,EAAI;AAC5B,CAAC,CAAA;AAED,KAAA,CAAM,iBAAkB;AACtB,EAAA,MAAM,IAAA,CAAK,UAAU,KAAA,EAAM;AAC7B,CAAC,CAAA","file":"define.js","sourcesContent":["import { After, Before, BeforeAll, defineParameterType, Given, Then, When } from '@cucumber/cucumber';\nimport { browse, createDateEngine, createFieldEngine } from '@letsrunit/playwright';\nimport { chromium, selectors } from '@playwright/test';\nimport { sanitizeStepDefinition } from '@letsrunit/gherkin';\nimport { typeDefinitions } from './parameters';\nimport { registry } from './registry';\nimport './steps'; // ensure built-in steps are registered before Cucumber receives them\n\nfor (const type of typeDefinitions) {\n defineParameterType(type);\n}\n\nfor (const step of registry.definitions) {\n const def = step.type === 'Given' ? Given : step.type === 'When' ? When : Then;\n def(sanitizeStepDefinition(step.expression), step.fn);\n}\n\nlet selectorsRegistered = false;\n\nBeforeAll(async function () {\n if (selectorsRegistered) return;\n try {\n await selectors.register('field', createFieldEngine);\n await selectors.register('date', createDateEngine);\n selectorsRegistered = true;\n } catch {}\n});\n\nBefore(async function () {\n const browser = await chromium.launch({ headless: true });\n this._browser = browser;\n this.page = await browse(browser, this.parameters);\n this.startTime = Date.now();\n});\n\nAfter(async function () {\n await this._browser?.close();\n});\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as _letsrunit_gherkin from '@letsrunit/gherkin';
|
|
2
|
+
import { ParameterTypeDefinition } from '@letsrunit/gherkin';
|
|
2
3
|
import * as _letsrunit_utils from '@letsrunit/utils';
|
|
3
4
|
import { World as World$1 } from '@cucumber/cucumber';
|
|
4
5
|
import { BrowserContextOptions, Page } from '@playwright/test';
|
|
5
6
|
import { Readable } from 'node:stream';
|
|
6
|
-
|
|
7
|
-
declare const typeDefinitions: (_letsrunit_gherkin.ParameterTypeDefinition<_letsrunit_utils.Scalar | _letsrunit_utils.Scalar[]> | _letsrunit_gherkin.ParameterTypeDefinition<_letsrunit_gherkin.KeyCombo> | _letsrunit_gherkin.ParameterTypeDefinition<boolean>)[];
|
|
7
|
+
import * as _cucumber_cucumber_expressions from '@cucumber/cucumber-expressions';
|
|
8
8
|
|
|
9
9
|
interface World extends World$1<BrowserContextOptions> {
|
|
10
10
|
page: Page;
|
|
@@ -25,7 +25,7 @@ interface StepDefinition {
|
|
|
25
25
|
comment?: string;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
declare const
|
|
28
|
+
declare const typeDefinitions: (_letsrunit_gherkin.ParameterTypeDefinition<_letsrunit_utils.Scalar | _letsrunit_utils.Scalar[]> | _letsrunit_gherkin.ParameterTypeDefinition<_letsrunit_gherkin.KeyCombo> | _letsrunit_gherkin.ParameterTypeDefinition<boolean>)[];
|
|
29
29
|
|
|
30
30
|
type AttachData = string | Buffer | Readable;
|
|
31
31
|
type AttachOptions = string | {
|
|
@@ -34,4 +34,54 @@ type AttachOptions = string | {
|
|
|
34
34
|
};
|
|
35
35
|
declare function toFile(data: AttachData, options?: AttachOptions): File;
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
declare function createRegistry(): {
|
|
38
|
+
/** IStepRegistry-compatible defs (source = String(expression), no raw expr). */
|
|
39
|
+
readonly defs: {
|
|
40
|
+
type: StepType;
|
|
41
|
+
source: string;
|
|
42
|
+
fn: StepHandler;
|
|
43
|
+
comment: string | undefined;
|
|
44
|
+
}[];
|
|
45
|
+
/** Raw step definitions with original expression — used by define.ts for Cucumber registration. */
|
|
46
|
+
readonly definitions: StepDefinition[];
|
|
47
|
+
defineStep(type: StepType, expression: string | RegExp, fn: StepHandler, comment?: string): void;
|
|
48
|
+
defineParameterType(type: ParameterTypeDefinition<unknown>): void;
|
|
49
|
+
match(text: string): {
|
|
50
|
+
def: {
|
|
51
|
+
type: StepType;
|
|
52
|
+
source: string;
|
|
53
|
+
fn: StepHandler;
|
|
54
|
+
comment: string | undefined;
|
|
55
|
+
};
|
|
56
|
+
values: unknown[];
|
|
57
|
+
args: readonly _cucumber_cucumber_expressions.Argument[];
|
|
58
|
+
} | null;
|
|
59
|
+
};
|
|
60
|
+
declare const registry: {
|
|
61
|
+
/** IStepRegistry-compatible defs (source = String(expression), no raw expr). */
|
|
62
|
+
readonly defs: {
|
|
63
|
+
type: StepType;
|
|
64
|
+
source: string;
|
|
65
|
+
fn: StepHandler;
|
|
66
|
+
comment: string | undefined;
|
|
67
|
+
}[];
|
|
68
|
+
/** Raw step definitions with original expression — used by define.ts for Cucumber registration. */
|
|
69
|
+
readonly definitions: StepDefinition[];
|
|
70
|
+
defineStep(type: StepType, expression: string | RegExp, fn: StepHandler, comment?: string): void;
|
|
71
|
+
defineParameterType(type: ParameterTypeDefinition<unknown>): void;
|
|
72
|
+
match(text: string): {
|
|
73
|
+
def: {
|
|
74
|
+
type: StepType;
|
|
75
|
+
source: string;
|
|
76
|
+
fn: StepHandler;
|
|
77
|
+
comment: string | undefined;
|
|
78
|
+
};
|
|
79
|
+
values: unknown[];
|
|
80
|
+
args: readonly _cucumber_cucumber_expressions.Argument[];
|
|
81
|
+
} | null;
|
|
82
|
+
};
|
|
83
|
+
declare function Given(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition;
|
|
84
|
+
declare function When(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition;
|
|
85
|
+
declare function Then(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition;
|
|
86
|
+
|
|
87
|
+
export { Given, type StepDefinition, type StepHandler, type StepType, Then, When, type World, createRegistry, registry, toFile, typeDefinitions };
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letsrunit/bdd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "BDD step definitions for browser automation with letsrunit",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"testing",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"packageManager": "yarn@4.10.3",
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@cucumber/cucumber-expressions": "^18.1.0",
|
|
55
|
-
"@letsrunit/gherkin": "0.
|
|
56
|
-
"@letsrunit/mailbox": "0.
|
|
57
|
-
"@letsrunit/playwright": "0.
|
|
58
|
-
"@letsrunit/utils": "0.
|
|
55
|
+
"@letsrunit/gherkin": "0.4.1",
|
|
56
|
+
"@letsrunit/mailbox": "0.4.1",
|
|
57
|
+
"@letsrunit/playwright": "0.4.1",
|
|
58
|
+
"@letsrunit/utils": "0.4.1",
|
|
59
59
|
"@playwright/test": "^1.57.0",
|
|
60
60
|
"iso-639-1": "^3.1.5",
|
|
61
61
|
"metascraper": "^5.49.15",
|
package/src/define.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { After, Before, BeforeAll, defineParameterType, Given, Then, When } from '@cucumber/cucumber';
|
|
2
2
|
import { browse, createDateEngine, createFieldEngine } from '@letsrunit/playwright';
|
|
3
3
|
import { chromium, selectors } from '@playwright/test';
|
|
4
|
-
import { typeDefinitions } from './parameters';
|
|
5
|
-
import { stepsDefinitions } from './steps';
|
|
6
4
|
import { sanitizeStepDefinition } from '@letsrunit/gherkin';
|
|
5
|
+
import { typeDefinitions } from './parameters';
|
|
6
|
+
import { registry } from './registry';
|
|
7
|
+
import './steps'; // ensure built-in steps are registered before Cucumber receives them
|
|
7
8
|
|
|
8
9
|
for (const type of typeDefinitions) {
|
|
9
10
|
defineParameterType(type);
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
for (const step of
|
|
13
|
+
for (const step of registry.definitions) {
|
|
13
14
|
const def = step.type === 'Given' ? Given : step.type === 'When' ? When : Then;
|
|
14
15
|
def(sanitizeStepDefinition(step.expression), step.fn);
|
|
15
16
|
}
|
package/src/index.ts
CHANGED
package/src/registry.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CucumberExpression,
|
|
3
|
+
ParameterType,
|
|
4
|
+
ParameterTypeRegistry,
|
|
5
|
+
RegularExpression,
|
|
6
|
+
} from '@cucumber/cucumber-expressions';
|
|
7
|
+
import { sanitizeStepDefinition, type ParameterTypeDefinition } from '@letsrunit/gherkin';
|
|
8
|
+
import { typeDefinitions } from './parameters';
|
|
9
|
+
import type { StepDefinition, StepHandler, StepType } from './types';
|
|
10
|
+
|
|
11
|
+
interface Entry {
|
|
12
|
+
type: StepType;
|
|
13
|
+
expression: string | RegExp;
|
|
14
|
+
fn: StepHandler;
|
|
15
|
+
comment?: string;
|
|
16
|
+
expr: CucumberExpression | RegularExpression;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createRegistry() {
|
|
20
|
+
const _paramRegistry = new ParameterTypeRegistry();
|
|
21
|
+
const _entries: Entry[] = [];
|
|
22
|
+
|
|
23
|
+
for (const t of typeDefinitions) {
|
|
24
|
+
_paramRegistry.defineParameterType(
|
|
25
|
+
new ParameterType(t.name, t.regexp, null, t.transformer as any, t.useForSnippets),
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
/** IStepRegistry-compatible defs (source = String(expression), no raw expr). */
|
|
31
|
+
get defs() {
|
|
32
|
+
return _entries.map(({ type, expression, fn, comment }) => ({
|
|
33
|
+
type,
|
|
34
|
+
source: String(expression),
|
|
35
|
+
fn,
|
|
36
|
+
comment,
|
|
37
|
+
}));
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
/** Raw step definitions with original expression — used by define.ts for Cucumber registration. */
|
|
41
|
+
get definitions(): StepDefinition[] {
|
|
42
|
+
return _entries.map(({ type, expression, fn, comment }) => ({ type, expression, fn, comment }));
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
defineStep(type: StepType, expression: string | RegExp, fn: StepHandler, comment?: string): void {
|
|
46
|
+
const expr =
|
|
47
|
+
typeof expression === 'string'
|
|
48
|
+
? new CucumberExpression(sanitizeStepDefinition(expression), _paramRegistry)
|
|
49
|
+
: new RegularExpression(expression, _paramRegistry);
|
|
50
|
+
_entries.push({ type, expression, fn, comment, expr });
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
defineParameterType(type: ParameterTypeDefinition<unknown>): void {
|
|
54
|
+
_paramRegistry.defineParameterType(
|
|
55
|
+
new ParameterType(type.name, type.regexp, null, type.transformer, type.useForSnippets),
|
|
56
|
+
);
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
match(text: string) {
|
|
60
|
+
for (const entry of _entries) {
|
|
61
|
+
const args = entry.expr.match(text);
|
|
62
|
+
if (args) {
|
|
63
|
+
return {
|
|
64
|
+
def: { type: entry.type, source: String(entry.expression), fn: entry.fn, comment: entry.comment },
|
|
65
|
+
values: args.map((a) => a.getValue(null)),
|
|
66
|
+
args,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const registry = createRegistry();
|
|
76
|
+
|
|
77
|
+
export function Given(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {
|
|
78
|
+
const def: StepDefinition = { type: 'Given', expression, fn, comment };
|
|
79
|
+
registry.defineStep('Given', expression, fn, comment);
|
|
80
|
+
return def;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function When(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {
|
|
84
|
+
const def: StepDefinition = { type: 'When', expression, fn, comment };
|
|
85
|
+
registry.defineStep('When', expression, fn, comment);
|
|
86
|
+
return def;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function Then(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {
|
|
90
|
+
const def: StepDefinition = { type: 'Then', expression, fn, comment };
|
|
91
|
+
registry.defineStep('Then', expression, fn, comment);
|
|
92
|
+
return def;
|
|
93
|
+
}
|
package/src/steps/assert.ts
CHANGED
package/src/steps/clipboard.ts
CHANGED
package/src/steps/form.ts
CHANGED
package/src/steps/index.ts
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
import type { StepDefinition } from '../types';
|
|
2
|
-
import * as assert from './assert';
|
|
3
|
-
import * as clipboard from './clipboard';
|
|
4
|
-
import * as form from './form';
|
|
5
|
-
import * as keyboard from './keyboard';
|
|
6
|
-
import * as mailbox from './mailbox';
|
|
7
|
-
import * as mouse from './mouse';
|
|
8
|
-
import * as navigation from './navigation';
|
|
9
|
-
|
|
10
1
|
// The order matters for the LLM
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
...Object.values(clipboard),
|
|
19
|
-
];
|
|
2
|
+
import './assert';
|
|
3
|
+
import './navigation';
|
|
4
|
+
import './mouse';
|
|
5
|
+
import './form';
|
|
6
|
+
import './keyboard';
|
|
7
|
+
import './mailbox';
|
|
8
|
+
import './clipboard';
|
package/src/steps/keyboard.ts
CHANGED
package/src/steps/mailbox.ts
CHANGED
package/src/steps/mouse.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { KeyCombo } from '@letsrunit/gherkin';
|
|
2
2
|
import { fuzzyLocator, waitAfterInteraction } from '@letsrunit/playwright';
|
|
3
3
|
import type { Locator } from '@playwright/test';
|
|
4
|
-
import { When } from '
|
|
4
|
+
import { When } from '../registry';
|
|
5
5
|
|
|
6
6
|
const TIMEOUT = 2500;
|
|
7
7
|
|
package/src/steps/navigation.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { eventually, pathRegexp, splitUrl } from '@letsrunit/utils';
|
|
|
3
3
|
import { expect } from '@playwright/test';
|
|
4
4
|
import { World } from '../types';
|
|
5
5
|
import { getLang } from '../utils/get-lang';
|
|
6
|
-
import { Given, Then, When } from '
|
|
6
|
+
import { Given, Then, When } from '../registry';
|
|
7
7
|
|
|
8
8
|
async function openPage(world: World, path: string): Promise<void> {
|
|
9
9
|
const { page } = world;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/parameters.ts","../src/steps/assert.ts","../src/utils/test-helpers.ts","../src/steps/wrappers.ts","../src/steps/clipboard.ts","../src/steps/form.ts","../src/steps/keyboard.ts","../src/steps/mailbox.ts","../src/steps/mouse.ts","../src/steps/navigation.ts","../src/utils/get-lang.ts","../src/steps/index.ts"],"names":["contain","fuzzyLocator","TIMEOUT","check","focus","DELAY","sleep","press","expect"],"mappings":"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","file":"chunk-A7ZD72RB.js","sourcesContent":["import { booleanParameter, enumParameter, keysParameter, locatorParameter, valueParameter } from '@letsrunit/gherkin';\n\nexport const typeDefinitions = [\n locatorParameter(),\n valueParameter(),\n keysParameter(),\n\n booleanParameter('visible', 'hidden'),\n booleanParameter('enabled', 'disabled', /((?:en|dis)abled)/),\n booleanParameter('checked', 'unchecked', /((?:un)?checked)/),\n booleanParameter('contains', 'not contains', /((?:not )?contains)/),\n\n booleanParameter('check', 'uncheck', /((?:un)?check)/),\n booleanParameter('focus', 'blur'),\n\n enumParameter(['click', 'double-click', 'right-click', 'hover'], /((?:double-|right-)?click|hover)/),\n];\n","import { fuzzyLocator } from '@letsrunit/playwright';\nimport { expectOrNot } from '../utils/test-helpers';\nimport { Then } from './wrappers';\n\nconst WAIT_TIMEOUT = 5000;\n\nexport const see = Then(\n 'The page {contains|not contains} {locator}',\n async function (visible: boolean, selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n await expectOrNot(el, visible).toBeVisible({ timeout: WAIT_TIMEOUT });\n },\n);\n\nexport const contain = Then(\n '{locator} {contains|not contains} {locator}',\n async function (selector: string, contain: boolean, child: string) {\n const el = await fuzzyLocator(this.page, selector);\n const childElement = el.locator(child);\n await expectOrNot(childElement, contain).toBeAttached({ timeout: WAIT_TIMEOUT });\n },\n);\n","import { expect, type Expect } from '@playwright/test';\n\nexport function expectOrNot<T>(\n actual: T,\n toBe: boolean\n): ReturnType<Expect<T>> | ReturnType<ReturnType<Expect<T>>['not']> {\n return toBe ? expect(actual) : expect(actual).not;\n}\n","import type { StepDefinition, StepHandler } from '../types';\n\nexport function Given(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {\n return { type: 'Given', expression, fn, comment };\n}\n\nexport function When(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {\n return { type: 'When', expression, fn, comment };\n}\n\nexport function Then(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {\n return { type: 'Then', expression, fn, comment };\n}\n","import { fuzzyLocator } from '@letsrunit/playwright';\nimport type { Locator } from '@playwright/test';\nimport { When } from './wrappers';\n\nconst TIMEOUT = 500;\n\nasync function copyInput(el: Locator): Promise<string | undefined> {\n try {\n return await el.inputValue();\n } catch {}\n}\n\nasync function copyLink(el: Locator): Promise<string | undefined> {\n try {\n const tag = await el.evaluate<string>((n: Element) => n.tagName.toLowerCase());\n const href = tag === 'a' ? await el.getAttribute('href') : null;\n if (href) {\n return href.startsWith('mailto:') ? href.replace(/^mailto:/i, '') : href;\n }\n } catch {}\n}\n\nasync function copyText(el: Locator): Promise<string | null> {\n return (await el.textContent()) ?? null;\n}\n\nexport const copy = When('I copy {locator} to the clipboard', async function (selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n let value = (await copyInput(el)) ?? (await copyLink(el)) ?? (await copyText(el));\n\n this.clipboard = { value };\n});\n\nexport const paste = When('I paste from the clipboard into {locator}', async function (selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n const value = this.clipboard?.value || '';\n\n await el.fill(String(value), { timeout: TIMEOUT });\n});\n","import { fuzzyLocator, setFieldValue } from '@letsrunit/playwright';\nimport { type Scalar, sleep } from '@letsrunit/utils';\nimport { When } from './wrappers';\n\nconst TIMEOUT = 500;\nconst DELAY = 500;\n\nexport const set = When('I set {locator} to {value}', async function (selector: string, value: Scalar | Scalar[]) {\n const el = await fuzzyLocator(this.page, selector);\n await setFieldValue(el, value, { timeout: TIMEOUT });\n await sleep(DELAY);\n});\n\nexport const setRange = When(\n 'I set {locator} to range of {value} to {value}',\n async function (selector: string, from: Scalar, to: Scalar) {\n const el = await fuzzyLocator(this.page, selector);\n await setFieldValue(el, { from, to }, { timeout: TIMEOUT });\n await sleep(DELAY);\n },\n);\n\nexport const clear = When('I clear {locator}', async function (selector) {\n const el = await fuzzyLocator(this.page, selector);\n await setFieldValue(el, null, { timeout: TIMEOUT });\n await sleep(DELAY);\n});\n\nexport const check = When(\n 'I {check|uncheck} {locator}',\n async function (check: boolean, selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n await setFieldValue(el, check, { timeout: TIMEOUT });\n await sleep(DELAY);\n },\n 'For checkbox input or switch component',\n);\n\nexport const focus = When('I {focus|blur} {locator}', async function (focus: boolean, selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n\n if (focus) {\n await el.focus({ timeout: TIMEOUT });\n } else {\n await el.blur({ timeout: TIMEOUT });\n }\n});\n","import type { KeyCombo } from '@letsrunit/gherkin';\nimport { sleep } from '@letsrunit/utils';\nimport { When } from './wrappers';\n\nconst DELAY = 500;\n\nexport const press = When('I press {keys}', async function (combo: KeyCombo) {\n // Hold modifiers\n for (const m of combo.modifiers) await this.page.keyboard.down(m);\n\n // Press final key\n await this.page.keyboard.press(combo.key);\n\n // Release modifiers (reverse order)\n for (const m of combo.modifiers.toReversed()) await this.page.keyboard.up(m);\n\n await sleep(DELAY);\n});\n\nexport const type = When('I type {string}', async function (value: string) {\n await this.page.keyboard.type(value, { delay: 200 });\n await sleep(DELAY);\n});\n","import { receiveMail, toEml } from '@letsrunit/mailbox';\nimport { asFilename, textToHtml } from '@letsrunit/utils';\nimport { Given, Then } from './wrappers';\n\nconst MAX_RECEIVE_WAIT = 120_000; // 2 minutes\n\nexport const view = Given(\n `I'm viewing an email sent to {string} with subject {string}`,\n async function (address: string, subject: string) {\n const emails = await receiveMail(address, { full: true, after: this.startTime, subject, limit: 1 });\n if (emails.length === 0) {\n throw new Error(`Did not receive an email with subject \"${subject}\"`);\n }\n\n const email = emails[0];\n\n await this.page.goto('about:blank', { waitUntil: 'load' });\n await this.page.setContent(email.html ?? textToHtml(email.text!), { waitUntil: 'domcontentloaded' });\n },\n);\n\nexport const receive = Then(\n 'I received an email sent to {string} with subject {string}',\n async function (address: string, subject: string) {\n const emails = await receiveMail(address, {\n after: this.startTime,\n full: true,\n subject,\n wait: true,\n timeout: MAX_RECEIVE_WAIT,\n limit: 1,\n });\n\n if (emails.length === 0) {\n throw new Error(`Did not receive an email with subject \"${subject}\"`);\n }\n\n const email = emails[0];\n\n this.attach(toEml(email), {\n mediaType: 'message/rfc822',\n fileName: asFilename(email.subject, 'eml'),\n });\n },\n);\n","import type { KeyCombo } from '@letsrunit/gherkin';\nimport { fuzzyLocator, waitAfterInteraction } from '@letsrunit/playwright';\nimport type { Locator } from '@playwright/test';\nimport { When } from './wrappers';\n\nconst TIMEOUT = 2500;\n\ntype MouseAction = 'click' | 'double-click' | 'right-click' | 'hover';\n\nasync function press(el: Locator, action: MouseAction) {\n if (action === 'hover') {\n await el.hover({ timeout: TIMEOUT });\n } else {\n await el.click({\n button: action === 'right-click' ? 'right' : 'left',\n clickCount: action === 'double-click' ? 2 : 1,\n timeout: TIMEOUT,\n });\n }\n}\n\nexport const click = When(\n 'I {click|double-click|right-click|hover} {locator}',\n async function (action: MouseAction, selector: string) {\n const prevUrl = this.page.url();\n\n const el = await fuzzyLocator(this.page, selector);\n await press(el, action);\n\n await waitAfterInteraction(this.page, el, { prevUrl });\n },\n);\n\nexport const clickHold = When(\n 'I {click|double-click|right-click|hover} {locator} while holding {keys}',\n async function (action: MouseAction, selector: string, combo: KeyCombo) {\n const prevUrl = this.page.url();\n\n const el = await fuzzyLocator(this.page, selector);\n const keys = [...combo.modifiers, combo.key];\n\n for (const m of keys) await this.page.keyboard.down(m);\n await press(el, action);\n for (const m of keys.reverse()) await this.page.keyboard.up(m);\n\n await waitAfterInteraction(this.page, el, { prevUrl });\n },\n);\n\nexport const scroll = When('I scroll {locator} into view', async function (selector: string) {\n const el = await fuzzyLocator(this.page, selector);\n await el.scrollIntoViewIfNeeded({ timeout: TIMEOUT });\n});\n","import { suppressInterferences, waitForIdle } from '@letsrunit/playwright';\nimport { eventually, pathRegexp, splitUrl } from '@letsrunit/utils';\nimport { expect } from '@playwright/test';\nimport { World } from '../types';\nimport { getLang } from '../utils/get-lang';\nimport { Given, Then, When } from './wrappers';\n\nasync function openPage(world: World, path: string): Promise<void> {\n const { page } = world;\n\n const result = await page.goto(path);\n expect(result?.status()).toBeLessThan(400);\n\n await waitForIdle(page);\n\n world.lang ??= (await getLang(page)) || undefined;\n}\n\nexport const navHome = Given(\"I'm on the homepage\", async function () {\n await openPage(this, '/');\n});\n\nexport const navPath = Given(\"I'm on page {string}\", async function (path: string) {\n await openPage(this, path);\n});\n\nexport const popupClosed = Given('all popups are closed', async function (){\n await suppressInterferences(this.page, { lang: this.lang?.code });\n});\n\nexport const assertPath = Then('I should be on page {string}', async function (expectedPath: string) {\n await eventually(async () => {\n const { path: actualPath } = splitUrl(this.page.url());\n\n if (expectedPath.includes(':')) {\n const { regexp, names } = pathRegexp(expectedPath);\n\n expect(actualPath, `Expected path ${actualPath} to match pattern ${expectedPath}`).toMatch(regexp);\n\n const match = actualPath.match(regexp);\n this.pathParams = Object.fromEntries(names.map((name, i) => [name, decodeURIComponent(match![i + 1])]));\n } else {\n expect(actualPath).toEqual(expectedPath);\n delete this.pathParams;\n }\n });\n});\n\nexport const back = When('I go back to the previous page', async function () {\n await this.page.goBack();\n await waitForIdle(this.page);\n});\n","import type { Snapshot } from '@letsrunit/playwright';\nimport { Page } from '@playwright/test';\nimport ISO6391 from 'iso-639-1';\nimport metascraper from 'metascraper';\nimport metascraperLang from 'metascraper-lang';\n\nconst scrapeLang = metascraper([metascraperLang()]);\n\nexport async function getLang(\n page: Pick<Page, 'content' | 'url'> | Snapshot,\n): Promise<{ code: string; name: string} | null> {\n const html = 'html' in page ? page.html : await page.content();\n const url = typeof page.url === 'function' ? page.url() : page.url;\n\n const { lang = null } = await scrapeLang({ html, url });\n if (!lang) return null;\n\n const code = lang.substring(0, 2);\n const name = ISO6391.getName(code) || code;\n\n return { code, name };\n}\n","import type { StepDefinition } from '../types';\nimport * as assert from './assert';\nimport * as clipboard from './clipboard';\nimport * as form from './form';\nimport * as keyboard from './keyboard';\nimport * as mailbox from './mailbox';\nimport * as mouse from './mouse';\nimport * as navigation from './navigation';\n\n// The order matters for the LLM\nexport const stepsDefinitions: StepDefinition[] = [\n ...Object.values(assert),\n ...Object.values(navigation),\n ...Object.values(mouse),\n ...Object.values(form),\n ...Object.values(keyboard),\n ...Object.values(mailbox),\n ...Object.values(clipboard),\n];\n"]}
|
package/src/steps/wrappers.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { StepDefinition, StepHandler } from '../types';
|
|
2
|
-
|
|
3
|
-
export function Given(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {
|
|
4
|
-
return { type: 'Given', expression, fn, comment };
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function When(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {
|
|
8
|
-
return { type: 'When', expression, fn, comment };
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function Then(expression: string | RegExp, fn: StepHandler, comment?: string): StepDefinition {
|
|
12
|
-
return { type: 'Then', expression, fn, comment };
|
|
13
|
-
}
|