@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.
@@ -1,17 +1,14 @@
1
- import { locatorParameter, valueParameter, keysParameter, booleanParameter, enumParameter } from '@letsrunit/gherkin';
2
- import { fuzzyLocator, setFieldValue, waitAfterInteraction, suppressInterferences, waitForIdle } from '@letsrunit/playwright';
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 { asFilename, eventually, splitUrl, pathRegexp, sleep, textToHtml } from '@letsrunit/utils';
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
- var __defProp = Object.defineProperty;
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
- // src/steps/assert.ts
29
- var assert_exports = {};
30
- __export(assert_exports, {
31
- contain: () => contain,
32
- see: () => see
33
- });
34
- function expectOrNot(actual, toBe) {
35
- return toBe ? expect(actual) : expect(actual).not;
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
- return { type: "Given", expression, fn, comment };
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
- return { type: "When", expression, fn, comment };
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
- return { type: "Then", expression, fn, comment };
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
- var see = Then(
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
- var contain = Then(
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/clipboard.ts
68
- var clipboard_exports = {};
69
- __export(clipboard_exports, {
70
- copy: () => copy,
71
- paste: () => paste
72
- });
73
- var TIMEOUT = 500;
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 copyLink(el) {
81
- try {
82
- const tag = await el.evaluate((n) => n.tagName.toLowerCase());
83
- const href = tag === "a" ? await el.getAttribute("href") : null;
84
- if (href) {
85
- return href.startsWith("mailto:") ? href.replace(/^mailto:/i, "") : href;
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
- } catch {
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
- async function copyText(el) {
91
- return await el.textContent() ?? null;
92
- }
93
- var copy = When("I copy {locator} to the clipboard", async function(selector) {
94
- const el = await fuzzyLocator(this.page, selector);
95
- let value = await copyInput(el) ?? await copyLink(el) ?? await copyText(el);
96
- this.clipboard = { value };
97
- });
98
- var paste = When("I paste from the clipboard into {locator}", async function(selector) {
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
- const value = this.clipboard?.value || "";
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
- var set = When("I set {locator} to {value}", async function(selector, value) {
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
- var setRange = When(
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
- var clear = When("I clear {locator}", async function(selector) {
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
- var check = When(
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
- var focus = When("I {focus|blur} {locator}", async function(focus2, selector) {
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
- var press = When("I press {keys}", async function(combo) {
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
- var type = When("I type {string}", async function(value) {
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
- var view = Given(
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
- var receive = Then(
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
- // src/steps/mouse.ts
211
- var mouse_exports = {};
212
- __export(mouse_exports, {
213
- click: () => click,
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
- var click = When(
230
- "I {click|double-click|right-click|hover} {locator}",
231
- async function(action, selector) {
232
- const prevUrl = this.page.url();
233
- const el = await fuzzyLocator(this.page, selector);
234
- await press2(el, action);
235
- await waitAfterInteraction(this.page, el, { prevUrl });
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
- // src/steps/navigation.ts
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
- var navHome = Given("I'm on the homepage", async function() {
284
- await openPage(this, "/");
285
- });
286
- var navPath = Given("I'm on page {string}", async function(path) {
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
- var back = When("I go back to the previous page", async function() {
307
- await this.page.goBack();
308
- await waitForIdle(this.page);
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
- // src/steps/index.ts
312
- var stepsDefinitions = [
313
- ...Object.values(assert_exports),
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, stepsDefinitions } from './chunk-A7ZD72RB.js';
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 stepsDefinitions) {
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
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/define.ts"],"names":[],"mappings":";;;;;;AAOA,KAAA,MAAW,QAAQ,eAAA,EAAiB;AAClC,EAAA,mBAAA,CAAoB,IAAI,CAAA;AAC1B;AAEA,KAAA,MAAW,QAAQ,gBAAA,EAAkB;AACnC,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 { typeDefinitions } from './parameters';\nimport { stepsDefinitions } from './steps';\nimport { sanitizeStepDefinition } from '@letsrunit/gherkin';\n\nfor (const type of typeDefinitions) {\n defineParameterType(type);\n}\n\nfor (const step of stepsDefinitions) {\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"]}
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 stepsDefinitions: StepDefinition[];
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
- export { type StepDefinition, type StepHandler, type StepType, type World, stepsDefinitions, toFile, typeDefinitions };
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
@@ -1,4 +1,4 @@
1
- export { stepsDefinitions, typeDefinitions } from './chunk-A7ZD72RB.js';
1
+ export { Given, Then, When, createRegistry, registry, typeDefinitions } from './chunk-D6IA6AFW.js';
2
2
 
3
3
  // src/utils/file.ts
4
4
  function toFile(data, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letsrunit/bdd",
3
- "version": "0.3.10",
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.3.10",
56
- "@letsrunit/mailbox": "0.3.10",
57
- "@letsrunit/playwright": "0.3.10",
58
- "@letsrunit/utils": "0.3.10",
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 stepsDefinitions) {
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
@@ -1,4 +1,5 @@
1
1
  export * from './parameters';
2
2
  export * from './steps';
3
3
  export * from './types';
4
- export { toFile } from './utils/file'
4
+ export { toFile } from './utils/file';
5
+ export { Given, When, Then, registry, createRegistry } from './registry';
@@ -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
+ }
@@ -1,6 +1,6 @@
1
1
  import { fuzzyLocator } from '@letsrunit/playwright';
2
2
  import { expectOrNot } from '../utils/test-helpers';
3
- import { Then } from './wrappers';
3
+ import { Then } from '../registry';
4
4
 
5
5
  const WAIT_TIMEOUT = 5000;
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { fuzzyLocator } from '@letsrunit/playwright';
2
2
  import type { Locator } from '@playwright/test';
3
- import { When } from './wrappers';
3
+ import { When } from '../registry';
4
4
 
5
5
  const TIMEOUT = 500;
6
6
 
package/src/steps/form.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { fuzzyLocator, setFieldValue } from '@letsrunit/playwright';
2
2
  import { type Scalar, sleep } from '@letsrunit/utils';
3
- import { When } from './wrappers';
3
+ import { When } from '../registry';
4
4
 
5
5
  const TIMEOUT = 500;
6
6
  const DELAY = 500;
@@ -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
- export const stepsDefinitions: StepDefinition[] = [
12
- ...Object.values(assert),
13
- ...Object.values(navigation),
14
- ...Object.values(mouse),
15
- ...Object.values(form),
16
- ...Object.values(keyboard),
17
- ...Object.values(mailbox),
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';
@@ -1,6 +1,6 @@
1
1
  import type { KeyCombo } from '@letsrunit/gherkin';
2
2
  import { sleep } from '@letsrunit/utils';
3
- import { When } from './wrappers';
3
+ import { When } from '../registry';
4
4
 
5
5
  const DELAY = 500;
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { receiveMail, toEml } from '@letsrunit/mailbox';
2
2
  import { asFilename, textToHtml } from '@letsrunit/utils';
3
- import { Given, Then } from './wrappers';
3
+ import { Given, Then } from '../registry';
4
4
 
5
5
  const MAX_RECEIVE_WAIT = 120_000; // 2 minutes
6
6
 
@@ -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 './wrappers';
4
+ import { When } from '../registry';
5
5
 
6
6
  const TIMEOUT = 2500;
7
7
 
@@ -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 './wrappers';
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"]}
@@ -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
- }