@atomic-testing/playwright 0.88.0 → 0.89.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  import { ElementNotFoundError, TestEngine, byCssSelector, dateUtil, defaultWaitForOption, interactorUtil, locatorUtil, timingUtil } from "@atomic-testing/core";
2
- import { expect, test } from "@playwright/test";
3
2
  //#region src/PlaywrightInteractor.ts
4
3
  /**
5
4
  * Implementation of the {@link Interactor} interface using Playwright.
@@ -12,44 +11,70 @@ var PlaywrightInteractor = class PlaywrightInteractor {
12
11
  this.page = page;
13
12
  }
14
13
  /**
14
+ * Run a Playwright mutation and normalize a "locator matched nothing" failure
15
+ * into {@link ElementNotFoundError}, so a missing element throws the same error
16
+ * class here as it does in `DOMInteractor`, regardless of environment (the
17
+ * unified contract ratified in ADR-006).
18
+ *
19
+ * Playwright auto-waits for actionability and then throws its own
20
+ * `TimeoutError`. We translate that to `ElementNotFoundError` ONLY when the
21
+ * element genuinely does not exist (count 0) and otherwise rethrow the original
22
+ * error — preserving Playwright's auto-wait for an element that exists but is
23
+ * briefly not actionable (covered, disabled, animating). The trade-off is that
24
+ * a truly-missing element waits out the page's action timeout before throwing;
25
+ * bound it with `page.setDefaultTimeout` when fast failure matters.
26
+ *
27
+ * @param locator - Locator the mutation targets
28
+ * @param action - Method name used in the error message (e.g. `'click'`)
29
+ * @param run - The Playwright action to execute
30
+ * @throws {ElementNotFoundError} If the action fails and the element is absent
31
+ */
32
+ async runMutation(locator, action, run) {
33
+ try {
34
+ return await run();
35
+ } catch (e) {
36
+ if (await this.exists(locator) === false) throw new ElementNotFoundError(locator, action);
37
+ throw e;
38
+ }
39
+ }
40
+ /**
15
41
  * Select the given option values on a `<select>` element.
16
42
  *
17
43
  * @param locator - Locator to the `<select>` element.
18
44
  * @param values - Values to select.
45
+ * @throws {ElementNotFoundError} If the element is not found
19
46
  */
20
47
  async selectOptionValue(locator, values) {
21
48
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
22
- await this.page.locator(cssLocator).selectOption(values);
49
+ await this.runMutation(locator, "selectOptionValue", () => this.page.locator(cssLocator).selectOption(values));
23
50
  }
24
51
  /**
25
52
  * Set the selected files on a `<input type="file">` element.
26
53
  *
27
54
  * Playwright's native `setInputFiles` reads the given paths from disk and
28
55
  * populates the input's `FileList`, firing the change event — the only way to
29
- * fill a file input, whose value cannot be set programmatically. Following
30
- * this layer's convention, no `ElementNotFoundError` is fabricated: a missing
31
- * element surfaces through Playwright's own auto-wait timeout.
56
+ * fill a file input, whose value cannot be set programmatically.
32
57
  *
33
58
  * @param locator - Locator of the `<input type="file">` element
34
59
  * @param files - One or more filesystem paths to upload
60
+ * @throws {ElementNotFoundError} If the element is not found
35
61
  */
36
62
  async setInputFiles(locator, files) {
37
63
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
38
- await this.page.locator(cssLocator).setInputFiles(files);
64
+ await this.runMutation(locator, "setInputFiles", () => this.page.locator(cssLocator).setInputFiles(files));
39
65
  }
40
66
  /**
41
67
  * Scroll the located element into view, no-op if already visible.
42
68
  *
43
69
  * Delegates to Playwright's `scrollIntoViewIfNeeded`, which performs a real
44
- * layout-aware scroll in the browser. Per this layer's convention, no
45
- * `ElementNotFoundError` is fabricated: a missing element surfaces through
46
- * Playwright's own auto-wait timeout.
70
+ * layout-aware scroll in the browser.
47
71
  *
48
72
  * @param locator - Locator of the element to scroll into view
73
+ * @throws {ElementNotFoundError} If the element is not found
49
74
  */
50
75
  async scrollIntoView(locator) {
51
76
  const css = await locatorUtil.toCssSelector(locator, this);
52
- await this.page.locator(css).scrollIntoViewIfNeeded();
77
+ await this.runMutation(locator, "scrollIntoView", () => this.page.locator(css).scrollIntoViewIfNeeded());
53
78
  }
54
79
  /**
55
80
  * Scroll the located element by the given pixel delta.
@@ -60,35 +85,39 @@ var PlaywrightInteractor = class PlaywrightInteractor {
60
85
  * whereas evaluating `scrollBy` on the resolved element scrolls exactly that
61
86
  * element. This is a deliberate deviation from ADR 0001's per-engine table
62
87
  * (which lists `page.mouse.wheel`), taking the alternative the step-5 prompt
63
- * permits ("or evaluate el.scrollBy") for cross-browser determinism. As with
64
- * {@link scrollIntoView}, no `ElementNotFoundError` is fabricated; a missing
65
- * element surfaces through Playwright's own auto-wait timeout.
88
+ * permits ("or evaluate el.scrollBy") for cross-browser determinism.
66
89
  *
67
90
  * @param locator - Locator of the scrollable element
68
91
  * @param delta - Pixel offset to scroll by
92
+ * @throws {ElementNotFoundError} If the element is not found
69
93
  */
70
94
  async scrollBy(locator, delta) {
71
95
  const css = await locatorUtil.toCssSelector(locator, this);
72
- await this.page.locator(css).evaluate((el, d) => el.scrollBy(d.x, d.y), {
96
+ await this.runMutation(locator, "scrollBy", () => this.page.locator(css).evaluate((el, d) => el.scrollBy(d.x, d.y), {
73
97
  x: delta.x,
74
98
  y: delta.y
75
- });
99
+ }));
76
100
  }
77
101
  /**
78
102
  * Drag the source element and drop it onto the target element.
79
103
  *
80
104
  * Delegates to Playwright's native `Locator.dragTo`, which performs a real,
81
- * layout-aware drag gesture in the browser. Per this layer's convention, no
82
- * `ElementNotFoundError` is fabricated: a missing element surfaces through
83
- * Playwright's own auto-wait timeout.
105
+ * layout-aware drag gesture in the browser.
84
106
  *
85
107
  * @param source - Locator of the element to drag
86
108
  * @param target - Locator of the drop target
109
+ * @throws {ElementNotFoundError} If either the source or target is not found
87
110
  */
88
111
  async dragTo(source, target) {
89
112
  const srcCss = await locatorUtil.toCssSelector(source, this);
90
113
  const tgtCss = await locatorUtil.toCssSelector(target, this);
91
- await this.page.locator(srcCss).dragTo(this.page.locator(tgtCss));
114
+ try {
115
+ await this.page.locator(srcCss).dragTo(this.page.locator(tgtCss));
116
+ } catch (e) {
117
+ if (await this.exists(source) === false) throw new ElementNotFoundError(source, "dragTo");
118
+ if (await this.exists(target) === false) throw new ElementNotFoundError(target, "dragTo");
119
+ throw e;
120
+ }
92
121
  }
