pomwright 1.5.0 → 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 +36 -0
- package/README.md +5 -5
- package/dist/index.d.mts +91 -989
- package/dist/index.d.ts +91 -989
- package/dist/index.js +627 -1887
- package/dist/index.mjs +633 -1888
- 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 -693
- 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.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 -66
- 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.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 -541
- 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,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,66 +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 clones records so mutations do not leak", async ({ page }) => {
|
|
25
|
-
type LocatorSchemaPaths = "button" | "button.copy";
|
|
26
|
-
|
|
27
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
28
|
-
|
|
29
|
-
registry.add("button").getByRole("button", { name: "Submit" }).filter({ hasText: "Submit" });
|
|
30
|
-
|
|
31
|
-
registry.add("button.copy", { reuse: "button" });
|
|
32
|
-
|
|
33
|
-
expect(registry.get("button.copy")).toEqual({
|
|
34
|
-
definition: { role: "button", options: { name: "Submit" }, type: "role" },
|
|
35
|
-
locatorSchemaPath: "button.copy",
|
|
36
|
-
steps: [{ filter: { hasText: "Submit" }, kind: "filter" }],
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
registry.replace("button.copy", {
|
|
40
|
-
definition: { role: "link", options: { name: "Copy" }, type: "role" },
|
|
41
|
-
locatorSchemaPath: "button.copy",
|
|
42
|
-
steps: [{ filter: { hasText: "Copy" }, kind: "filter" }],
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
expect(registry.get("button.copy")).toEqual({
|
|
46
|
-
definition: { role: "link", options: { name: "Copy" }, type: "role" },
|
|
47
|
-
locatorSchemaPath: "button.copy",
|
|
48
|
-
steps: [{ filter: { hasText: "Copy" }, kind: "filter" }],
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
expect(registry.get("button")).toEqual({
|
|
52
|
-
definition: { role: "button", options: { name: "Submit" }, type: "role" },
|
|
53
|
-
locatorSchemaPath: "button",
|
|
54
|
-
steps: [{ filter: { hasText: "Submit" }, kind: "filter" }],
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("add reuse by path throws when the source path is missing", async ({ page }) => {
|
|
59
|
-
type LocatorSchemaPaths = "button" | "button.copy";
|
|
60
|
-
|
|
61
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
62
|
-
|
|
63
|
-
expect(() => registry.add("button.copy", { reuse: "button" })).toThrowError(
|
|
64
|
-
'No locator schema registered for path "button".',
|
|
65
|
-
);
|
|
66
|
-
});
|
|
@@ -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
|
-
});
|
|
@@ -1,159 +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 regex-driven getBy* registrations to registry", async ({ page }) => {
|
|
8
|
-
type LocatorSchemaPaths =
|
|
9
|
-
| "regex.text"
|
|
10
|
-
| "regex.label"
|
|
11
|
-
| "regex.placeholder"
|
|
12
|
-
| "regex.altText"
|
|
13
|
-
| "regex.title"
|
|
14
|
-
| "regex.reuse.text"
|
|
15
|
-
| "regex.reusePath.text";
|
|
16
|
-
|
|
17
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
18
|
-
|
|
19
|
-
registry.add("regex.text").getByText(/Welcome/i);
|
|
20
|
-
registry.add("regex.label").getByLabel(/Username/i);
|
|
21
|
-
registry.add("regex.placeholder").getByPlaceholder(/Enter your name/i);
|
|
22
|
-
registry.add("regex.altText").getByAltText(/Sample Image/i);
|
|
23
|
-
registry.add("regex.title").getByTitle(/Home Page/i);
|
|
24
|
-
|
|
25
|
-
const reusableText = registry.createReusable.getByText(/Seeded/i);
|
|
26
|
-
registry.add("regex.reuse.text", { reuse: reusableText }).getByText({ exact: true });
|
|
27
|
-
registry.add("regex.reusePath.text", { reuse: "regex.text" });
|
|
28
|
-
|
|
29
|
-
expect(registry.get("regex.text")).toEqual({
|
|
30
|
-
definition: { text: /Welcome/i, type: "text" },
|
|
31
|
-
locatorSchemaPath: "regex.text",
|
|
32
|
-
steps: [],
|
|
33
|
-
});
|
|
34
|
-
expect(registry.get("regex.label")).toEqual({
|
|
35
|
-
definition: { text: /Username/i, type: "label" },
|
|
36
|
-
locatorSchemaPath: "regex.label",
|
|
37
|
-
steps: [],
|
|
38
|
-
});
|
|
39
|
-
expect(registry.get("regex.placeholder")).toEqual({
|
|
40
|
-
definition: { text: /Enter your name/i, type: "placeholder" },
|
|
41
|
-
locatorSchemaPath: "regex.placeholder",
|
|
42
|
-
steps: [],
|
|
43
|
-
});
|
|
44
|
-
expect(registry.get("regex.altText")).toEqual({
|
|
45
|
-
definition: { text: /Sample Image/i, type: "altText" },
|
|
46
|
-
locatorSchemaPath: "regex.altText",
|
|
47
|
-
steps: [],
|
|
48
|
-
});
|
|
49
|
-
expect(registry.get("regex.title")).toEqual({
|
|
50
|
-
definition: { text: /Home Page/i, type: "title" },
|
|
51
|
-
locatorSchemaPath: "regex.title",
|
|
52
|
-
steps: [],
|
|
53
|
-
});
|
|
54
|
-
expect(registry.get("regex.reuse.text")).toEqual({
|
|
55
|
-
definition: { text: /Seeded/i, options: { exact: true }, type: "text" },
|
|
56
|
-
locatorSchemaPath: "regex.reuse.text",
|
|
57
|
-
steps: [],
|
|
58
|
-
});
|
|
59
|
-
expect(registry.get("regex.reusePath.text")).toEqual({
|
|
60
|
-
definition: { text: /Welcome/i, type: "text" },
|
|
61
|
-
locatorSchemaPath: "regex.reusePath.text",
|
|
62
|
-
steps: [],
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test("add prevents multiple locator type definitions", async ({ page }) => {
|
|
67
|
-
type LocatorSchemaPaths = "heading";
|
|
68
|
-
|
|
69
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
70
|
-
|
|
71
|
-
const builder = registry.add("heading").getByRole("heading", { level: 2 });
|
|
72
|
-
|
|
73
|
-
expect((builder as { getByText?: unknown }).getByText).toBeUndefined();
|
|
74
|
-
|
|
75
|
-
builder.filter({ hasText: "Heading" }).nth(0);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test("add typing narrows locator methods after a definition is chosen", async ({ page }) => {
|
|
79
|
-
type LocatorSchemaPaths = "heading";
|
|
80
|
-
|
|
81
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
82
|
-
const postDefinition = registry.add("heading").getByRole("heading", { level: 2 });
|
|
83
|
-
|
|
84
|
-
// @ts-expect-error additional locator methods are not exposed after a definition is set
|
|
85
|
-
const _invalidLocatorMethod = postDefinition.getByText;
|
|
86
|
-
|
|
87
|
-
postDefinition.filter({ hasText: "Heading" }).nth(0);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test("A LocatorSchemaPath can only be added once", async ({ page }) => {
|
|
91
|
-
type LocatorSchemaPaths = "body";
|
|
92
|
-
|
|
93
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
94
|
-
|
|
95
|
-
registry.add("body").locator("body");
|
|
96
|
-
|
|
97
|
-
const errMsg = /A locator schema with the path "body" already exists*/;
|
|
98
|
-
|
|
99
|
-
expect(() => registry.add("body").locator("someone elses body")).toThrowError(errMsg);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test("add getByRole overloads accept optional options and support chained steps", async ({ page }) => {
|
|
103
|
-
type LocalPath = "root" | "root.options" | "root.minimal";
|
|
104
|
-
const registry = new LocatorRegistryInternal<LocalPath>(page);
|
|
105
|
-
|
|
106
|
-
registry.add("root").locator("body");
|
|
107
|
-
|
|
108
|
-
registry.add("root.options").getByRole("button", { name: "opts" }).filter({ hasText: "filtered" }).nth("last");
|
|
109
|
-
registry.add("root.minimal").getByRole("button");
|
|
110
|
-
|
|
111
|
-
expect(registry.get("root.options")).toEqual({
|
|
112
|
-
locatorSchemaPath: "root.options",
|
|
113
|
-
definition: { type: "role", role: "button", options: { name: "opts" } },
|
|
114
|
-
steps: [
|
|
115
|
-
{ kind: "filter", filter: { hasText: "filtered" } },
|
|
116
|
-
{ kind: "index", index: "last" },
|
|
117
|
-
],
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
expect(registry.get("root.minimal")).toEqual({
|
|
121
|
-
locatorSchemaPath: "root.minimal",
|
|
122
|
-
definition: { type: "role", role: "button" },
|
|
123
|
-
steps: [],
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test("add overloads support other strategies with options and chained steps", async ({ page }) => {
|
|
128
|
-
type LocalPath = "root.text" | "root.locator" | "root.frame";
|
|
129
|
-
|
|
130
|
-
const registry = new LocatorRegistryInternal<LocalPath>(page);
|
|
131
|
-
|
|
132
|
-
registry.add("root.text").getByText("needle", { exact: true }).filter({ hasText: "filtered" }).nth(0);
|
|
133
|
-
registry.add("root.locator").locator(".selector", { hasText: "opt" }).filter({ hasText: "filtered" }).nth(0);
|
|
134
|
-
registry.add("root.frame").frameLocator("iframe[name=child]");
|
|
135
|
-
|
|
136
|
-
expect(registry.get("root.text")).toEqual({
|
|
137
|
-
locatorSchemaPath: "root.text",
|
|
138
|
-
definition: { type: "text", text: "needle", options: { exact: true } },
|
|
139
|
-
steps: [
|
|
140
|
-
{ kind: "filter", filter: { hasText: "filtered" } },
|
|
141
|
-
{ kind: "index", index: 0 },
|
|
142
|
-
],
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
expect(registry.get("root.locator")).toEqual({
|
|
146
|
-
locatorSchemaPath: "root.locator",
|
|
147
|
-
definition: { type: "locator", selector: ".selector", options: { hasText: "opt" } },
|
|
148
|
-
steps: [
|
|
149
|
-
{ kind: "filter", filter: { hasText: "filtered" } },
|
|
150
|
-
{ kind: "index", index: 0 },
|
|
151
|
-
],
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
expect(registry.get("root.frame")).toEqual({
|
|
155
|
-
locatorSchemaPath: "root.frame",
|
|
156
|
-
definition: { type: "frameLocator", selector: "iframe[name=child]" },
|
|
157
|
-
steps: [],
|
|
158
|
-
});
|
|
159
|
-
});
|