@atomic-testing/playwright 0.59.0 → 0.70.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.d.mts CHANGED
@@ -3,14 +3,47 @@ import { Page } from "@playwright/test";
3
3
  import { E2eTestInterface, E2eTestRunEnvironmentFixture, TestFrameworkMapper } from "@atomic-testing/test-runner";
4
4
 
5
5
  //#region src/createTestEngine.d.ts
6
+
7
+ /**
8
+ * Create a {@link TestEngine} instance backed by Playwright.
9
+ *
10
+ * @param page - Playwright page used for interaction.
11
+ * @param partDefinitions - Scene part definitions describing the scene
12
+ * structure for the engine.
13
+ * @returns A configured {@link TestEngine} ready for use.
14
+ */
6
15
  declare function createTestEngine<T extends ScenePart>(page: Page, partDefinitions: T): TestEngine<T>;
7
16
  //#endregion
8
17
  //#region src/PlaywrightInteractor.d.ts
18
+ /**
19
+ * Implementation of the {@link Interactor} interface using Playwright.
20
+ */
9
21
  declare class PlaywrightInteractor implements Interactor {
10
22
  readonly page: Page;
23
+ /**
24
+ * @param page - Playwright page instance used to drive the browser.
25
+ */
11
26
  constructor(page: Page);
27
+ /**
28
+ * Select the given option values on a `<select>` element.
29
+ *
30
+ * @param locator - Locator to the `<select>` element.
31
+ * @param values - Values to select.
32
+ */
12
33
  selectOptionValue(locator: PartLocator, values: string[]): Promise<void>;
34
+ /**
35
+ * Get the value of an `<input>` element.
36
+ *
37
+ * @param locator - Locator pointing to the input element.
38
+ * @returns The current value of the input or `undefined` if not present.
39
+ */
13
40
  getInputValue(locator: PartLocator): Promise<Optional<string>>;
41
+ /**
42
+ * Retrieve the values of selected options within a `<select>` element.
43
+ *
44
+ * @param locator - Locator to the `<select>` element.
45
+ * @returns Array of selected option values or `undefined` when no option is selected.
46
+ */
14
47
  getSelectValues(locator: PartLocator): Promise<Optional<readonly string[]>>;
15
48
  getSelectLabels(locator: PartLocator): Promise<Optional<readonly string[]>>;
16
49
  getStyleValue(locator: PartLocator, propertyName: CssProperty): Promise<Optional<string>>;
@@ -44,10 +77,25 @@ declare class PlaywrightInteractor implements Interactor {
44
77
  }
45
78
  //#endregion
46
79
  //#region src/testRunnerAdapter.d.ts
80
+ /**
81
+ * Navigate the current Playwright page to the provided URL.
82
+ *
83
+ * @param url - Destination URL to load.
84
+ * @param fixture - Optional test fixture supplying the Playwright page.
85
+ */
47
86
  declare function goto(url: string): Promise<void>;
48
87
  declare function goto(url: string, fixture: E2eTestRunEnvironmentFixture): Promise<void>;
88
+ /**
89
+ * Create a {@link TestEngine} bound to the Playwright page in the given fixture.
90
+ *
91
+ * @param scenePart - Scene definition to drive.
92
+ * @param fixture - Fixture providing the Playwright page.
93
+ */
49
94
  declare function playwrightGetTestEngine<T extends ScenePart>(scenePart: T, fixture: E2eTestRunEnvironmentFixture): TestEngine<T>;
50
95
  declare const playWrightTestFrameworkMapper: TestFrameworkMapper;
96
+ /**
97
+ * Get a typed interface for running end-to-end tests with Playwright.
98
+ */
51
99
  declare function getTestRunnerInterface<T extends ScenePart>(): E2eTestInterface<T>;
52
100
  //#endregion
53
101
  export { PlaywrightInteractor, createTestEngine, getTestRunnerInterface, goto, playWrightTestFrameworkMapper, playwrightGetTestEngine };
package/dist/index.d.ts CHANGED
@@ -3,14 +3,47 @@ import { Page } from "@playwright/test";
3
3
  import { E2eTestInterface, E2eTestRunEnvironmentFixture, TestFrameworkMapper } from "@atomic-testing/test-runner";
4
4
 
5
5
  //#region src/createTestEngine.d.ts
6
+
7
+ /**
8
+ * Create a {@link TestEngine} instance backed by Playwright.
9
+ *
10
+ * @param page - Playwright page used for interaction.
11
+ * @param partDefinitions - Scene part definitions describing the scene
12
+ * structure for the engine.
13
+ * @returns A configured {@link TestEngine} ready for use.
14
+ */
6
15
  declare function createTestEngine<T extends ScenePart>(page: Page, partDefinitions: T): TestEngine<T>;
7
16
  //#endregion
8
17
  //#region src/PlaywrightInteractor.d.ts
18
+ /**
19
+ * Implementation of the {@link Interactor} interface using Playwright.
20
+ */
9
21
  declare class PlaywrightInteractor implements Interactor {
10
22
  readonly page: Page;
23
+ /**
24
+ * @param page - Playwright page instance used to drive the browser.
25
+ */
11
26
  constructor(page: Page);
27
+ /**
28
+ * Select the given option values on a `<select>` element.
29
+ *
30
+ * @param locator - Locator to the `<select>` element.
31
+ * @param values - Values to select.
32
+ */
12
33
  selectOptionValue(locator: PartLocator, values: string[]): Promise<void>;
34
+ /**
35
+ * Get the value of an `<input>` element.
36
+ *
37
+ * @param locator - Locator pointing to the input element.
38
+ * @returns The current value of the input or `undefined` if not present.
39
+ */
13
40
  getInputValue(locator: PartLocator): Promise<Optional<string>>;
41
+ /**
42
+ * Retrieve the values of selected options within a `<select>` element.
43
+ *
44
+ * @param locator - Locator to the `<select>` element.
45
+ * @returns Array of selected option values or `undefined` when no option is selected.
46
+ */
14
47
  getSelectValues(locator: PartLocator): Promise<Optional<readonly string[]>>;
15
48
  getSelectLabels(locator: PartLocator): Promise<Optional<readonly string[]>>;
16
49
  getStyleValue(locator: PartLocator, propertyName: CssProperty): Promise<Optional<string>>;
@@ -44,10 +77,25 @@ declare class PlaywrightInteractor implements Interactor {
44
77
  }
45
78
  //#endregion
46
79
  //#region src/testRunnerAdapter.d.ts
80
+ /**
81
+ * Navigate the current Playwright page to the provided URL.
82
+ *
83
+ * @param url - Destination URL to load.
84
+ * @param fixture - Optional test fixture supplying the Playwright page.
85
+ */
47
86
  declare function goto(url: string): Promise<void>;
48
87
  declare function goto(url: string, fixture: E2eTestRunEnvironmentFixture): Promise<void>;
88
+ /**
89
+ * Create a {@link TestEngine} bound to the Playwright page in the given fixture.
90
+ *
91
+ * @param scenePart - Scene definition to drive.
92
+ * @param fixture - Fixture providing the Playwright page.
93
+ */
49
94
  declare function playwrightGetTestEngine<T extends ScenePart>(scenePart: T, fixture: E2eTestRunEnvironmentFixture): TestEngine<T>;
50
95
  declare const playWrightTestFrameworkMapper: TestFrameworkMapper;
96
+ /**
97
+ * Get a typed interface for running end-to-end tests with Playwright.
98
+ */
51
99
  declare function getTestRunnerInterface<T extends ScenePart>(): E2eTestInterface<T>;
52
100
  //#endregion
53
101
  export { PlaywrightInteractor, createTestEngine, getTestRunnerInterface, goto, playWrightTestFrameworkMapper, playwrightGetTestEngine };
package/dist/index.js CHANGED
@@ -25,18 +25,42 @@ const __atomic_testing_core = __toESM(require("@atomic-testing/core"));
25
25
  const __playwright_test = __toESM(require("@playwright/test"));
26
26
 
27
27
  //#region src/PlaywrightInteractor.ts
28
+ /**
29
+ * Implementation of the {@link Interactor} interface using Playwright.
30
+ */
28
31
  var PlaywrightInteractor = class PlaywrightInteractor {
32
+ /**
33
+ * @param page - Playwright page instance used to drive the browser.
34
+ */
29
35
  constructor(page) {
30
36
  this.page = page;
31
37
  }
38
+ /**
39
+ * Select the given option values on a `<select>` element.
40
+ *
41
+ * @param locator - Locator to the `<select>` element.
42
+ * @param values - Values to select.
43
+ */
32
44
  async selectOptionValue(locator, values) {
33
45
  const cssLocator = await __atomic_testing_core.locatorUtil.toCssSelector(locator, this);
34
46
  await this.page.locator(cssLocator).selectOption(values);
35
47
  }
48
+ /**
49
+ * Get the value of an `<input>` element.
50
+ *
51
+ * @param locator - Locator pointing to the input element.
52
+ * @returns The current value of the input or `undefined` if not present.
53
+ */
36
54
  async getInputValue(locator) {
37
55
  const cssLocator = await __atomic_testing_core.locatorUtil.toCssSelector(locator, this);
38
56
  return this.page.locator(cssLocator).inputValue();
39
57
  }
58
+ /**
59
+ * Retrieve the values of selected options within a `<select>` element.
60
+ *
61
+ * @param locator - Locator to the `<select>` element.
62
+ * @returns Array of selected option values or `undefined` when no option is selected.
63
+ */
40
64
  async getSelectValues(locator) {
41
65
  const optionLocator = (0, __atomic_testing_core.byCssSelector)("option:checked");
42
66
  const selectedOptionLocator = __atomic_testing_core.locatorUtil.append(locator, optionLocator);
@@ -205,6 +229,14 @@ var PlaywrightInteractor = class PlaywrightInteractor {
205
229
 
206
230
  //#endregion
207
231
  //#region src/createTestEngine.ts
232
+ /**
233
+ * Create a {@link TestEngine} instance backed by Playwright.
234
+ *
235
+ * @param page - Playwright page used for interaction.
236
+ * @param partDefinitions - Scene part definitions describing the scene
237
+ * structure for the engine.
238
+ * @returns A configured {@link TestEngine} ready for use.
239
+ */
208
240
  function createTestEngine(page, partDefinitions) {
209
241
  const engine = new __atomic_testing_core.TestEngine([], new PlaywrightInteractor(page), { parts: partDefinitions });
210
242
  return engine;
@@ -216,6 +248,12 @@ async function goto(url, fixture) {
216
248
  const page = fixture.page;
217
249
  await page.goto(url);
218
250
  }
251
+ /**
252
+ * Create a {@link TestEngine} bound to the Playwright page in the given fixture.
253
+ *
254
+ * @param scenePart - Scene definition to drive.
255
+ * @param fixture - Fixture providing the Playwright page.
256
+ */
219
257
  function playwrightGetTestEngine(scenePart, fixture) {
220
258
  const page = fixture.page;
221
259
  return createTestEngine(page, scenePart);
@@ -230,6 +268,9 @@ const playWrightTestFrameworkMapper = {
230
268
  test: __playwright_test.test,
231
269
  it: __playwright_test.test
232
270
  };
271
+ /**
272
+ * Get a typed interface for running end-to-end tests with Playwright.
273
+ */
233
274
  function getTestRunnerInterface() {
234
275
  return {
235
276
  getTestEngine: playwrightGetTestEngine,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["page: Page","locator: PartLocator","values: string[]","optionLocator: PartLocator","labels: string[]","propertyName: CssProperty","text: string","option?: Optional<Partial<EnterTextOption>>","option?: Partial<ClickOption>","option?: Partial<HoverOption>","option?: Partial<MouseMoveOption>","option?: Partial<MouseDownOption>","option?: Partial<MouseUpOption>","_option?: Partial<MouseOutOption>","_option?: Partial<MouseEnterOption>","_option?: Partial<MouseLeaveOption>","_option: Partial<FocusOption>","ms: number","option: Partial<Readonly<WaitForOption>>","defaultWaitForOption","option: WaitUntilOption<T>","name: string","isMultiple?: boolean","locator","value","prop: CssProperty","invisibleValue: string","interactor: PlaywrightInteractor","className: string","page: Page","partDefinitions: T","TestEngine","url: string","fixture?: E2eTestRunEnvironmentFixture","scenePart: T","fixture: E2eTestRunEnvironmentFixture","playWrightTestFrameworkMapper: TestFrameworkMapper","test"],"sources":["../src/PlaywrightInteractor.ts","../src/createTestEngine.ts","../src/testRunnerAdapter.ts"],"sourcesContent":["import {\n byCssSelector,\n ClickOption,\n CssProperty,\n dateUtil,\n defaultWaitForOption,\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 timingUtil,\n WaitForOption,\n WaitUntilOption,\n} from '@atomic-testing/core';\nimport { Page } from '@playwright/test';\n\nexport class PlaywrightInteractor implements Interactor {\n constructor(public readonly page: Page) {}\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 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 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 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 await this.hover(locator, {\n position: {\n x: 0,\n y: 0,\n },\n });\n await this.page.mouse.move(-10, -10);\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 return this.mouseOut(locator);\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 //#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 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\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 { E2eTestInterface, E2eTestRunEnvironmentFixture, TestFrameworkMapper } from '@atomic-testing/test-runner';\nimport { expect, Page, test } from '@playwright/test';\n\nimport { createTestEngine } from './createTestEngine';\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\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\nexport const playWrightTestFrameworkMapper: TestFrameworkMapper = {\n assertEqual: (a, b) => expect(a).toEqual(b),\n // @ts-expect-error - expect type is not compatible with the type of the test framework\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 - expect type is not compatible with the type of the test framework\n test: test,\n\n // @ts-expect-error - expect type is not compatible with the type of the test framework\n it: test,\n};\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.js","names":["page: Page","locator: PartLocator","values: string[]","optionLocator: PartLocator","labels: string[]","propertyName: CssProperty","text: string","option?: Optional<Partial<EnterTextOption>>","option?: Partial<ClickOption>","option?: Partial<HoverOption>","option?: Partial<MouseMoveOption>","option?: Partial<MouseDownOption>","option?: Partial<MouseUpOption>","_option?: Partial<MouseOutOption>","_option?: Partial<MouseEnterOption>","_option?: Partial<MouseLeaveOption>","_option: Partial<FocusOption>","ms: number","option: Partial<Readonly<WaitForOption>>","defaultWaitForOption","option: WaitUntilOption<T>","name: string","isMultiple?: boolean","locator","value","prop: CssProperty","invisibleValue: string","interactor: PlaywrightInteractor","className: string","page: Page","partDefinitions: T","TestEngine","url: string","fixture?: E2eTestRunEnvironmentFixture","scenePart: T","fixture: E2eTestRunEnvironmentFixture","playWrightTestFrameworkMapper: TestFrameworkMapper","test"],"sources":["../src/PlaywrightInteractor.ts","../src/createTestEngine.ts","../src/testRunnerAdapter.ts"],"sourcesContent":["import {\n byCssSelector,\n ClickOption,\n CssProperty,\n dateUtil,\n defaultWaitForOption,\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 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 * 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 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 await this.hover(locator, {\n position: {\n x: 0,\n y: 0,\n },\n });\n await this.page.mouse.move(-10, -10);\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 return this.mouseOut(locator);\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 //#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 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>(\n page: Page,\n partDefinitions: T,\n): 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/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\nexport const playWrightTestFrameworkMapper: TestFrameworkMapper = {\n assertEqual: (a, b) => expect(a).toEqual(b),\n // @ts-expect-error - expect type is not compatible with the type of the test framework\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 - expect type is not compatible with the type of the test framework\n test: test,\n\n // @ts-expect-error - expect type is not compatible with the type of the test framework\n it: test,\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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"}
package/dist/index.mjs CHANGED
@@ -2,18 +2,42 @@ import { TestEngine, byCssSelector, dateUtil, defaultWaitForOption, interactorUt
2
2
  import { expect, test } from "@playwright/test";
3
3
 
4
4
  //#region src/PlaywrightInteractor.ts
5
+ /**
6
+ * Implementation of the {@link Interactor} interface using Playwright.
7
+ */
5
8
  var PlaywrightInteractor = class PlaywrightInteractor {
9
+ /**
10
+ * @param page - Playwright page instance used to drive the browser.
11
+ */
6
12
  constructor(page) {
7
13
  this.page = page;
8
14
  }
15
+ /**
16
+ * Select the given option values on a `<select>` element.
17
+ *
18
+ * @param locator - Locator to the `<select>` element.
19
+ * @param values - Values to select.
20
+ */
9
21
  async selectOptionValue(locator, values) {
10
22
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
11
23
  await this.page.locator(cssLocator).selectOption(values);
12
24
  }
25
+ /**
26
+ * Get the value of an `<input>` element.
27
+ *
28
+ * @param locator - Locator pointing to the input element.
29
+ * @returns The current value of the input or `undefined` if not present.
30
+ */
13
31
  async getInputValue(locator) {
14
32
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
15
33
  return this.page.locator(cssLocator).inputValue();
16
34
  }
35
+ /**
36
+ * Retrieve the values of selected options within a `<select>` element.
37
+ *
38
+ * @param locator - Locator to the `<select>` element.
39
+ * @returns Array of selected option values or `undefined` when no option is selected.
40
+ */
17
41
  async getSelectValues(locator) {
18
42
  const optionLocator = byCssSelector("option:checked");
19
43
  const selectedOptionLocator = locatorUtil.append(locator, optionLocator);
@@ -182,6 +206,14 @@ var PlaywrightInteractor = class PlaywrightInteractor {
182
206
 
183
207
  //#endregion
184
208
  //#region src/createTestEngine.ts
209
+ /**
210
+ * Create a {@link TestEngine} instance backed by Playwright.
211
+ *
212
+ * @param page - Playwright page used for interaction.
213
+ * @param partDefinitions - Scene part definitions describing the scene
214
+ * structure for the engine.
215
+ * @returns A configured {@link TestEngine} ready for use.
216
+ */
185
217
  function createTestEngine(page, partDefinitions) {
186
218
  const engine = new TestEngine([], new PlaywrightInteractor(page), { parts: partDefinitions });
187
219
  return engine;
@@ -193,6 +225,12 @@ async function goto(url, fixture) {
193
225
  const page = fixture.page;
194
226
  await page.goto(url);
195
227
  }
228
+ /**
229
+ * Create a {@link TestEngine} bound to the Playwright page in the given fixture.
230
+ *
231
+ * @param scenePart - Scene definition to drive.
232
+ * @param fixture - Fixture providing the Playwright page.
233
+ */
196
234
  function playwrightGetTestEngine(scenePart, fixture) {
197
235
  const page = fixture.page;
198
236
  return createTestEngine(page, scenePart);
@@ -207,6 +245,9 @@ const playWrightTestFrameworkMapper = {
207
245
  test,
208
246
  it: test
209
247
  };
248
+ /**
249
+ * Get a typed interface for running end-to-end tests with Playwright.
250
+ */
210
251
  function getTestRunnerInterface() {
211
252
  return {
212
253
  getTestEngine: playwrightGetTestEngine,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["page: Page","locator: PartLocator","values: string[]","optionLocator: PartLocator","labels: string[]","propertyName: CssProperty","text: string","option?: Optional<Partial<EnterTextOption>>","option?: Partial<ClickOption>","option?: Partial<HoverOption>","option?: Partial<MouseMoveOption>","option?: Partial<MouseDownOption>","option?: Partial<MouseUpOption>","_option?: Partial<MouseOutOption>","_option?: Partial<MouseEnterOption>","_option?: Partial<MouseLeaveOption>","_option: Partial<FocusOption>","ms: number","option: Partial<Readonly<WaitForOption>>","option: WaitUntilOption<T>","name: string","isMultiple?: boolean","locator","value","prop: CssProperty","invisibleValue: string","interactor: PlaywrightInteractor","className: string","page: Page","partDefinitions: T","url: string","fixture?: E2eTestRunEnvironmentFixture","scenePart: T","fixture: E2eTestRunEnvironmentFixture","playWrightTestFrameworkMapper: TestFrameworkMapper"],"sources":["../src/PlaywrightInteractor.ts","../src/createTestEngine.ts","../src/testRunnerAdapter.ts"],"sourcesContent":["import {\n byCssSelector,\n ClickOption,\n CssProperty,\n dateUtil,\n defaultWaitForOption,\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 timingUtil,\n WaitForOption,\n WaitUntilOption,\n} from '@atomic-testing/core';\nimport { Page } from '@playwright/test';\n\nexport class PlaywrightInteractor implements Interactor {\n constructor(public readonly page: Page) {}\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 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 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 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 await this.hover(locator, {\n position: {\n x: 0,\n y: 0,\n },\n });\n await this.page.mouse.move(-10, -10);\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 return this.mouseOut(locator);\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 //#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 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\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 { E2eTestInterface, E2eTestRunEnvironmentFixture, TestFrameworkMapper } from '@atomic-testing/test-runner';\nimport { expect, Page, test } from '@playwright/test';\n\nimport { createTestEngine } from './createTestEngine';\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\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\nexport const playWrightTestFrameworkMapper: TestFrameworkMapper = {\n assertEqual: (a, b) => expect(a).toEqual(b),\n // @ts-expect-error - expect type is not compatible with the type of the test framework\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 - expect type is not compatible with the type of the test framework\n test: test,\n\n // @ts-expect-error - expect type is not compatible with the type of the test framework\n it: test,\n};\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":["page: Page","locator: PartLocator","values: string[]","optionLocator: PartLocator","labels: string[]","propertyName: CssProperty","text: string","option?: Optional<Partial<EnterTextOption>>","option?: Partial<ClickOption>","option?: Partial<HoverOption>","option?: Partial<MouseMoveOption>","option?: Partial<MouseDownOption>","option?: Partial<MouseUpOption>","_option?: Partial<MouseOutOption>","_option?: Partial<MouseEnterOption>","_option?: Partial<MouseLeaveOption>","_option: Partial<FocusOption>","ms: number","option: Partial<Readonly<WaitForOption>>","option: WaitUntilOption<T>","name: string","isMultiple?: boolean","locator","value","prop: CssProperty","invisibleValue: string","interactor: PlaywrightInteractor","className: string","page: Page","partDefinitions: T","url: string","fixture?: E2eTestRunEnvironmentFixture","scenePart: T","fixture: E2eTestRunEnvironmentFixture","playWrightTestFrameworkMapper: TestFrameworkMapper"],"sources":["../src/PlaywrightInteractor.ts","../src/createTestEngine.ts","../src/testRunnerAdapter.ts"],"sourcesContent":["import {\n byCssSelector,\n ClickOption,\n CssProperty,\n dateUtil,\n defaultWaitForOption,\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 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 * 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 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 await this.hover(locator, {\n position: {\n x: 0,\n y: 0,\n },\n });\n await this.page.mouse.move(-10, -10);\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 return this.mouseOut(locator);\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 //#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 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>(\n page: Page,\n partDefinitions: T,\n): 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/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\nexport const playWrightTestFrameworkMapper: TestFrameworkMapper = {\n assertEqual: (a, b) => expect(a).toEqual(b),\n // @ts-expect-error - expect type is not compatible with the type of the test framework\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 - expect type is not compatible with the type of the test framework\n test: test,\n\n // @ts-expect-error - expect type is not compatible with the type of the test framework\n it: test,\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomic-testing/playwright",
3
- "version": "0.59.0",
3
+ "version": "0.70.0",
4
4
  "description": "Atomic Testing Playwright Adapter",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -18,8 +18,8 @@
18
18
  "directory": "packages/playwright"
19
19
  },
20
20
  "dependencies": {
21
- "@atomic-testing/core": "0.59.0",
22
- "@atomic-testing/test-runner": "0.59.0"
21
+ "@atomic-testing/core": "0.70.0",
22
+ "@atomic-testing/test-runner": "0.70.0"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@playwright/test": "^1.51.1",
@@ -24,19 +24,43 @@ import {
24
24
  } from '@atomic-testing/core';
25
25
  import { Page } from '@playwright/test';
26
26
 
27
+ /**
28
+ * Implementation of the {@link Interactor} interface using Playwright.
29
+ */
27
30
  export class PlaywrightInteractor implements Interactor {
31
+ /**
32
+ * @param page - Playwright page instance used to drive the browser.
33
+ */
28
34
  constructor(public readonly page: Page) {}
29
35
 
36
+ /**
37
+ * Select the given option values on a `<select>` element.
38
+ *
39
+ * @param locator - Locator to the `<select>` element.
40
+ * @param values - Values to select.
41
+ */
30
42
  async selectOptionValue(locator: PartLocator, values: string[]): Promise<void> {
31
43
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
32
44
  await this.page.locator(cssLocator).selectOption(values);
33
45
  }
34
46
 
47
+ /**
48
+ * Get the value of an `<input>` element.
49
+ *
50
+ * @param locator - Locator pointing to the input element.
51
+ * @returns The current value of the input or `undefined` if not present.
52
+ */
35
53
  async getInputValue(locator: PartLocator): Promise<Optional<string>> {
36
54
  const cssLocator = await locatorUtil.toCssSelector(locator, this);
37
55
  return this.page.locator(cssLocator).inputValue();
38
56
  }
39
57
 
58
+ /**
59
+ * Retrieve the values of selected options within a `<select>` element.
60
+ *
61
+ * @param locator - Locator to the `<select>` element.
62
+ * @returns Array of selected option values or `undefined` when no option is selected.
63
+ */
40
64
  async getSelectValues(locator: PartLocator): Promise<Optional<readonly string[]>> {
41
65
  const optionLocator: PartLocator = byCssSelector('option:checked');
42
66
  const selectedOptionLocator = locatorUtil.append(locator, optionLocator);
@@ -3,7 +3,18 @@ import { Page } from '@playwright/test';
3
3
 
4
4
  import { PlaywrightInteractor } from './PlaywrightInteractor';
5
5
 
6
- export function createTestEngine<T extends ScenePart>(page: Page, partDefinitions: T): TestEngine<T> {
6
+ /**
7
+ * Create a {@link TestEngine} instance backed by Playwright.
8
+ *
9
+ * @param page - Playwright page used for interaction.
10
+ * @param partDefinitions - Scene part definitions describing the scene
11
+ * structure for the engine.
12
+ * @returns A configured {@link TestEngine} ready for use.
13
+ */
14
+ export function createTestEngine<T extends ScenePart>(
15
+ page: Page,
16
+ partDefinitions: T,
17
+ ): TestEngine<T> {
7
18
  const engine = new TestEngine([], new PlaywrightInteractor(page), {
8
19
  parts: partDefinitions,
9
20
  });
@@ -1,9 +1,19 @@
1
1
  import { ScenePart, TestEngine } from '@atomic-testing/core';
2
- import { E2eTestInterface, E2eTestRunEnvironmentFixture, TestFrameworkMapper } from '@atomic-testing/test-runner';
2
+ import {
3
+ E2eTestInterface,
4
+ E2eTestRunEnvironmentFixture,
5
+ TestFrameworkMapper,
6
+ } from '@atomic-testing/test-runner';
3
7
  import { expect, Page, test } from '@playwright/test';
4
8
 
5
9
  import { createTestEngine } from './createTestEngine';
6
10
 
11
+ /**
12
+ * Navigate the current Playwright page to the provided URL.
13
+ *
14
+ * @param url - Destination URL to load.
15
+ * @param fixture - Optional test fixture supplying the Playwright page.
16
+ */
7
17
  export async function goto(url: string): Promise<void>;
8
18
  export async function goto(url: string, fixture: E2eTestRunEnvironmentFixture): Promise<void>;
9
19
  export async function goto(url: string, fixture?: E2eTestRunEnvironmentFixture): Promise<void> {
@@ -11,9 +21,15 @@ export async function goto(url: string, fixture?: E2eTestRunEnvironmentFixture):
11
21
  await page.goto(url);
12
22
  }
13
23
 
24
+ /**
25
+ * Create a {@link TestEngine} bound to the Playwright page in the given fixture.
26
+ *
27
+ * @param scenePart - Scene definition to drive.
28
+ * @param fixture - Fixture providing the Playwright page.
29
+ */
14
30
  export function playwrightGetTestEngine<T extends ScenePart>(
15
31
  scenePart: T,
16
- fixture: E2eTestRunEnvironmentFixture
32
+ fixture: E2eTestRunEnvironmentFixture,
17
33
  ): TestEngine<T> {
18
34
  const page = fixture.page as Page;
19
35
  return createTestEngine(page, scenePart);
@@ -36,6 +52,9 @@ export const playWrightTestFrameworkMapper: TestFrameworkMapper = {
36
52
  it: test,
37
53
  };
38
54
 
55
+ /**
56
+ * Get a typed interface for running end-to-end tests with Playwright.
57
+ */
39
58
  export function getTestRunnerInterface<T extends ScenePart>(): E2eTestInterface<T> {
40
59
  return {
41
60
  getTestEngine: playwrightGetTestEngine,