93
122
  /**
94
123
  * Drag the located element by the given pixel delta from its center.
@@ -98,9 +127,9 @@ var PlaywrightInteractor = class PlaywrightInteractor {
98
127
  * {@link mouseMove}/{@link mouseDown} — `mouseMove` resets the pointer with
99
128
  * `page.mouse.move(0, 0)` after hovering, which would corrupt the drag path
100
129
  * (see ADR 0001, option 5). The center comes from {@link getBoundingRect},
101
- * which throws `ElementNotFoundError` when the element has no box
102
- * (detached/invisible) rather than auto-waiting so this shares that
103
- * "element not found" contract instead of re-deriving the box + guard here.
130
+ * which throws `ElementNotFoundError` when the element has no box, so this
131
+ * shares that "element not found" contract instead of re-deriving the box +
132
+ * guard here.
104
133
  *
105
134
  * @param locator - Locator of the element to drag
106
135
  * @param delta - Pixel offset to drag by
@@ -163,71 +192,91 @@ var PlaywrightInteractor = class PlaywrightInteractor {
163
192
  }
164
193
  async enterText(locator, text, option) {
165
194
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
166
- if (!option?.append) await this.page.locator(cssLocator).clear();
167
- const type = await this.getAttribute(locator, "type") ?? "";
168
- if (dateUtil.isHtmlDateInputType(type)) {
169
- const result = dateUtil.validateHtmlDateInput(type, text);
170
- if (!result.valid) throw new Error(`Invalid date format for type: ${type}, expected format: ${result.format}, example: ${result.example}`);
171
- }
172
- await this.page.locator(cssLocator).fill(text);
195
+ await this.runMutation(locator, "enterText", async () => {
196
+ if (!option?.append) await this.page.locator(cssLocator).clear();
197
+ const type = await this.getAttribute(locator, "type") ?? "";
198
+ if (dateUtil.isHtmlDateInputType(type)) {
199
+ const result = dateUtil.validateHtmlDateInput(type, text);
200
+ if (!result.valid) throw new Error(`Invalid date format for type: ${type}, expected format: ${result.format}, example: ${result.example}`);
201
+ }
202
+ await this.page.locator(cssLocator).fill(text);
203
+ });
204
+ }
205
+ async setRangeValue(locator, value) {
206
+ const cssLocator = await locatorUtil.toCssSelector(locator, this);
207
+ await this.runMutation(locator, "setRangeValue", () => this.page.locator(cssLocator).evaluate((el, nextValue) => {
208
+ const input = el;
209
+ (Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set)?.call(input, nextValue);
210
+ input.dispatchEvent(new Event("input", { bubbles: true }));
211
+ input.dispatchEvent(new Event("change", { bubbles: true }));
212
+ }, String(value)));
173
213
  }
174
214
  async click(locator, option) {
175
215
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
176
- await this.page.locator(cssLocator).click({ position: option?.position });
216
+ await this.runMutation(locator, "click", () => this.page.locator(cssLocator).click({ position: option?.position }));
177
217
  }
178
218
  /**
179
219
  * Dispatch a right-click on the located element to open its context menu.
180
220
  *
181
221
  * Delegates to Playwright's native right-button click, which fires a real
182
- * `contextmenu` event in the browser. Per this layer's convention, no
183
- * `ElementNotFoundError` is fabricated: a missing element surfaces through
184
- * Playwright's own auto-wait timeout.
222
+ * `contextmenu` event in the browser.
185
223
  *
186
224
  * @param locator - Locator of the element to right-click
225
+ * @throws {ElementNotFoundError} If the element is not found
187
226
  */
188
227
  async contextMenu(locator) {
189
228
  const css = await locatorUtil.toCssSelector(locator, this);
190
- await this.page.locator(css).click({ button: "right" });
229
+ await this.runMutation(locator, "contextMenu", () => this.page.locator(css).click({ button: "right" }));
191
230
  }
192
231
  async hover(locator, option) {
193
232
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
194
- await this.page.locator(cssLocator).hover({ position: option?.position });
233
+ await this.runMutation(locator, "hover", () => this.page.locator(cssLocator).hover({ position: option?.position }));
195
234
  }
196
235
  async mouseMove(locator, option) {
197
- await this.hover(locator, { position: option?.position });
198
- await this.page.mouse.move(0, 0);
236
+ await this.runMutation(locator, "mouseMove", async () => {
237
+ await this.hover(locator, { position: option?.position });
238
+ await this.page.mouse.move(0, 0);
239
+ });
199
240
  }
200
241
  async mouseDown(locator, option) {
201
- await this.hover(locator, { position: option?.position });
202
- await this.page.mouse.down();
242
+ await this.runMutation(locator, "mouseDown", async () => {
243
+ await this.hover(locator, { position: option?.position });
244
+ await this.page.mouse.down();
245
+ });
203
246
  }
204
247
  async mouseUp(locator, option) {
205
- await this.hover(locator, { position: option?.position });
206
- await this.page.mouse.up();
248
+ await this.runMutation(locator, "mouseUp", async () => {
249
+ await this.hover(locator, { position: option?.position });
250
+ await this.page.mouse.up();
251
+ });
207
252
  }
208
253
  async mouseOver(locator, option) {
209
- return this.hover(locator, option);
254
+ await this.runMutation(locator, "mouseOver", () => this.hover(locator, option));
210
255
  }
211
256
  async mouseOut(locator, _option) {
212
257
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
213
- await this.page.locator(cssLocator).hover();
214
- await this.page.locator(cssLocator).dispatchEvent("mouseout");
258
+ await this.runMutation(locator, "mouseOut", async () => {
259
+ await this.page.locator(cssLocator).hover();
260
+ await this.page.locator(cssLocator).dispatchEvent("mouseout");
261
+ });
215
262
  }
216
263
  async mouseEnter(locator, _option) {
217
- return this.hover(locator);
264
+ await this.runMutation(locator, "mouseEnter", () => this.hover(locator));
218
265
  }
219
266
  async mouseLeave(locator, _option) {
220
267
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
221
- await this.page.locator(cssLocator).hover();
222
- await this.page.locator(cssLocator).dispatchEvent("mouseout");
268
+ await this.runMutation(locator, "mouseLeave", async () => {
269
+ await this.page.locator(cssLocator).hover();
270
+ await this.page.locator(cssLocator).dispatchEvent("mouseout");
271
+ });
223
272
  }
224
273
  async focus(locator, _option) {
225
274
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
226
- return this.page.focus(cssLocator);
275
+ await this.runMutation(locator, "focus", () => this.page.focus(cssLocator));
227
276
  }
228
277
  async blur(locator, _option) {
229
278
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
230
- await this.page.locator(cssLocator).blur();
279
+ await this.runMutation(locator, "blur", () => this.page.locator(cssLocator).blur());
231
280
  }
