pomwright 1.5.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +5 -5
- package/dist/index.d.mts +75 -970
- package/dist/index.d.ts +75 -970
- package/dist/index.js +585 -1872
- package/dist/index.mjs +598 -1880
- package/package.json +9 -11
- package/AGENTS.md +0 -37
- package/docs/v1/BaseApi-explanation.md +0 -63
- package/docs/v1/BasePage-explanation.md +0 -96
- package/docs/v1/LocatorSchema-explanation.md +0 -271
- package/docs/v1/LocatorSchemaPath-explanation.md +0 -165
- package/docs/v1/PlaywrightReportLogger-explanation.md +0 -56
- package/docs/v1/get-locator-methods-explanation.md +0 -250
- package/docs/v1/intro-to-using-pomwright.md +0 -899
- package/docs/v1/sessionStorage-methods-explanation.md +0 -38
- package/docs/v1/tips-folder-structure.md +0 -38
- package/docs/v1-to-v2-migration/bridge-migration-guide.md +0 -159
- package/docs/v1-to-v2-migration/direct-migration-guide.md +0 -238
- package/docs/v1-to-v2-migration/v1-to-v2-comparison.md +0 -547
- package/docs/v2/PageObject.md +0 -293
- package/docs/v2/composing-locator-modules.md +0 -93
- package/docs/v2/locator-registry.md +0 -695
- package/docs/v2/logging.md +0 -168
- package/docs/v2/overview.md +0 -515
- package/docs/v2/session-storage.md +0 -160
- package/index.ts +0 -75
- package/intTestV2/.env +0 -0
- package/intTestV2/fixtures/testApp.fixtures.ts +0 -43
- package/intTestV2/package.json +0 -22
- package/intTestV2/page-object-models/testApp/pages/iframe/iframe.locatorSchema.ts +0 -24
- package/intTestV2/page-object-models/testApp/pages/iframe/iframe.page.ts +0 -17
- package/intTestV2/page-object-models/testApp/pages/testPage.locatorSchema.ts +0 -32
- package/intTestV2/page-object-models/testApp/pages/testPage.page.ts +0 -119
- package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.locatorSchema.ts +0 -29
- package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.page.ts +0 -48
- package/intTestV2/page-object-models/testApp/pages/testPath/testPath.locatorSchema.ts +0 -9
- package/intTestV2/page-object-models/testApp/pages/testPath/testPath.page.ts +0 -23
- package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.locatorSchema.ts +0 -114
- package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.page.ts +0 -23
- package/intTestV2/page-object-models/testApp/testApp.base.ts +0 -20
- package/intTestV2/playwright.config.ts +0 -54
- package/intTestV2/server.js +0 -216
- package/intTestV2/test-data/staticPage/index.html +0 -280
- package/intTestV2/test-data/staticPage/w3images/avatar2.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar3.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar5.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar6.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/forest.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/lights.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/mountains.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/nature.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/snow.jpg +0 -0
- package/intTestV2/tests/locatorRegistry/add/add.describe.spec.ts +0 -54
- package/intTestV2/tests/locatorRegistry/add/add.filter.spec.ts +0 -143
- package/intTestV2/tests/locatorRegistry/add/add.frameLocator.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.get.clone.spec.ts +0 -76
- package/intTestV2/tests/locatorRegistry/add/add.getByAltText.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getById.spec.ts +0 -45
- package/intTestV2/tests/locatorRegistry/add/add.getByLabel.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByPlaceholder.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByRole.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByTestId.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByText.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByTitle.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.locator.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.reuseExisting.spec.ts +0 -107
- package/intTestV2/tests/locatorRegistry/add/add.reuseReusable.spec.ts +0 -311
- package/intTestV2/tests/locatorRegistry/add/add.spec.ts +0 -159
- package/intTestV2/tests/locatorRegistry/filter.cycle.spec.ts +0 -39
- package/intTestV2/tests/locatorRegistry/getLocator/getLocator.spec.ts +0 -253
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.clearSteps.spec.ts +0 -105
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.describe.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.filter.spec.ts +0 -368
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getLocator.spec.ts +0 -56
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getNestedLocator.spec.ts +0 -175
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.nth.spec.ts +0 -60
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.remove.spec.ts +0 -32
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.replace.spec.ts +0 -24
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.spec.ts +0 -110
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.update.spec.ts +0 -322
- package/intTestV2/tests/locatorRegistry/getNestedLocator/getNestedLocator.spec.ts +0 -412
- package/intTestV2/tests/locatorRegistry/registry/registry.binding.spec.ts +0 -50
- package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.spec.ts +0 -115
- package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.typecheck.ts +0 -86
- package/intTestV2/tests/locatorRegistry/validation/validation.sub-path.spec.ts +0 -45
- package/intTestV2/tests/step/step.spec.ts +0 -49
- package/intTestV2/tests/testApp/color.spec.ts +0 -15
- package/intTestV2/tests/testApp/iframe.spec.ts +0 -57
- package/intTestV2/tests/testApp/testFilters.spec.ts +0 -24
- package/intTestV2/tests/testApp/testPage.spec.ts +0 -161
- package/intTestV2/tests/testApp/testPath.spec.ts +0 -18
- package/pack-build.sh +0 -11
- package/pack-test-v2.sh +0 -36
- package/playwright.base.ts +0 -42
- package/skills/README.md +0 -56
- package/skills/pomwright-v1-5-bridge-migration/SKILL.md +0 -40
- package/skills/pomwright-v1-5-bridge-migration/references/call-site-migration.md +0 -178
- package/skills/pomwright-v1-5-bridge-migration/references/schema-translation.md +0 -183
- package/skills/pomwright-v2-migration/SKILL.md +0 -63
- package/skills/pomwright-v2-migration/references/call-site-migration.md +0 -265
- package/skills/pomwright-v2-migration/references/class-migration.md +0 -266
- package/skills/pomwright-v2-migration/references/fixture-and-helpers.md +0 -423
- package/skills/pomwright-v2-migration/references/locator-registration.md +0 -344
- package/srcV2/fixture/base.fixtures.ts +0 -23
- package/srcV2/helpers/navigation.ts +0 -153
- package/srcV2/helpers/playwrightReportLogger.ts +0 -196
- package/srcV2/helpers/sessionStorage.ts +0 -251
- package/srcV2/helpers/stepDecorator.ts +0 -106
- package/srcV2/locators/index.ts +0 -15
- package/srcV2/locators/locatorQueryBuilder.ts +0 -427
- package/srcV2/locators/locatorRegistrationBuilder.ts +0 -558
- package/srcV2/locators/locatorRegistry.ts +0 -583
- package/srcV2/locators/locatorUpdateBuilder.ts +0 -602
- package/srcV2/locators/reusableLocatorBuilder.ts +0 -200
- package/srcV2/locators/types.ts +0 -256
- package/srcV2/locators/utils.ts +0 -309
- package/srcV2/locators/v1SchemaTranslator.ts +0 -178
- package/srcV2/pageObject.ts +0 -105
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import type { Page } from "@playwright/test";
|
|
3
|
-
import { LocatorRegistryInternal } from "../../../../srcV2/locators";
|
|
4
|
-
|
|
5
|
-
const createTestRegistry = <Paths extends string>(page: Page) => new LocatorRegistryInternal<Paths>(page);
|
|
6
|
-
|
|
7
|
-
const errMsg = "No locator schema registered for path";
|
|
8
|
-
|
|
9
|
-
test("add getById to registry", async ({ page }) => {
|
|
10
|
-
type LocatorSchemaPaths = "stringId" | "stringId.#stringId" | "regExpId";
|
|
11
|
-
|
|
12
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
13
|
-
|
|
14
|
-
expect(() => registry.get("stringId")).toThrowError(`${errMsg} "stringId".`);
|
|
15
|
-
expect(() => registry.get("stringId.#stringId")).toThrowError(`${errMsg} "stringId.#stringId".`);
|
|
16
|
-
expect(() => registry.get("regExpId")).toThrowError(`${errMsg} "regExpId".`);
|
|
17
|
-
|
|
18
|
-
registry.add("stringId").getById("unique-element");
|
|
19
|
-
registry.add("stringId.#stringId").getById("#unique-element");
|
|
20
|
-
|
|
21
|
-
const expectedStringIdDefinition = {
|
|
22
|
-
definition: { id: "unique-element", type: "id" },
|
|
23
|
-
locatorSchemaPath: "stringId",
|
|
24
|
-
steps: [],
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const expectedHashIdDefinition = {
|
|
28
|
-
...expectedStringIdDefinition,
|
|
29
|
-
locatorSchemaPath: "stringId.#stringId",
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
expect(registry.get("stringId")).toEqual(expectedStringIdDefinition);
|
|
33
|
-
expect(registry.get("stringId.#stringId")).toEqual(expectedHashIdDefinition);
|
|
34
|
-
|
|
35
|
-
const locator = registry.getLocator("stringId.#stringId");
|
|
36
|
-
expect(`${locator}`).toEqual("locator('#unique-element')");
|
|
37
|
-
|
|
38
|
-
registry.add("regExpId").getById(/unique-\w+/);
|
|
39
|
-
const regExpDefinition = {
|
|
40
|
-
definition: { id: /unique-\w+/, type: "id" },
|
|
41
|
-
locatorSchemaPath: "regExpId",
|
|
42
|
-
steps: [],
|
|
43
|
-
};
|
|
44
|
-
expect(registry.get("regExpId")).toEqual(regExpDefinition);
|
|
45
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import type { Page } from "@playwright/test";
|
|
3
|
-
import { LocatorRegistryInternal } from "../../../../srcV2/locators";
|
|
4
|
-
|
|
5
|
-
const createTestRegistry = <Paths extends string>(page: Page) => new LocatorRegistryInternal<Paths>(page);
|
|
6
|
-
|
|
7
|
-
const errMsg = "No locator schema registered for path";
|
|
8
|
-
|
|
9
|
-
test("add getByLabel to registry", async ({ page }) => {
|
|
10
|
-
type LocatorSchemaPaths = "elementByLabel";
|
|
11
|
-
|
|
12
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
13
|
-
|
|
14
|
-
expect(() => registry.get("elementByLabel")).toThrowError(`${errMsg} "elementByLabel".`);
|
|
15
|
-
|
|
16
|
-
registry.add("elementByLabel").getByLabel("Username");
|
|
17
|
-
|
|
18
|
-
expect(registry.get("elementByLabel")).toEqual({
|
|
19
|
-
definition: { text: "Username", type: "label" },
|
|
20
|
-
locatorSchemaPath: "elementByLabel",
|
|
21
|
-
steps: [],
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import type { Page } from "@playwright/test";
|
|
3
|
-
import { LocatorRegistryInternal } from "../../../../srcV2/locators";
|
|
4
|
-
|
|
5
|
-
const createTestRegistry = <Paths extends string>(page: Page) => new LocatorRegistryInternal<Paths>(page);
|
|
6
|
-
|
|
7
|
-
const errMsg = "No locator schema registered for path";
|
|
8
|
-
|
|
9
|
-
test("add getByPlaceholder to registry", async ({ page }) => {
|
|
10
|
-
type LocatorSchemaPaths = "elementByPlaceholder";
|
|
11
|
-
|
|
12
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
13
|
-
|
|
14
|
-
expect(() => registry.get("elementByPlaceholder")).toThrowError(`${errMsg} "elementByPlaceholder".`);
|
|
15
|
-
|
|
16
|
-
registry.add("elementByPlaceholder").getByPlaceholder("Enter your name");
|
|
17
|
-
|
|
18
|
-
expect(registry.get("elementByPlaceholder")).toEqual({
|
|
19
|
-
definition: { text: "Enter your name", type: "placeholder" },
|
|
20
|
-
locatorSchemaPath: "elementByPlaceholder",
|
|
21
|
-
steps: [],
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import type { Page } from "@playwright/test";
|
|
3
|
-
import { LocatorRegistryInternal } from "../../../../srcV2/locators";
|
|
4
|
-
|
|
5
|
-
const createTestRegistry = <Paths extends string>(page: Page) => new LocatorRegistryInternal<Paths>(page);
|
|
6
|
-
|
|
7
|
-
const errMsg = "No locator schema registered for path";
|
|
8
|
-
|
|
9
|
-
test("add getByRole to registry", async ({ page }) => {
|
|
10
|
-
type LocatorSchemaPaths = "buttonByRole";
|
|
11
|
-
|
|
12
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
13
|
-
|
|
14
|
-
expect(() => registry.get("buttonByRole")).toThrowError(`${errMsg} "buttonByRole".`);
|
|
15
|
-
|
|
16
|
-
registry.add("buttonByRole").getByRole("button", { name: "Submit" });
|
|
17
|
-
|
|
18
|
-
expect(registry.get("buttonByRole")).toEqual({
|
|
19
|
-
definition: { role: "button", options: { name: "Submit" }, type: "role" },
|
|
20
|
-
locatorSchemaPath: "buttonByRole",
|
|
21
|
-
steps: [],
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import type { Page } from "@playwright/test";
|
|
3
|
-
import { LocatorRegistryInternal } from "../../../../srcV2/locators";
|
|
4
|
-
|
|
5
|
-
const createTestRegistry = <Paths extends string>(page: Page) => new LocatorRegistryInternal<Paths>(page);
|
|
6
|
-
|
|
7
|
-
const errMsg = "No locator schema registered for path";
|
|
8
|
-
|
|
9
|
-
test("add getByTestId to registry", async ({ page }) => {
|
|
10
|
-
type LocatorSchemaPaths = "elementByTestId";
|
|
11
|
-
|
|
12
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
13
|
-
|
|
14
|
-
expect(() => registry.get("elementByTestId")).toThrowError(`${errMsg} "elementByTestId".`);
|
|
15
|
-
|
|
16
|
-
registry.add("elementByTestId").getByTestId("login-button");
|
|
17
|
-
|
|
18
|
-
expect(registry.get("elementByTestId")).toEqual({
|
|
19
|
-
definition: { testId: "login-button", type: "testId" },
|
|
20
|
-
locatorSchemaPath: "elementByTestId",
|
|
21
|
-
steps: [],
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import type { Page } from "@playwright/test";
|
|
3
|
-
import { LocatorRegistryInternal } from "../../../../srcV2/locators";
|
|
4
|
-
|
|
5
|
-
const createTestRegistry = <Paths extends string>(page: Page) => new LocatorRegistryInternal<Paths>(page);
|
|
6
|
-
|
|
7
|
-
const errMsg = "No locator schema registered for path";
|
|
8
|
-
|
|
9
|
-
test("add getByText to registry", async ({ page }) => {
|
|
10
|
-
type LocatorSchemaPaths = "elementByText";
|
|
11
|
-
|
|
12
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
13
|
-
|
|
14
|
-
expect(() => registry.get("elementByText")).toThrowError(`${errMsg} "elementByText".`);
|
|
15
|
-
|
|
16
|
-
registry.add("elementByText").getByText("Welcome");
|
|
17
|
-
|
|
18
|
-
expect(registry.get("elementByText")).toEqual({
|
|
19
|
-
definition: { text: "Welcome", type: "text" },
|
|
20
|
-
locatorSchemaPath: "elementByText",
|
|
21
|
-
steps: [],
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import type { Page } from "@playwright/test";
|
|
3
|
-
import { LocatorRegistryInternal } from "../../../../srcV2/locators";
|
|
4
|
-
|
|
5
|
-
const createTestRegistry = <Paths extends string>(page: Page) => new LocatorRegistryInternal<Paths>(page);
|
|
6
|
-
|
|
7
|
-
const errMsg = "No locator schema registered for path";
|
|
8
|
-
|
|
9
|
-
test("add getByTitle to registry", async ({ page }) => {
|
|
10
|
-
type LocatorSchemaPaths = "elementByTitle";
|
|
11
|
-
|
|
12
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
13
|
-
|
|
14
|
-
expect(() => registry.get("elementByTitle")).toThrowError(`${errMsg} "elementByTitle".`);
|
|
15
|
-
|
|
16
|
-
registry.add("elementByTitle").getByTitle("Home Page");
|
|
17
|
-
|
|
18
|
-
expect(registry.get("elementByTitle")).toEqual({
|
|
19
|
-
definition: { text: "Home Page", type: "title" },
|
|
20
|
-
locatorSchemaPath: "elementByTitle",
|
|
21
|
-
steps: [],
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import type { Page } from "@playwright/test";
|
|
3
|
-
import { LocatorRegistryInternal } from "../../../../srcV2/locators";
|
|
4
|
-
|
|
5
|
-
const createTestRegistry = <Paths extends string>(page: Page) => new LocatorRegistryInternal<Paths>(page);
|
|
6
|
-
|
|
7
|
-
const errMsg = "No locator schema registered for path";
|
|
8
|
-
|
|
9
|
-
test("add locator to registry", async ({ page }) => {
|
|
10
|
-
type LocatorSchemaPaths = "body";
|
|
11
|
-
|
|
12
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
13
|
-
|
|
14
|
-
expect(() => registry.get("body")).toThrowError(`${errMsg} "body".`);
|
|
15
|
-
|
|
16
|
-
registry.add("body").locator("body");
|
|
17
|
-
|
|
18
|
-
expect(registry.get("body")).toEqual({
|
|
19
|
-
definition: { selector: "body", type: "locator" },
|
|
20
|
-
locatorSchemaPath: "body",
|
|
21
|
-
steps: [],
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import type { Page } from "@playwright/test";
|
|
3
|
-
import { LocatorRegistryInternal } from "../../../../srcV2/locators";
|
|
4
|
-
|
|
5
|
-
const createTestRegistry = <Paths extends string>(page: Page) => new LocatorRegistryInternal<Paths>(page);
|
|
6
|
-
|
|
7
|
-
test("add reuses with existing record by path does not have chainable methods", async ({ page }) => {
|
|
8
|
-
type LocatorSchemaPaths = "button" | "button.copy";
|
|
9
|
-
|
|
10
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
11
|
-
|
|
12
|
-
registry.add("button").getByRole("button", { name: "Submit" }).filter({ hasText: "Submit" });
|
|
13
|
-
|
|
14
|
-
const builder = registry.add("button.copy", { reuse: "button" });
|
|
15
|
-
|
|
16
|
-
expect(builder).toBeUndefined();
|
|
17
|
-
expect(registry.get("button.copy")).toEqual({
|
|
18
|
-
definition: { role: "button", options: { name: "Submit" }, type: "role" },
|
|
19
|
-
locatorSchemaPath: "button.copy",
|
|
20
|
-
steps: [{ filter: { hasText: "Submit" }, kind: "filter" }],
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test("add reuse by path with empty string does not silently skip reuse", async ({ page }) => {
|
|
25
|
-
type LocatorSchemaPaths = "button";
|
|
26
|
-
|
|
27
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
28
|
-
|
|
29
|
-
// @ts-expect-error - testing runtime error when reuse is an empty string
|
|
30
|
-
expect(() => registry.add("button", { reuse: "" })).toThrowError('No locator schema registered for path "".');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test("add reuse by path throws when source path matches target path", async ({ page }) => {
|
|
34
|
-
type LocatorSchemaPaths = "button";
|
|
35
|
-
|
|
36
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
37
|
-
|
|
38
|
-
// @ts-expect-error - testing runtime error when reuse path is the same as registration path
|
|
39
|
-
expect(() => registry.add("button", { reuse: "button" })).toThrowError(
|
|
40
|
-
'Locator reuse path cannot be the same as registration path: "button".',
|
|
41
|
-
);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("add reuse by path reports compile-time fallback reason when forced at runtime", async ({ page }) => {
|
|
45
|
-
type LocatorSchemaPaths = "button" | "button.copy";
|
|
46
|
-
|
|
47
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
48
|
-
|
|
49
|
-
const addUnsafe = registry.add as unknown as (
|
|
50
|
-
path: string,
|
|
51
|
-
options: {
|
|
52
|
-
reuse: [string];
|
|
53
|
-
},
|
|
54
|
-
) => void;
|
|
55
|
-
|
|
56
|
-
expect(() =>
|
|
57
|
-
addUnsafe("button.copy", {
|
|
58
|
-
reuse: ["Invalid reuse path, reuse path cannot be the same as registration path: button.copy"],
|
|
59
|
-
}),
|
|
60
|
-
).toThrowError(
|
|
61
|
-
'Invalid reuse path configuration for "button.copy": Invalid reuse path, reuse path cannot be the same as registration path: button.copy',
|
|
62
|
-
);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test("add reuse by path clones records so mutations do not leak", async ({ page }) => {
|
|
66
|
-
type LocatorSchemaPaths = "button" | "button.copy";
|
|
67
|
-
|
|
68
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
69
|
-
|
|
70
|
-
registry.add("button").getByRole("button", { name: "Submit" }).filter({ hasText: "Submit" });
|
|
71
|
-
|
|
72
|
-
registry.add("button.copy", { reuse: "button" });
|
|
73
|
-
|
|
74
|
-
expect(registry.get("button.copy")).toEqual({
|
|
75
|
-
definition: { role: "button", options: { name: "Submit" }, type: "role" },
|
|
76
|
-
locatorSchemaPath: "button.copy",
|
|
77
|
-
steps: [{ filter: { hasText: "Submit" }, kind: "filter" }],
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
registry.replace("button.copy", {
|
|
81
|
-
definition: { role: "link", options: { name: "Copy" }, type: "role" },
|
|
82
|
-
locatorSchemaPath: "button.copy",
|
|
83
|
-
steps: [{ filter: { hasText: "Copy" }, kind: "filter" }],
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
expect(registry.get("button.copy")).toEqual({
|
|
87
|
-
definition: { role: "link", options: { name: "Copy" }, type: "role" },
|
|
88
|
-
locatorSchemaPath: "button.copy",
|
|
89
|
-
steps: [{ filter: { hasText: "Copy" }, kind: "filter" }],
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
expect(registry.get("button")).toEqual({
|
|
93
|
-
definition: { role: "button", options: { name: "Submit" }, type: "role" },
|
|
94
|
-
locatorSchemaPath: "button",
|
|
95
|
-
steps: [{ filter: { hasText: "Submit" }, kind: "filter" }],
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test("add reuse by path throws when the source path is missing", async ({ page }) => {
|
|
100
|
-
type LocatorSchemaPaths = "button" | "button.copy";
|
|
101
|
-
|
|
102
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
103
|
-
|
|
104
|
-
expect(() => registry.add("button.copy", { reuse: "button" })).toThrowError(
|
|
105
|
-
'No locator schema registered for path "button".',
|
|
106
|
-
);
|
|
107
|
-
});
|
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import type { Page } from "@playwright/test";
|
|
3
|
-
import { type FilterDefinition, LocatorRegistryInternal } from "../../../../srcV2/locators";
|
|
4
|
-
|
|
5
|
-
const createTestRegistry = <Paths extends string>(page: Page) => new LocatorRegistryInternal<Paths>(page);
|
|
6
|
-
|
|
7
|
-
test("add can reuse a reusable locator definition", async ({ page }) => {
|
|
8
|
-
type LocatorSchemaPaths = "heading" | "heading.first";
|
|
9
|
-
|
|
10
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
11
|
-
|
|
12
|
-
const h2 = registry.createReusable.getByRole("heading", { level: 2 }).filter({ hasText: /Summary/ });
|
|
13
|
-
|
|
14
|
-
registry.add("heading", { reuse: h2 });
|
|
15
|
-
registry.add("heading.first", { reuse: h2 }).nth(0);
|
|
16
|
-
|
|
17
|
-
expect(registry.get("heading")).toEqual({
|
|
18
|
-
definition: { role: "heading", options: { level: 2 }, type: "role" },
|
|
19
|
-
locatorSchemaPath: "heading",
|
|
20
|
-
steps: [{ filter: { hasText: /Summary/ }, kind: "filter" }],
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
expect(registry.get("heading.first")).toEqual({
|
|
24
|
-
definition: { role: "heading", options: { level: 2 }, type: "role" },
|
|
25
|
-
locatorSchemaPath: "heading.first",
|
|
26
|
-
steps: [
|
|
27
|
-
{ filter: { hasText: /Summary/ }, kind: "filter" },
|
|
28
|
-
{ index: 0, kind: "index" },
|
|
29
|
-
],
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test("reusable builder yields the same locator chain as a direct definition", async ({ page }) => {
|
|
34
|
-
type LocatorSchemaPaths = "heading" | "heading.reused";
|
|
35
|
-
|
|
36
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
37
|
-
|
|
38
|
-
const reusable = registry.createReusable.getByRole("heading", { level: 2 }).filter({ hasText: "Intro" }).nth(1);
|
|
39
|
-
|
|
40
|
-
registry.add("heading").getByRole("heading", { level: 2 }).filter({ hasText: "Intro" }).nth(1);
|
|
41
|
-
registry.add("heading.reused", { reuse: reusable });
|
|
42
|
-
|
|
43
|
-
const direct = registry.getLocator("heading");
|
|
44
|
-
const reused = registry.getLocator("heading.reused");
|
|
45
|
-
|
|
46
|
-
expect(`${reused}`).toEqual(`${direct}`);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("add reuse by reusable locator patches options while preserving selector", async ({ page }) => {
|
|
50
|
-
type LocatorSchemaPaths = "errorMessage" | "error.invalidPassword";
|
|
51
|
-
|
|
52
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
53
|
-
|
|
54
|
-
const errorMessage = registry.createReusable.locator("error-message");
|
|
55
|
-
registry.add("errorMessage", { reuse: errorMessage });
|
|
56
|
-
registry.add("error.invalidPassword", { reuse: errorMessage }).locator({ hasText: /invalid password/ });
|
|
57
|
-
|
|
58
|
-
expect(registry.get("errorMessage")).toEqual({
|
|
59
|
-
definition: { selector: "error-message", type: "locator" },
|
|
60
|
-
locatorSchemaPath: "errorMessage",
|
|
61
|
-
steps: [],
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
expect(registry.get("error.invalidPassword")).toEqual({
|
|
65
|
-
definition: { options: { hasText: /invalid password/ }, selector: "error-message", type: "locator" },
|
|
66
|
-
locatorSchemaPath: "error.invalidPassword",
|
|
67
|
-
steps: [],
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test("add reuse by reusable locator inherits selector and discriminant", async ({ page }) => {
|
|
72
|
-
type LocatorSchemaPaths = "errorMessage" | "error.invalidPassword";
|
|
73
|
-
|
|
74
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
75
|
-
|
|
76
|
-
const errorMessage = registry.createReusable.locator("error-message", { hasText: /invalid password/ });
|
|
77
|
-
registry.add("errorMessage", { reuse: errorMessage });
|
|
78
|
-
registry.add("error.invalidPassword", { reuse: errorMessage }).locator({ hasText: /invalid email/ });
|
|
79
|
-
|
|
80
|
-
expect(registry.get("errorMessage")).toEqual({
|
|
81
|
-
definition: { options: { hasText: /invalid password/ }, selector: "error-message", type: "locator" },
|
|
82
|
-
locatorSchemaPath: "errorMessage",
|
|
83
|
-
steps: [],
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
expect(registry.get("error.invalidPassword")).toEqual({
|
|
87
|
-
definition: { options: { hasText: /invalid email/ }, selector: "error-message", type: "locator" },
|
|
88
|
-
locatorSchemaPath: "error.invalidPassword",
|
|
89
|
-
steps: [],
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test("add reuse with a reusable locator does not mutate the reusable definition", async ({ page }) => {
|
|
94
|
-
type LocatorSchemaPaths = "heading" | "heading.first";
|
|
95
|
-
|
|
96
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
97
|
-
|
|
98
|
-
const reusable = registry.createReusable.getByRole("heading", { level: 2 }).filter({ hasText: /Summary/ });
|
|
99
|
-
|
|
100
|
-
registry.add("heading", { reuse: reusable });
|
|
101
|
-
registry.add("heading.first", { reuse: reusable }).nth(0);
|
|
102
|
-
|
|
103
|
-
expect(reusable.steps).toEqual([{ filter: { hasText: /Summary/ }, kind: "filter" }]);
|
|
104
|
-
expect(registry.get("heading")).toEqual({
|
|
105
|
-
definition: { role: "heading", options: { level: 2 }, type: "role" },
|
|
106
|
-
locatorSchemaPath: "heading",
|
|
107
|
-
steps: [{ filter: { hasText: /Summary/ }, kind: "filter" }],
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
expect(registry.get("heading.first")).toEqual({
|
|
111
|
-
definition: { role: "heading", options: { level: 2 }, type: "role" },
|
|
112
|
-
locatorSchemaPath: "heading.first",
|
|
113
|
-
steps: [
|
|
114
|
-
{ filter: { hasText: /Summary/ }, kind: "filter" },
|
|
115
|
-
{ index: 0, kind: "index" },
|
|
116
|
-
],
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("add reuse enforces matching locator type overrides", async ({ page }) => {
|
|
121
|
-
type LocatorSchemaPaths = "button" | "button.reuseLocator";
|
|
122
|
-
|
|
123
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
124
|
-
|
|
125
|
-
const button = registry.createReusable.getByRole("button", { name: "Submit" });
|
|
126
|
-
|
|
127
|
-
// @ts-expect-error mismatched locator strategies are not allowed when reusing a locator (getByText attempt on role locator)
|
|
128
|
-
expect(() => registry.add("button", { reuse: button }).getByText("text")).toThrowError(
|
|
129
|
-
'must use the "role" strategy',
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
registry.add("button", { reuse: button });
|
|
133
|
-
|
|
134
|
-
expect(registry.get("button")).toEqual({
|
|
135
|
-
definition: { role: "button", options: { name: "Submit" }, type: "role" },
|
|
136
|
-
locatorSchemaPath: "button",
|
|
137
|
-
steps: [],
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// @ts-expect-error mismatched locator strategies are not allowed when reusing a locator (getById attempt on role locator)
|
|
141
|
-
expect(() => registry.add("button.reuseLocator", { reuse: button }).getById("Submit")).toThrowError(
|
|
142
|
-
'must use the "role" strategy',
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
registry.add("button.reuseLocator", { reuse: button }).getByRole({ name: "Submit" });
|
|
146
|
-
|
|
147
|
-
expect(registry.get("button.reuseLocator")).toEqual({
|
|
148
|
-
definition: { role: "button", options: { name: "Submit" }, type: "role" },
|
|
149
|
-
locatorSchemaPath: "button.reuseLocator",
|
|
150
|
-
steps: [],
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
test("add reuse patches role options while preserving role value", async ({ page }) => {
|
|
155
|
-
type LocatorSchemaPaths = "heading";
|
|
156
|
-
|
|
157
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
158
|
-
const h2 = registry.createReusable.getByRole("heading", { level: 2 });
|
|
159
|
-
|
|
160
|
-
registry.add("heading", { reuse: h2 }).getByRole({ name: "Summary" });
|
|
161
|
-
|
|
162
|
-
expect(registry.get("heading")).toEqual({
|
|
163
|
-
definition: { role: "heading", options: { level: 2, name: "Summary" }, type: "role" },
|
|
164
|
-
locatorSchemaPath: "heading",
|
|
165
|
-
steps: [],
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
test("add reuse typing narrows override methods to the matching strategy", async ({ page }) => {
|
|
170
|
-
type LocatorSchemaPaths = "button";
|
|
171
|
-
|
|
172
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
173
|
-
const button = registry.createReusable.getByRole("button", { name: "Submit" });
|
|
174
|
-
const builder = registry.add("button", { reuse: button });
|
|
175
|
-
|
|
176
|
-
// @ts-expect-error mismatched locator strategies are not exposed when reusing a locator
|
|
177
|
-
const _invalidOverrideMethod = builder.getByText;
|
|
178
|
-
|
|
179
|
-
builder.getByRole({ name: "Submit" });
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
test("add reuse allows only one matching locator override", async ({ page }) => {
|
|
183
|
-
type LocatorSchemaPaths = "heading";
|
|
184
|
-
|
|
185
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
186
|
-
const h2 = registry.createReusable.getByRole("heading", { level: 2 });
|
|
187
|
-
|
|
188
|
-
const builder = registry.add("heading", { reuse: h2 });
|
|
189
|
-
|
|
190
|
-
builder.getByRole("heading", { name: "Summary" });
|
|
191
|
-
|
|
192
|
-
expect(() => builder.getByRole("heading", { name: "Other" })).toThrowError("only one matching override is allowed");
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
test("createReusable.filter supports Playwright Locator instances for has/hasNot", async ({ page }) => {
|
|
196
|
-
type LocatorSchemaPaths = "item";
|
|
197
|
-
|
|
198
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
199
|
-
|
|
200
|
-
const seed = registry.createReusable
|
|
201
|
-
.getByRole("button")
|
|
202
|
-
.filter({ has: page.getByRole("heading", { level: 2 }) })
|
|
203
|
-
.filter({ hasNot: page.getByRole("heading", { level: 3 }) });
|
|
204
|
-
|
|
205
|
-
registry.add("item", { reuse: seed });
|
|
206
|
-
|
|
207
|
-
const locator = registry.getLocator("item");
|
|
208
|
-
|
|
209
|
-
expect(`${locator}`).toEqual(
|
|
210
|
-
"getByRole('button').filter({ has: getByRole('heading', { level: 2 }) }).filter({ hasNot: getByRole('heading', { level: 3 }) })",
|
|
211
|
-
);
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
test("createReusable.filter supports registry path strings for has/hasNot", async ({ page }) => {
|
|
215
|
-
type LocatorSchemaPaths = "item" | "heading.primary" | "heading.secondary";
|
|
216
|
-
|
|
217
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
218
|
-
|
|
219
|
-
registry.add("heading.primary").getByRole("heading", { level: 2 });
|
|
220
|
-
registry.add("heading.secondary").getByRole("heading", { level: 3 });
|
|
221
|
-
|
|
222
|
-
const seed = registry.createReusable
|
|
223
|
-
.getByRole("button")
|
|
224
|
-
.filter({ has: "heading.primary" })
|
|
225
|
-
.filter({ hasNot: "heading.secondary" });
|
|
226
|
-
|
|
227
|
-
registry.add("item", { reuse: seed });
|
|
228
|
-
|
|
229
|
-
const locator = registry.getLocator("item");
|
|
230
|
-
|
|
231
|
-
expect(`${locator}`).toEqual(
|
|
232
|
-
"getByRole('button').filter({ has: getByRole('heading', { level: 2 }) }).filter({ hasNot: getByRole('heading', { level: 3 }) })",
|
|
233
|
-
);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
test("createReusable.filter rejects inline locator strategy definitions for has/hasNot", async ({ page }) => {
|
|
237
|
-
type LocatorSchemaPaths = "item";
|
|
238
|
-
|
|
239
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
240
|
-
|
|
241
|
-
registry.createReusable
|
|
242
|
-
.getByRole("button")
|
|
243
|
-
// @ts-expect-error inline locator definitions are no longer supported
|
|
244
|
-
.filter({ has: { type: "locator", selector: "section" } });
|
|
245
|
-
|
|
246
|
-
const unsafeFilter = {
|
|
247
|
-
has: { type: "locator", selector: "section" },
|
|
248
|
-
} as unknown as FilterDefinition<LocatorSchemaPaths, LocatorSchemaPaths>;
|
|
249
|
-
|
|
250
|
-
const unsafeSeed = registry.createReusable.getByRole("button").filter(unsafeFilter);
|
|
251
|
-
|
|
252
|
-
registry.add("item", { reuse: unsafeSeed });
|
|
253
|
-
|
|
254
|
-
expect(() => registry.getLocator("item")).toThrow(/Unsupported filter reference/);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
test("createReusable.filter rejects locator wrappers for has/hasNot", async ({ page }) => {
|
|
258
|
-
type LocatorSchemaPaths = "item";
|
|
259
|
-
|
|
260
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
261
|
-
|
|
262
|
-
registry.createReusable
|
|
263
|
-
.getByRole("button")
|
|
264
|
-
// @ts-expect-error locator wrapper is no longer supported
|
|
265
|
-
.filter({ has: { locator: { type: "locator", selector: "section" } } });
|
|
266
|
-
|
|
267
|
-
const unsafeFilter = {
|
|
268
|
-
has: { locator: { type: "locator", selector: "section" } },
|
|
269
|
-
} as unknown as FilterDefinition<LocatorSchemaPaths, LocatorSchemaPaths>;
|
|
270
|
-
|
|
271
|
-
const unsafeSeed = registry.createReusable.getByRole("button").filter(unsafeFilter);
|
|
272
|
-
|
|
273
|
-
registry.add("item", { reuse: unsafeSeed });
|
|
274
|
-
|
|
275
|
-
expect(() => registry.getLocator("item")).toThrow(/Unsupported filter reference/);
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
test("createReusable.filter rejects locatorPath wrappers for has/hasNot", async ({ page }) => {
|
|
279
|
-
type LocatorSchemaPaths = "item";
|
|
280
|
-
|
|
281
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
282
|
-
|
|
283
|
-
registry.createReusable
|
|
284
|
-
.getByRole("button")
|
|
285
|
-
// @ts-expect-error locatorPath wrapper is no longer supported
|
|
286
|
-
.filter({ has: { locatorPath: "item" } });
|
|
287
|
-
|
|
288
|
-
const unsafeFilter = {
|
|
289
|
-
has: { locatorPath: "item" },
|
|
290
|
-
} as unknown as FilterDefinition<LocatorSchemaPaths, LocatorSchemaPaths>;
|
|
291
|
-
|
|
292
|
-
const unsafeSeed = registry.createReusable.getByRole("button").filter(unsafeFilter);
|
|
293
|
-
|
|
294
|
-
registry.add("item", { reuse: unsafeSeed });
|
|
295
|
-
|
|
296
|
-
expect(() => registry.getLocator("item")).toThrow(/Unsupported filter reference/);
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
test("createReusable.filter supports visible true/false", async ({ page }) => {
|
|
300
|
-
type LocatorSchemaPaths = "item";
|
|
301
|
-
|
|
302
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
303
|
-
|
|
304
|
-
const seed = registry.createReusable.getByRole("button").filter({ visible: true }).filter({ visible: false });
|
|
305
|
-
|
|
306
|
-
registry.add("item", { reuse: seed });
|
|
307
|
-
|
|
308
|
-
const locator = registry.getLocator("item");
|
|
309
|
-
|
|
310
|
-
expect(`${locator}`).toEqual("getByRole('button').filter({ visible: true }).filter({ visible: false })");
|
|
311
|
-
});
|