232
281
  async pressKey(locator, key, option) {
233
282
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
@@ -237,11 +286,11 @@ var PlaywrightInteractor = class PlaywrightInteractor {
237
286
  if (option?.shift) modifiers.push("Shift");
238
287
  if (option?.meta) modifiers.push("Meta");
239
288
  const chord = modifiers.length > 0 ? `${modifiers.join("+")}+${key}` : key;
240
- await this.page.locator(cssLocator).press(chord);
289
+ await this.runMutation(locator, "pressKey", () => this.page.locator(cssLocator).press(chord));
241
290
  }
242
291
  async activate(locator) {
243
292
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
244
- await this.page.locator(cssLocator).dispatchEvent("click");
293
+ await this.runMutation(locator, "activate", () => this.page.locator(cssLocator).dispatchEvent("click"));
245
294
  }
246
295
  wait(ms) {
247
296
  return timingUtil.wait(ms);
@@ -274,9 +323,8 @@ var PlaywrightInteractor = class PlaywrightInteractor {
274
323
  * Get the located element's bounding rectangle.
275
324
  *
276
325
  * `boundingBox()` returns `null` for a detached/invisible element rather than
277
- * auto-waiting, so this is one of the few Playwright methods that throws
278
- * `ElementNotFoundError` — matching the house "element not found" contract
279
- * (ADR 0001).
326
+ * auto-waiting, so this throws `ElementNotFoundError` directly (no auto-wait)
327
+ * — matching the unified "element not found" contract (ADR-006).
280
328
  *
281
329
  * @param locator - Locator of the element to measure
282
330
  * @returns The element's bounding rectangle in CSS pixels
@@ -353,48 +401,6 @@ function createTestEngine(page, partDefinitions) {
353
401
  return new TestEngine([], new PlaywrightInteractor(page), { parts: partDefinitions });
354
402
  }
355
403
  //#endregion
356
- //#region src/testRunnerAdapter.ts
357
- async function goto(url, fixture) {
358
- await fixture.page.goto(url);
359
- }
360
- /**
361
- * Create a {@link TestEngine} bound to the Playwright page in the given fixture.
362
- *
363
- * @param scenePart - Scene definition to drive.
364
- * @param fixture - Fixture providing the Playwright page.
365
- */
366
- function playwrightGetTestEngine(scenePart, fixture) {
367
- const page = fixture.page;
368
- return createTestEngine(page, scenePart);
369
- }
370
- /**
371
- * Playwright adapter for the TestFrameworkMapper interface.
372
- */
373
- const playWrightTestFrameworkMapper = {
374
- assertEqual: (a, b) => expect(a).toEqual(b),
375
- assertNotEqual: (a, b) => expect(a).not.toEqual(b),
376
- assertTrue: (value) => expect(value).toBe(true),
377
- assertFalse: (value) => expect(value).toBe(false),
378
- assertApproxEqual: (actual, expected, tolerance) => expect(Math.abs(actual - expected)).toBeLessThanOrEqual(tolerance),
379
- describe: test.describe,
380
- beforeEach: test.beforeEach,
381
- afterEach: test.afterEach,
382
- beforeAll: test.beforeAll,
383
- afterAll: test.afterAll,
384
- test,
385
- it: test,
386
- hasLayout: true
387
- };
388
- /**
389
- * Get a typed interface for running end-to-end tests with Playwright.
390
- */
391
- function getTestRunnerInterface() {
392
- return {
393
- getTestEngine: playwrightGetTestEngine,
394
- goto
395
- };
396
- }
397
- //#endregion
398
- export { PlaywrightInteractor, createTestEngine, getTestRunnerInterface, goto, playWrightTestFrameworkMapper, playwrightGetTestEngine };
404
+ export { PlaywrightInteractor, createTestEngine };
399
405
 
400
406
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/PlaywrightInteractor.ts","../src/createTestEngine.ts","../src/testRunnerAdapter.ts"],"sourcesContent":["import {\n BlurOption,\n BoundingRect,\n byCssSelector,\n ClickOption,\n CssProperty,\n dateUtil,\n defaultWaitForOption,\n ElementNotFoundError,\n EnterTextOption,\n FocusOption,\n HoverOption,\n Interactor,\n interactorUtil,\n locatorUtil,\n MouseEnterOption,\n MouseLeaveOption,\n MouseOutOption,\n MouseDownOption,\n MouseMoveOption,\n MouseUpOption,\n Optional,\n PartLocator,\n Point,\n PressKeyOption,\n timingUtil,\n WaitForOption,\n WaitUntilOption,\n} from '@atomic-testing/core';\nimport { Page } from '@playwright/test';\n\n/**\n * Implementation of the {@link Interactor} interface using Playwright.\n */\nexport class PlaywrightInteractor implements Interactor {\n /**\n * @param page - Playwright page instance used to drive the browser.\n */\n constructor(public readonly page: Page) {}\n\n /**\n * Select the given option values on a `<select>` element.\n *\n * @param locator - Locator to the `<select>` element.\n * @param values - Values to select.\n */\n async selectOptionValue(locator: PartLocator, values: string[]): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.page.locator(cssLocator).selectOption(values);\n }\n\n /**\n * Set the selected files on a `<input type=\"file\">` element.\n *\n * Playwright's native `setInputFiles` reads the given paths from disk and\n * populates the input's `FileList`, firing the change event — the only way to\n * fill a file input, whose value cannot be set programmatically. Following\n * this layer's convention, no `ElementNotFoundError` is fabricated: a missing\n * element surfaces through Playwright's own auto-wait timeout.\n *\n * @param locator - Locator of the `<input type=\"file\">` element\n * @param files - One or more filesystem paths to upload\n */\n async setInputFiles(locator: PartLocator, files: string | string[]): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.page.locator(cssLocator).setInputFiles(files);\n }\n\n /**\n * Scroll the located element into view, no-op if already visible.\n *\n * Delegates to Playwright's `scrollIntoViewIfNeeded`, which performs a real\n * layout-aware scroll in the browser. Per this layer's convention, no\n * `ElementNotFoundError` is fabricated: a missing element surfaces through\n * Playwright's own auto-wait timeout.\n *\n * @param locator - Locator of the element to scroll into view\n */\n async scrollIntoView(locator: PartLocator): Promise<void> {\n const css = await locatorUtil.toCssSelector(locator, this);\n await this.page.locator(css).scrollIntoViewIfNeeded();\n }\n\n /**\n * Scroll the located element by the given pixel delta.\n *\n * The scroll is performed by evaluating `el.scrollBy(dx, dy)` on the element\n * itself rather than `page.mouse.wheel`. A wheel event scrolls whatever sits\n * under the pointer and is non-deterministic across chromium/firefox/webkit,\n * whereas evaluating `scrollBy` on the resolved element scrolls exactly that\n * element. This is a deliberate deviation from ADR 0001's per-engine table\n * (which lists `page.mouse.wheel`), taking the alternative the step-5 prompt\n * permits (\"or evaluate el.scrollBy\") for cross-browser determinism. As with\n * {@link scrollIntoView}, no `ElementNotFoundError` is fabricated; a missing\n * element surfaces through Playwright's own auto-wait timeout.\n *\n * @param locator - Locator of the scrollable element\n * @param delta - Pixel offset to scroll by\n */\n async scrollBy(locator: PartLocator, delta: Point): Promise<void> {\n const css = await locatorUtil.toCssSelector(locator, this);\n await this.page.locator(css).evaluate((el, d) => el.scrollBy(d.x, d.y), { x: delta.x, y: delta.y });\n }\n\n /**\n * Drag the source element and drop it onto the target element.\n *\n * Delegates to Playwright's native `Locator.dragTo`, which performs a real,\n * layout-aware drag gesture in the browser. Per this layer's convention, no\n * `ElementNotFoundError` is fabricated: a missing element surfaces through\n * Playwright's own auto-wait timeout.\n *\n * @param source - Locator of the element to drag\n * @param target - Locator of the drop target\n */\n async dragTo(source: PartLocator, target: PartLocator): Promise<void> {\n const srcCss = await locatorUtil.toCssSelector(source, this);\n const tgtCss = await locatorUtil.toCssSelector(target, this);\n await this.page.locator(srcCss).dragTo(this.page.locator(tgtCss));\n }\n\n /**\n * Drag the located element by the given pixel delta from its center.\n *\n * The gesture is a single uninterrupted `move → down → move → up` sequence\n * computed from the element's center. It deliberately does NOT reuse\n * {@link mouseMove}/{@link mouseDown} — `mouseMove` resets the pointer with\n * `page.mouse.move(0, 0)` after hovering, which would corrupt the drag path\n * (see ADR 0001, option 5). The center comes from {@link getBoundingRect},\n * which throws `ElementNotFoundError` when the element has no box\n * (detached/invisible) rather than auto-waiting — so this shares that\n * \"element not found\" contract instead of re-deriving the box + guard here.\n *\n * @param locator - Locator of the element to drag\n * @param delta - Pixel offset to drag by\n * @throws {ElementNotFoundError} If the element has no bounding box\n */\n async drag(locator: PartLocator, delta: Point): Promise<void> {\n const rect = await this.getBoundingRect(locator);\n const cx = rect.x + rect.width / 2;\n const cy = rect.y + rect.height / 2;\n await this.page.mouse.move(cx, cy);\n await this.page.mouse.down();\n await this.page.mouse.move(cx + delta.x, cy + delta.y, { steps: 8 });\n await this.page.mouse.up();\n }\n\n /**\n * Get the value of an `<input>` element.\n *\n * @param locator - Locator pointing to the input element.\n * @returns The current value of the input or `undefined` if not present.\n */\n async getInputValue(locator: PartLocator): Promise<Optional<string>> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n return this.page.locator(cssLocator).inputValue();\n }\n\n /**\n * Retrieve the values of selected options within a `<select>` element.\n *\n * @param locator - Locator to the `<select>` element.\n * @returns Array of selected option values or `undefined` when no option is selected.\n */\n async getSelectValues(locator: PartLocator): Promise<Optional<readonly string[]>> {\n const optionLocator: PartLocator = byCssSelector('option:checked');\n const selectedOptionLocator = locatorUtil.append(locator, optionLocator);\n const cssLocator = await locatorUtil.toCssSelector(selectedOptionLocator, this);\n const allOptions = await this.page.locator(cssLocator).all();\n const values: string[] = [];\n for (const option of allOptions) {\n const value = await option.getAttribute('value');\n if (value != null) {\n values.push(value);\n }\n }\n return values;\n }\n\n async getSelectLabels(locator: PartLocator): Promise<Optional<readonly string[]>> {\n const optionLocator: PartLocator = byCssSelector('option:checked');\n const selectedOptionLocator = locatorUtil.append(locator, optionLocator);\n const cssLocator = await locatorUtil.toCssSelector(selectedOptionLocator, this);\n const allOptions = await this.page.locator(cssLocator).all();\n const labels: string[] = [];\n for (const option of allOptions) {\n const label = await option.textContent();\n if (label != null) {\n labels.push(label);\n }\n }\n return labels;\n }\n\n async getStyleValue(locator: PartLocator, propertyName: CssProperty): Promise<Optional<string>> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const elLocator = this.page.locator(cssLocator);\n const value = await elLocator.evaluate((element, prop) => {\n return window.getComputedStyle(element).getPropertyValue(prop as string);\n }, propertyName);\n return value;\n }\n\n async enterText(locator: PartLocator, text: string, option?: Optional<Partial<EnterTextOption>>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n if (!option?.append) {\n await this.page.locator(cssLocator).clear();\n }\n\n // If it is a date, time or datetime-local input, validate the date format\n const type = (await this.getAttribute(locator, 'type')) ?? '';\n if (dateUtil.isHtmlDateInputType(type)) {\n const result = dateUtil.validateHtmlDateInput(type, text);\n if (!result.valid) {\n throw new Error(\n `Invalid date format for type: ${type}, expected format: ${result.format}, example: ${result.example}`\n );\n }\n }\n await this.page.locator(cssLocator).fill(text);\n }\n\n async click(locator: PartLocator, option?: Partial<ClickOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.page.locator(cssLocator).click({ position: option?.position });\n }\n\n /**\n * Dispatch a right-click on the located element to open its context menu.\n *\n * Delegates to Playwright's native right-button click, which fires a real\n * `contextmenu` event in the browser. Per this layer's convention, no\n * `ElementNotFoundError` is fabricated: a missing element surfaces through\n * Playwright's own auto-wait timeout.\n *\n * @param locator - Locator of the element to right-click\n */\n async contextMenu(locator: PartLocator): Promise<void> {\n const css = await locatorUtil.toCssSelector(locator, this);\n await this.page.locator(css).click({ button: 'right' });\n }\n\n async hover(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.page.locator(cssLocator).hover({ position: option?.position });\n }\n\n async mouseMove(locator: PartLocator, option?: Partial<MouseMoveOption>): Promise<void> {\n await this.hover(locator, {\n position: option?.position,\n });\n await this.page.mouse.move(0, 0);\n }\n\n async mouseDown(locator: PartLocator, option?: Partial<MouseDownOption>): Promise<void> {\n await this.hover(locator, {\n position: option?.position,\n });\n await this.page.mouse.down();\n }\n\n async mouseUp(locator: PartLocator, option?: Partial<MouseUpOption>): Promise<void> {\n await this.hover(locator, {\n position: option?.position,\n });\n await this.page.mouse.up();\n }\n\n async mouseOver(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {\n return this.hover(locator, option);\n }\n\n async mouseOut(locator: PartLocator, _option?: Partial<MouseOutOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n // First hover over the element to trigger mouseenter/mouseover\n await this.page.locator(cssLocator).hover();\n // Then dispatch mouseout event directly for cross-browser reliability\n await this.page.locator(cssLocator).dispatchEvent('mouseout');\n }\n\n async mouseEnter(locator: PartLocator, _option?: Partial<MouseEnterOption>): Promise<void> {\n return this.hover(locator);\n }\n\n async mouseLeave(locator: PartLocator, _option?: Partial<MouseLeaveOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n // First hover over the element to trigger mouseenter/mouseover\n await this.page.locator(cssLocator).hover();\n // Dispatch mouseout which triggers both mouseout and mouseleave handlers in React\n await this.page.locator(cssLocator).dispatchEvent('mouseout');\n }\n\n async focus(locator: PartLocator, _option?: Partial<FocusOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n return this.page.focus(cssLocator);\n }\n\n async blur(locator: PartLocator, _option?: Partial<BlurOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.page.locator(cssLocator).blur();\n }\n\n async pressKey(locator: PartLocator, key: string, option?: Partial<PressKeyOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n // Compose Playwright's chord syntax — modifiers joined to the key by `+`, in\n // Playwright's accepted Control+Alt+Shift+Meta order — so the browser holds\n // those modifiers across the keypress and the event carries ctrlKey/etc.\n const modifiers: string[] = [];\n if (option?.ctrl) {\n modifiers.push('Control');\n }\n if (option?.alt) {\n modifiers.push('Alt');\n }\n if (option?.shift) {\n modifiers.push('Shift');\n }\n if (option?.meta) {\n modifiers.push('Meta');\n }\n const chord = modifiers.length > 0 ? `${modifiers.join('+')}+${key}` : key;\n // locator.press auto-focuses the element, then dispatches a real, trusted\n // KeyboardEvent — the browser equivalent of the DOM focus-first keyDown/keyUp.\n // Caveat: for Shift + a printable key the browser case-folds `event.key`\n // (`Shift+a` → `'A'`) whereas the jsdom path keeps `'a'` — only the modifier\n // flags are delivered identically across engines (see #924).\n await this.page.locator(cssLocator).press(chord);\n }\n\n async activate(locator: PartLocator): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n // Geometry-free activation mirrors the mouseout dispatch precedent above: it\n // bypasses hit-testing to actuate a covered or zero-size input that\n // locator.click() (a real geometry hit-test) cannot reach.\n await this.page.locator(cssLocator).dispatchEvent('click');\n }\n\n //#region wait conditions\n wait(ms: number): Promise<void> {\n return timingUtil.wait(ms);\n }\n\n async waitUntilComponentState(\n locator: PartLocator,\n option: Partial<Readonly<WaitForOption>> = defaultWaitForOption\n ): Promise<void> {\n return interactorUtil.interactorWaitUtil(locator, this, option);\n }\n\n waitUntil<T>(option: WaitUntilOption<T>): Promise<T> {\n return timingUtil.waitUntil(option);\n }\n //#endregion\n\n async getAttribute(locator: PartLocator, name: string, isMultiple: true): Promise<readonly string[]>;\n async getAttribute(locator: PartLocator, name: string, isMultiple: false): Promise<Optional<string>>;\n async getAttribute(locator: PartLocator, name: string): Promise<Optional<string>>;\n async getAttribute(\n locator: PartLocator,\n name: string,\n isMultiple?: boolean\n ): Promise<Optional<string> | readonly string[]> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const elLocator = this.page.locator(cssLocator);\n if (isMultiple) {\n const locators = await elLocator.all();\n const values: string[] = [];\n for (const locator of locators) {\n const value = await locator.getAttribute(name);\n if (value != null) {\n values.push(value);\n }\n }\n return values;\n }\n const value = await elLocator.getAttribute(name);\n return value ?? undefined;\n }\n\n async getText(locator: PartLocator): Promise<Optional<string>> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const text = await this.page.locator(cssLocator).textContent();\n return text ?? undefined;\n }\n\n /**\n * Get the located element's bounding rectangle.\n *\n * `boundingBox()` returns `null` for a detached/invisible element rather than\n * auto-waiting, so this is one of the few Playwright methods that throws\n * `ElementNotFoundError` — matching the house \"element not found\" contract\n * (ADR 0001).\n *\n * @param locator - Locator of the element to measure\n * @returns The element's bounding rectangle in CSS pixels\n * @throws {ElementNotFoundError} If the element has no bounding box\n */\n async getBoundingRect(locator: PartLocator): Promise<BoundingRect> {\n const css = await locatorUtil.toCssSelector(locator, this);\n const box = await this.page.locator(css).boundingBox();\n if (box == null) {\n throw new ElementNotFoundError(locator, 'getBoundingRect');\n }\n return { x: box.x, y: box.y, width: box.width, height: box.height };\n }\n\n async exists(locator: PartLocator): Promise<boolean> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const count = await this.page.locator(cssLocator).count();\n return count > 0;\n }\n\n async isChecked(locator: PartLocator): Promise<boolean> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const checked = await this.page.locator(cssLocator).isChecked();\n return checked;\n }\n\n async isDisabled(locator: PartLocator): Promise<boolean> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const isDisabled = await this.page.locator(cssLocator).isDisabled();\n return isDisabled;\n }\n\n async isReadonly(locator: PartLocator): Promise<boolean> {\n const readonly = await this.getAttribute(locator, 'readonly');\n return readonly != null;\n }\n\n async isVisible(locator: PartLocator): Promise<boolean> {\n const exists = await this.exists(locator);\n if (!exists) {\n return false;\n }\n\n async function checkCssVisibility(\n prop: CssProperty,\n invisibleValue: string,\n interactor: PlaywrightInteractor\n ): Promise<boolean> {\n try {\n const value = await interactor.getStyleValue(locator, prop);\n return value !== invisibleValue;\n } catch (e) {\n // Element may disappear or detached while being checked because of animation\n // when it happens, an error is thrown. In this case, if indeed the element\n // is not visible, we return false. Otherwise, we re-throw the error.\n if ((await interactor.exists(locator)) === false) {\n return false;\n }\n throw e;\n }\n }\n\n if ((await checkCssVisibility('opacity', '0', this)) === false) {\n return false;\n }\n\n if ((await checkCssVisibility('visibility', 'hidden', this)) === false) {\n return false;\n }\n\n if ((await checkCssVisibility('display', 'none', this)) === false) {\n return false;\n }\n\n return true;\n }\n\n async hasCssClass(locator: PartLocator, className: string): Promise<boolean> {\n const classNames = await this.getAttribute(locator, 'class');\n if (classNames == null) {\n return false;\n }\n\n const names = classNames.split(/\\s+/);\n return names.includes(className);\n }\n\n async hasAttribute(locator: PartLocator, name: string): Promise<boolean> {\n const attrValue = await this.getAttribute(locator, name);\n return attrValue != null;\n }\n\n //#region\n async innerHTML(locator: PartLocator): Promise<string> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n return this.page.locator(cssLocator).innerHTML();\n }\n //#endregion\n\n clone(): Interactor {\n return new PlaywrightInteractor(this.page);\n }\n}\n","import { ScenePart, TestEngine } from '@atomic-testing/core';\nimport { Page } from '@playwright/test';\n\nimport { PlaywrightInteractor } from './PlaywrightInteractor';\n\n/**\n * Create a {@link TestEngine} instance backed by Playwright.\n *\n * @param page - Playwright page used for interaction.\n * @param partDefinitions - Scene part definitions describing the scene\n * structure for the engine.\n * @returns A configured {@link TestEngine} ready for use.\n */\nexport function createTestEngine<T extends ScenePart>(page: Page, partDefinitions: T): TestEngine<T> {\n const engine = new TestEngine([], new PlaywrightInteractor(page), {\n parts: partDefinitions,\n });\n\n return engine;\n}\n","import { ScenePart, TestEngine } from '@atomic-testing/core';\nimport {\n E2eTestInterface,\n E2eTestRunEnvironmentFixture,\n TestFrameworkMapper,\n} from '@atomic-testing/internal-test-runner';\nimport { expect, Page, test } from '@playwright/test';\n\nimport { createTestEngine } from './createTestEngine';\n\n/**\n * Navigate the current Playwright page to the provided URL.\n *\n * @param url - Destination URL to load.\n * @param fixture - Optional test fixture supplying the Playwright page.\n */\nexport async function goto(url: string): Promise<void>;\nexport async function goto(url: string, fixture: E2eTestRunEnvironmentFixture): Promise<void>;\nexport async function goto(url: string, fixture?: E2eTestRunEnvironmentFixture): Promise<void> {\n const page = fixture!.page as Page;\n await page.goto(url);\n}\n\n/**\n * Create a {@link TestEngine} bound to the Playwright page in the given fixture.\n *\n * @param scenePart - Scene definition to drive.\n * @param fixture - Fixture providing the Playwright page.\n */\nexport function playwrightGetTestEngine<T extends ScenePart>(\n scenePart: T,\n fixture: E2eTestRunEnvironmentFixture\n): TestEngine<T> {\n const page = fixture.page as Page;\n return createTestEngine(page, scenePart);\n}\n\n/**\n * Playwright adapter for the TestFrameworkMapper interface.\n */\nexport const playWrightTestFrameworkMapper: TestFrameworkMapper = {\n /*\n * INTENTIONAL @ts-expect-error comments: Playwright's test functions have different type\n * signatures than the normalized TestFrameworkMapper interface. Playwright uses fixture-based\n * callbacks with destructuring ({ page, browser }) while our interface uses a union type for\n * Jest compatibility (done callback or fixture object). The functions are compatible at runtime\n * but TypeScript cannot verify this due to these fundamental signature differences.\n */\n\n assertEqual: (a, b) => expect(a).toEqual(b),\n assertNotEqual: (a, b) => expect(a).not.toEqual(b),\n assertTrue: value => expect(value).toBe(true),\n assertFalse: value => expect(value).toBe(false),\n assertApproxEqual: (actual, expected, tolerance) =>\n expect(Math.abs(actual - expected)).toBeLessThanOrEqual(tolerance),\n // @ts-expect-error - Playwright describe signature differs from TestFrameworkMapper.Describe\n describe: test.describe,\n\n beforeEach: test.beforeEach,\n afterEach: test.afterEach,\n beforeAll: test.beforeAll,\n afterAll: test.afterAll,\n\n // @ts-expect-error - Playwright test signature differs from TestFrameworkMapper.Test\n test: test,\n\n // @ts-expect-error - Playwright test signature differs from TestFrameworkMapper.Test\n it: test,\n\n hasLayout: true,\n};\n\n/**\n * Get a typed interface for running end-to-end tests with Playwright.\n */\nexport function getTestRunnerInterface<T extends ScenePart>(): E2eTestInterface<T> {\n return {\n getTestEngine: playwrightGetTestEngine,\n goto,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/PlaywrightInteractor.ts","../src/createTestEngine.ts"],"sourcesContent":["import {\n BlurOption,\n BoundingRect,\n byCssSelector,\n ClickOption,\n CssProperty,\n dateUtil,\n defaultWaitForOption,\n ElementNotFoundError,\n EnterTextOption,\n FocusOption,\n HoverOption,\n Interactor,\n interactorUtil,\n locatorUtil,\n MouseEnterOption,\n MouseLeaveOption,\n MouseOutOption,\n MouseDownOption,\n MouseMoveOption,\n MouseUpOption,\n Optional,\n PartLocator,\n Point,\n PressKeyOption,\n timingUtil,\n WaitForOption,\n WaitUntilOption,\n} from '@atomic-testing/core';\nimport { Page } from '@playwright/test';\n\n/**\n * Implementation of the {@link Interactor} interface using Playwright.\n */\nexport class PlaywrightInteractor implements Interactor {\n /**\n * @param page - Playwright page instance used to drive the browser.\n */\n constructor(public readonly page: Page) {}\n\n /**\n * Run a Playwright mutation and normalize a \"locator matched nothing\" failure\n * into {@link ElementNotFoundError}, so a missing element throws the same error\n * class here as it does in `DOMInteractor`, regardless of environment (the\n * unified contract ratified in ADR-006).\n *\n * Playwright auto-waits for actionability and then throws its own\n * `TimeoutError`. We translate that to `ElementNotFoundError` ONLY when the\n * element genuinely does not exist (count 0) and otherwise rethrow the original\n * error — preserving Playwright's auto-wait for an element that exists but is\n * briefly not actionable (covered, disabled, animating). The trade-off is that\n * a truly-missing element waits out the page's action timeout before throwing;\n * bound it with `page.setDefaultTimeout` when fast failure matters.\n *\n * @param locator - Locator the mutation targets\n * @param action - Method name used in the error message (e.g. `'click'`)\n * @param run - The Playwright action to execute\n * @throws {ElementNotFoundError} If the action fails and the element is absent\n */\n private async runMutation<T>(locator: PartLocator, action: string, run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (e) {\n if ((await this.exists(locator)) === false) {\n throw new ElementNotFoundError(locator, action);\n }\n throw e;\n }\n }\n\n /**\n * Select the given option values on a `<select>` element.\n *\n * @param locator - Locator to the `<select>` element.\n * @param values - Values to select.\n * @throws {ElementNotFoundError} If the element is not found\n */\n async selectOptionValue(locator: PartLocator, values: string[]): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'selectOptionValue', () => this.page.locator(cssLocator).selectOption(values));\n }\n\n /**\n * Set the selected files on a `<input type=\"file\">` element.\n *\n * Playwright's native `setInputFiles` reads the given paths from disk and\n * populates the input's `FileList`, firing the change event — the only way to\n * fill a file input, whose value cannot be set programmatically.\n *\n * @param locator - Locator of the `<input type=\"file\">` element\n * @param files - One or more filesystem paths to upload\n * @throws {ElementNotFoundError} If the element is not found\n */\n async setInputFiles(locator: PartLocator, files: string | string[]): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'setInputFiles', () => this.page.locator(cssLocator).setInputFiles(files));\n }\n\n /**\n * Scroll the located element into view, no-op if already visible.\n *\n * Delegates to Playwright's `scrollIntoViewIfNeeded`, which performs a real\n * layout-aware scroll in the browser.\n *\n * @param locator - Locator of the element to scroll into view\n * @throws {ElementNotFoundError} If the element is not found\n */\n async scrollIntoView(locator: PartLocator): Promise<void> {\n const css = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'scrollIntoView', () => this.page.locator(css).scrollIntoViewIfNeeded());\n }\n\n /**\n * Scroll the located element by the given pixel delta.\n *\n * The scroll is performed by evaluating `el.scrollBy(dx, dy)` on the element\n * itself rather than `page.mouse.wheel`. A wheel event scrolls whatever sits\n * under the pointer and is non-deterministic across chromium/firefox/webkit,\n * whereas evaluating `scrollBy` on the resolved element scrolls exactly that\n * element. This is a deliberate deviation from ADR 0001's per-engine table\n * (which lists `page.mouse.wheel`), taking the alternative the step-5 prompt\n * permits (\"or evaluate el.scrollBy\") for cross-browser determinism.\n *\n * @param locator - Locator of the scrollable element\n * @param delta - Pixel offset to scroll by\n * @throws {ElementNotFoundError} If the element is not found\n */\n async scrollBy(locator: PartLocator, delta: Point): Promise<void> {\n const css = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'scrollBy', () =>\n this.page.locator(css).evaluate((el, d) => el.scrollBy(d.x, d.y), { x: delta.x, y: delta.y })\n );\n }\n\n /**\n * Drag the source element and drop it onto the target element.\n *\n * Delegates to Playwright's native `Locator.dragTo`, which performs a real,\n * layout-aware drag gesture in the browser.\n *\n * @param source - Locator of the element to drag\n * @param target - Locator of the drop target\n * @throws {ElementNotFoundError} If either the source or target is not found\n */\n async dragTo(source: PartLocator, target: PartLocator): Promise<void> {\n const srcCss = await locatorUtil.toCssSelector(source, this);\n const tgtCss = await locatorUtil.toCssSelector(target, this);\n try {\n await this.page.locator(srcCss).dragTo(this.page.locator(tgtCss));\n } catch (e) {\n if ((await this.exists(source)) === false) {\n throw new ElementNotFoundError(source, 'dragTo');\n }\n if ((await this.exists(target)) === false) {\n throw new ElementNotFoundError(target, 'dragTo');\n }\n throw e;\n }\n }\n\n /**\n * Drag the located element by the given pixel delta from its center.\n *\n * The gesture is a single uninterrupted `move → down → move → up` sequence\n * computed from the element's center. It deliberately does NOT reuse\n * {@link mouseMove}/{@link mouseDown} — `mouseMove` resets the pointer with\n * `page.mouse.move(0, 0)` after hovering, which would corrupt the drag path\n * (see ADR 0001, option 5). The center comes from {@link getBoundingRect},\n * which throws `ElementNotFoundError` when the element has no box, so this\n * shares that \"element not found\" contract instead of re-deriving the box +\n * guard here.\n *\n * @param locator - Locator of the element to drag\n * @param delta - Pixel offset to drag by\n * @throws {ElementNotFoundError} If the element has no bounding box\n */\n async drag(locator: PartLocator, delta: Point): Promise<void> {\n const rect = await this.getBoundingRect(locator);\n const cx = rect.x + rect.width / 2;\n const cy = rect.y + rect.height / 2;\n await this.page.mouse.move(cx, cy);\n await this.page.mouse.down();\n await this.page.mouse.move(cx + delta.x, cy + delta.y, { steps: 8 });\n await this.page.mouse.up();\n }\n\n /**\n * Get the value of an `<input>` element.\n *\n * @param locator - Locator pointing to the input element.\n * @returns The current value of the input or `undefined` if not present.\n */\n async getInputValue(locator: PartLocator): Promise<Optional<string>> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n return this.page.locator(cssLocator).inputValue();\n }\n\n /**\n * Retrieve the values of selected options within a `<select>` element.\n *\n * @param locator - Locator to the `<select>` element.\n * @returns Array of selected option values or `undefined` when no option is selected.\n */\n async getSelectValues(locator: PartLocator): Promise<Optional<readonly string[]>> {\n const optionLocator: PartLocator = byCssSelector('option:checked');\n const selectedOptionLocator = locatorUtil.append(locator, optionLocator);\n const cssLocator = await locatorUtil.toCssSelector(selectedOptionLocator, this);\n const allOptions = await this.page.locator(cssLocator).all();\n const values: string[] = [];\n for (const option of allOptions) {\n const value = await option.getAttribute('value');\n if (value != null) {\n values.push(value);\n }\n }\n return values;\n }\n\n async getSelectLabels(locator: PartLocator): Promise<Optional<readonly string[]>> {\n const optionLocator: PartLocator = byCssSelector('option:checked');\n const selectedOptionLocator = locatorUtil.append(locator, optionLocator);\n const cssLocator = await locatorUtil.toCssSelector(selectedOptionLocator, this);\n const allOptions = await this.page.locator(cssLocator).all();\n const labels: string[] = [];\n for (const option of allOptions) {\n const label = await option.textContent();\n if (label != null) {\n labels.push(label);\n }\n }\n return labels;\n }\n\n async getStyleValue(locator: PartLocator, propertyName: CssProperty): Promise<Optional<string>> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const elLocator = this.page.locator(cssLocator);\n const value = await elLocator.evaluate((element, prop) => {\n return window.getComputedStyle(element).getPropertyValue(prop as string);\n }, propertyName);\n return value;\n }\n\n async enterText(locator: PartLocator, text: string, option?: Optional<Partial<EnterTextOption>>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'enterText', async () => {\n if (!option?.append) {\n await this.page.locator(cssLocator).clear();\n }\n\n // If it is a date, time or datetime-local input, validate the date format\n const type = (await this.getAttribute(locator, 'type')) ?? '';\n if (dateUtil.isHtmlDateInputType(type)) {\n const result = dateUtil.validateHtmlDateInput(type, text);\n if (!result.valid) {\n throw new Error(\n `Invalid date format for type: ${type}, expected format: ${result.format}, example: ${result.example}`\n );\n }\n }\n await this.page.locator(cssLocator).fill(text);\n });\n }\n\n async setRangeValue(locator: PartLocator, value: number): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n // Playwright's `fill` rejects `<input type=\"range\">` (it is not a fillable\n // text control), so set the value in-page through the native value setter.\n // Calling the prototype setter both sanitizes the value to the input's step\n // (the browser snaps an off-step target to the nearest valid step) and lets\n // React's value tracker observe the change; the dispatched input/change\n // events then drive a controlled component (e.g. MUI Slider) to re-render.\n await this.runMutation(locator, 'setRangeValue', () =>\n this.page.locator(cssLocator).evaluate((el, nextValue) => {\n const input = el as HTMLInputElement;\n const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;\n setter?.call(input, nextValue);\n input.dispatchEvent(new Event('input', { bubbles: true }));\n input.dispatchEvent(new Event('change', { bubbles: true }));\n }, String(value))\n );\n }\n\n async click(locator: PartLocator, option?: Partial<ClickOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'click', () => this.page.locator(cssLocator).click({ position: option?.position }));\n }\n\n /**\n * Dispatch a right-click on the located element to open its context menu.\n *\n * Delegates to Playwright's native right-button click, which fires a real\n * `contextmenu` event in the browser.\n *\n * @param locator - Locator of the element to right-click\n * @throws {ElementNotFoundError} If the element is not found\n */\n async contextMenu(locator: PartLocator): Promise<void> {\n const css = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'contextMenu', () => this.page.locator(css).click({ button: 'right' }));\n }\n\n async hover(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'hover', () => this.page.locator(cssLocator).hover({ position: option?.position }));\n }\n\n async mouseMove(locator: PartLocator, option?: Partial<MouseMoveOption>): Promise<void> {\n await this.runMutation(locator, 'mouseMove', async () => {\n await this.hover(locator, { position: option?.position });\n await this.page.mouse.move(0, 0);\n });\n }\n\n async mouseDown(locator: PartLocator, option?: Partial<MouseDownOption>): Promise<void> {\n await this.runMutation(locator, 'mouseDown', async () => {\n await this.hover(locator, { position: option?.position });\n await this.page.mouse.down();\n });\n }\n\n async mouseUp(locator: PartLocator, option?: Partial<MouseUpOption>): Promise<void> {\n await this.runMutation(locator, 'mouseUp', async () => {\n await this.hover(locator, { position: option?.position });\n await this.page.mouse.up();\n });\n }\n\n async mouseOver(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {\n await this.runMutation(locator, 'mouseOver', () => this.hover(locator, option));\n }\n\n async mouseOut(locator: PartLocator, _option?: Partial<MouseOutOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'mouseOut', async () => {\n // First hover over the element to trigger mouseenter/mouseover\n await this.page.locator(cssLocator).hover();\n // Then dispatch mouseout event directly for cross-browser reliability\n await this.page.locator(cssLocator).dispatchEvent('mouseout');\n });\n }\n\n async mouseEnter(locator: PartLocator, _option?: Partial<MouseEnterOption>): Promise<void> {\n await this.runMutation(locator, 'mouseEnter', () => this.hover(locator));\n }\n\n async mouseLeave(locator: PartLocator, _option?: Partial<MouseLeaveOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'mouseLeave', async () => {\n // First hover over the element to trigger mouseenter/mouseover\n await this.page.locator(cssLocator).hover();\n // Dispatch mouseout which triggers both mouseout and mouseleave handlers in React\n await this.page.locator(cssLocator).dispatchEvent('mouseout');\n });\n }\n\n async focus(locator: PartLocator, _option?: Partial<FocusOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'focus', () => this.page.focus(cssLocator));\n }\n\n async blur(locator: PartLocator, _option?: Partial<BlurOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n await this.runMutation(locator, 'blur', () => this.page.locator(cssLocator).blur());\n }\n\n async pressKey(locator: PartLocator, key: string, option?: Partial<PressKeyOption>): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n // Compose Playwright's chord syntax — modifiers joined to the key by `+`, in\n // Playwright's accepted Control+Alt+Shift+Meta order — so the browser holds\n // those modifiers across the keypress and the event carries ctrlKey/etc.\n const modifiers: string[] = [];\n if (option?.ctrl) {\n modifiers.push('Control');\n }\n if (option?.alt) {\n modifiers.push('Alt');\n }\n if (option?.shift) {\n modifiers.push('Shift');\n }\n if (option?.meta) {\n modifiers.push('Meta');\n }\n const chord = modifiers.length > 0 ? `${modifiers.join('+')}+${key}` : key;\n // locator.press auto-focuses the element, then dispatches a real, trusted\n // KeyboardEvent — the browser equivalent of the DOM focus-first keyDown/keyUp.\n // Caveat: for Shift + a printable key the browser case-folds `event.key`\n // (`Shift+a` → `'A'`) whereas the jsdom path keeps `'a'` — only the modifier\n // flags are delivered identically across engines (see #924).\n await this.runMutation(locator, 'pressKey', () => this.page.locator(cssLocator).press(chord));\n }\n\n async activate(locator: PartLocator): Promise<void> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n // Geometry-free activation mirrors the mouseout dispatch precedent above: it\n // bypasses hit-testing to actuate a covered or zero-size input that\n // locator.click() (a real geometry hit-test) cannot reach.\n await this.runMutation(locator, 'activate', () => this.page.locator(cssLocator).dispatchEvent('click'));\n }\n\n //#region wait conditions\n wait(ms: number): Promise<void> {\n return timingUtil.wait(ms);\n }\n\n async waitUntilComponentState(\n locator: PartLocator,\n option: Partial<Readonly<WaitForOption>> = defaultWaitForOption\n ): Promise<void> {\n return interactorUtil.interactorWaitUtil(locator, this, option);\n }\n\n waitUntil<T>(option: WaitUntilOption<T>): Promise<T> {\n return timingUtil.waitUntil(option);\n }\n //#endregion\n\n async getAttribute(locator: PartLocator, name: string, isMultiple: true): Promise<readonly string[]>;\n async getAttribute(locator: PartLocator, name: string, isMultiple: false): Promise<Optional<string>>;\n async getAttribute(locator: PartLocator, name: string): Promise<Optional<string>>;\n async getAttribute(\n locator: PartLocator,\n name: string,\n isMultiple?: boolean\n ): Promise<Optional<string> | readonly string[]> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const elLocator = this.page.locator(cssLocator);\n if (isMultiple) {\n const locators = await elLocator.all();\n const values: string[] = [];\n for (const locator of locators) {\n const value = await locator.getAttribute(name);\n if (value != null) {\n values.push(value);\n }\n }\n return values;\n }\n const value = await elLocator.getAttribute(name);\n return value ?? undefined;\n }\n\n async getText(locator: PartLocator): Promise<Optional<string>> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const text = await this.page.locator(cssLocator).textContent();\n return text ?? undefined;\n }\n\n /**\n * Get the located element's bounding rectangle.\n *\n * `boundingBox()` returns `null` for a detached/invisible element rather than\n * auto-waiting, so this throws `ElementNotFoundError` directly (no auto-wait)\n * — matching the unified \"element not found\" contract (ADR-006).\n *\n * @param locator - Locator of the element to measure\n * @returns The element's bounding rectangle in CSS pixels\n * @throws {ElementNotFoundError} If the element has no bounding box\n */\n async getBoundingRect(locator: PartLocator): Promise<BoundingRect> {\n const css = await locatorUtil.toCssSelector(locator, this);\n const box = await this.page.locator(css).boundingBox();\n if (box == null) {\n throw new ElementNotFoundError(locator, 'getBoundingRect');\n }\n return { x: box.x, y: box.y, width: box.width, height: box.height };\n }\n\n async exists(locator: PartLocator): Promise<boolean> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const count = await this.page.locator(cssLocator).count();\n return count > 0;\n }\n\n async isChecked(locator: PartLocator): Promise<boolean> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const checked = await this.page.locator(cssLocator).isChecked();\n return checked;\n }\n\n async isDisabled(locator: PartLocator): Promise<boolean> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n const isDisabled = await this.page.locator(cssLocator).isDisabled();\n return isDisabled;\n }\n\n async isReadonly(locator: PartLocator): Promise<boolean> {\n const readonly = await this.getAttribute(locator, 'readonly');\n return readonly != null;\n }\n\n async isVisible(locator: PartLocator): Promise<boolean> {\n const exists = await this.exists(locator);\n if (!exists) {\n return false;\n }\n\n async function checkCssVisibility(\n prop: CssProperty,\n invisibleValue: string,\n interactor: PlaywrightInteractor\n ): Promise<boolean> {\n try {\n const value = await interactor.getStyleValue(locator, prop);\n return value !== invisibleValue;\n } catch (e) {\n // Element may disappear or detached while being checked because of animation\n // when it happens, an error is thrown. In this case, if indeed the element\n // is not visible, we return false. Otherwise, we re-throw the error.\n if ((await interactor.exists(locator)) === false) {\n return false;\n }\n throw e;\n }\n }\n\n if ((await checkCssVisibility('opacity', '0', this)) === false) {\n return false;\n }\n\n if ((await checkCssVisibility('visibility', 'hidden', this)) === false) {\n return false;\n }\n\n if ((await checkCssVisibility('display', 'none', this)) === false) {\n return false;\n }\n\n return true;\n }\n\n async hasCssClass(locator: PartLocator, className: string): Promise<boolean> {\n const classNames = await this.getAttribute(locator, 'class');\n if (classNames == null) {\n return false;\n }\n\n const names = classNames.split(/\\s+/);\n return names.includes(className);\n }\n\n async hasAttribute(locator: PartLocator, name: string): Promise<boolean> {\n const attrValue = await this.getAttribute(locator, name);\n return attrValue != null;\n }\n\n //#region\n async innerHTML(locator: PartLocator): Promise<string> {\n const cssLocator = await locatorUtil.toCssSelector(locator, this);\n return this.page.locator(cssLocator).innerHTML();\n }\n //#endregion\n\n clone(): Interactor {\n return new PlaywrightInteractor(this.page);\n }\n}\n","import { ScenePart, TestEngine } from '@atomic-testing/core';\nimport { Page } from '@playwright/test';\n\nimport { PlaywrightInteractor } from './PlaywrightInteractor';\n\n/**\n * Create a {@link TestEngine} instance backed by Playwright.\n *\n * @param page - Playwright page used for interaction.\n * @param partDefinitions - Scene part definitions describing the scene\n * structure for the engine.\n * @returns A configured {@link TestEngine} ready for use.\n */\nexport function createTestEngine<T extends ScenePart>(page: Page, partDefinitions: T): TestEngine<T> {\n const engine = new TestEngine([], new PlaywrightInteractor(page), {\n parts: partDefinitions,\n });\n\n return engine;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomic-testing/playwright",
3
- "version": "0.88.0",
3
+ "version": "0.89.0",
4
4
  "description": "Atomic Testing Playwright Adapter",
5
5
  "keywords": [],
6
6
  "license": "MIT",
@@ -25,14 +25,14 @@
25
25
  }
26
26
  },
27
27
  "dependencies": {
28
- "@atomic-testing/core": "0.88.0",
29
- "@atomic-testing/internal-test-runner": "0.88.0"
28
+ "@atomic-testing/core": "0.89.0"
30
29
  },
31
30
  "peerDependencies": {
32
31
  "@playwright/test": ">=1.50.0"
33
32
  },
34
33
  "scripts": {
35
34
  "build": "tsdown",
36
- "check:type": "tsgo --noEmit"
35
+ "check:type": "tsgo --noEmit",
36
+ "check:api": "api-extractor run"
37
37
  }
38
38
  }