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,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
|
-
});
|
|
@@ -1,39 +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("filter cycle detection throws on direct self-reference", async ({ page }) => {
|
|
8
|
-
type LocatorSchemaPaths = "main.h1";
|
|
9
|
-
|
|
10
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
11
|
-
|
|
12
|
-
registry.add("main.h1").getByRole("heading", { level: 1 }).filter({ has: "main.h1" });
|
|
13
|
-
|
|
14
|
-
expect(() => registry.getLocator("main.h1")).toThrow(/resolving "main\.h1": "main\.h1"/);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test("filter cycle detection throws on indirect reference loops", async ({ page }) => {
|
|
18
|
-
type LocatorSchemaPaths = "a" | "b";
|
|
19
|
-
|
|
20
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
21
|
-
|
|
22
|
-
registry.add("a").getByRole("button").filter({ has: "b" });
|
|
23
|
-
registry.add("b").getByRole("button").filter({ has: "a" });
|
|
24
|
-
|
|
25
|
-
expect(() => registry.getLocator("a")).toThrow(/resolving "a": "b"/);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test("filter cycle detection allows repeated non-cyclic references", async ({ page }) => {
|
|
29
|
-
type LocatorSchemaPaths = "a" | "a.b" | "shared.heading";
|
|
30
|
-
|
|
31
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
32
|
-
|
|
33
|
-
registry.add("shared.heading").getByRole("heading", { level: 2 });
|
|
34
|
-
registry.add("a").getByRole("button").filter({ has: "shared.heading" });
|
|
35
|
-
registry.add("a.b").getByRole("button").filter({ has: "shared.heading" });
|
|
36
|
-
|
|
37
|
-
expect(() => registry.getLocator("a")).not.toThrow();
|
|
38
|
-
expect(() => registry.getLocator("a.b")).not.toThrow();
|
|
39
|
-
});
|
|
@@ -1,253 +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("getLocator resolves the terminal locator when ancestor paths are registered", async ({ page }) => {
|
|
8
|
-
type LocatorSchemaPaths =
|
|
9
|
-
| "topMenu"
|
|
10
|
-
| "topMenu.notifications"
|
|
11
|
-
| "topMenu.notifications.dropdown"
|
|
12
|
-
| "topMenu.notifications.dropdown.item";
|
|
13
|
-
|
|
14
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
15
|
-
|
|
16
|
-
registry.add("topMenu").locator(".w3-top");
|
|
17
|
-
registry.add("topMenu.notifications").locator(".w3-dropdown-hover");
|
|
18
|
-
registry.add("topMenu.notifications.dropdown").locator(".w3-dropdown-content");
|
|
19
|
-
registry.add("topMenu.notifications.dropdown.item").locator(".w3-bar-item");
|
|
20
|
-
|
|
21
|
-
const locator = registry.getLocator("topMenu.notifications.dropdown.item");
|
|
22
|
-
const chained = page
|
|
23
|
-
.locator(".w3-top")
|
|
24
|
-
.locator(".w3-dropdown-hover")
|
|
25
|
-
.locator(".w3-dropdown-content")
|
|
26
|
-
.locator(".w3-bar-item");
|
|
27
|
-
|
|
28
|
-
expect(`${locator}`).toEqual("locator('.w3-bar-item')");
|
|
29
|
-
expect(`${locator}`).not.toEqual(`${chained}`);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("getLocator uses terminal steps while ignoring ancestor filters", async ({ page }) => {
|
|
33
|
-
type LocatorSchemaPaths = "panel" | "panel.row" | "panel.row.button";
|
|
34
|
-
|
|
35
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
36
|
-
|
|
37
|
-
registry.add("panel").locator("section.panel").filter({ hasText: "panel" }).nth(2);
|
|
38
|
-
registry.add("panel.row").locator("div.row").filter({ hasText: "row" });
|
|
39
|
-
registry.add("panel.row.button").getByRole("button", { name: "Save" }).filter({ hasText: "terminal" });
|
|
40
|
-
|
|
41
|
-
const locator = registry.getLocator("panel.row.button");
|
|
42
|
-
|
|
43
|
-
expect(`${locator}`).toEqual("getByRole('button', { name: 'Save' }).filter({ hasText: 'terminal' })");
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test("getLocator returns a fresh locator each time", async ({ page }) => {
|
|
47
|
-
type LocatorSchemaPaths = "button";
|
|
48
|
-
|
|
49
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
50
|
-
|
|
51
|
-
registry.add("button").getByRole("button", { name: "Submit" });
|
|
52
|
-
|
|
53
|
-
const first = registry.getLocator("button");
|
|
54
|
-
const second = registry.getLocator("button");
|
|
55
|
-
|
|
56
|
-
expect(first).not.toBe(second);
|
|
57
|
-
expect(`${first}`).toEqual(`${second}`);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test.describe("getLocator applies terminal filters for registered definitions", () => {
|
|
61
|
-
const cases = [
|
|
62
|
-
{
|
|
63
|
-
label: "role",
|
|
64
|
-
build: (registry: LocatorRegistryInternal<"terminal">) =>
|
|
65
|
-
registry.add("terminal").getByRole("button").filter({ hasText: "filtered" }),
|
|
66
|
-
expected: "getByRole('button').filter({ hasText: 'filtered' })",
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
label: "text",
|
|
70
|
-
build: (registry: LocatorRegistryInternal<"terminal">) =>
|
|
71
|
-
registry.add("terminal").getByText("text").filter({ hasText: "filtered" }),
|
|
72
|
-
expected: "getByText('text').filter({ hasText: 'filtered' })",
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
label: "label",
|
|
76
|
-
build: (registry: LocatorRegistryInternal<"terminal">) =>
|
|
77
|
-
registry.add("terminal").getByLabel("label").filter({ hasText: "filtered" }),
|
|
78
|
-
expected: "getByLabel('label').filter({ hasText: 'filtered' })",
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
label: "placeholder",
|
|
82
|
-
build: (registry: LocatorRegistryInternal<"terminal">) =>
|
|
83
|
-
registry.add("terminal").getByPlaceholder("placeholder").filter({ hasText: "filtered" }),
|
|
84
|
-
expected: "getByPlaceholder('placeholder').filter({ hasText: 'filtered' })",
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
label: "altText",
|
|
88
|
-
build: (registry: LocatorRegistryInternal<"terminal">) =>
|
|
89
|
-
registry.add("terminal").getByAltText("altText").filter({ hasText: "filtered" }),
|
|
90
|
-
expected: "getByAltText('altText').filter({ hasText: 'filtered' })",
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
label: "title",
|
|
94
|
-
build: (registry: LocatorRegistryInternal<"terminal">) =>
|
|
95
|
-
registry.add("terminal").getByTitle("title").filter({ hasText: "filtered" }),
|
|
96
|
-
expected: "getByTitle('title').filter({ hasText: 'filtered' })",
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
label: "locator",
|
|
100
|
-
build: (registry: LocatorRegistryInternal<"terminal">) =>
|
|
101
|
-
registry.add("terminal").locator("locator").filter({ hasText: "filtered" }),
|
|
102
|
-
expected: "locator('locator').filter({ hasText: 'filtered' })",
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
label: "testId",
|
|
106
|
-
build: (registry: LocatorRegistryInternal<"terminal">) =>
|
|
107
|
-
registry.add("terminal").getByTestId("testId").filter({ hasText: "filtered" }),
|
|
108
|
-
expected: "getByTestId('testId').filter({ hasText: 'filtered' })",
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
label: "id",
|
|
112
|
-
build: (registry: LocatorRegistryInternal<"terminal">) =>
|
|
113
|
-
registry.add("terminal").getById("unique-id").filter({ hasText: "filtered" }),
|
|
114
|
-
expected: "locator('#unique-id').filter({ hasText: 'filtered' })",
|
|
115
|
-
},
|
|
116
|
-
];
|
|
117
|
-
|
|
118
|
-
for (const { label, build, expected } of cases) {
|
|
119
|
-
test(`definition ${label}: applies terminal filters`, async ({ page }) => {
|
|
120
|
-
const registry = createTestRegistry<"terminal">(page);
|
|
121
|
-
|
|
122
|
-
build(registry);
|
|
123
|
-
|
|
124
|
-
const locator = registry.getLocator("terminal");
|
|
125
|
-
expect(`${locator}`).toEqual(expected);
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test("getLocator returns frame locators without chaining ancestor filters", async ({ page }) => {
|
|
131
|
-
type LocatorSchemaPaths = "frame";
|
|
132
|
-
|
|
133
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
134
|
-
|
|
135
|
-
registry.add("frame").frameLocator('iframe[title="name"]');
|
|
136
|
-
|
|
137
|
-
const locator = registry.getLocator("frame");
|
|
138
|
-
const manual = page.frameLocator('iframe[title="name"]').owner();
|
|
139
|
-
|
|
140
|
-
expect(`${locator}`).toEqual(`${manual}`);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
test("getLocator ignores filter options when all values are undefined", async ({ page }) => {
|
|
144
|
-
type LocatorSchemaPaths = "fictional.filter@optionsUndefined";
|
|
145
|
-
|
|
146
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
147
|
-
|
|
148
|
-
registry
|
|
149
|
-
.add("fictional.filter@optionsUndefined")
|
|
150
|
-
.getByRole("button")
|
|
151
|
-
.filter({ has: undefined, hasNot: undefined, hasText: undefined, hasNotText: undefined });
|
|
152
|
-
|
|
153
|
-
const locator = registry.getLocator("fictional.filter@optionsUndefined");
|
|
154
|
-
|
|
155
|
-
expect(`${locator}`).toEqual("getByRole('button')");
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
test("getLocator applies terminal indices", async ({ page }) => {
|
|
159
|
-
type LocatorSchemaPaths =
|
|
160
|
-
| "fictional.filter@hasNotText"
|
|
161
|
-
| "fictional.filter@hasNotText.filter@hasText"
|
|
162
|
-
| "fictional.filter@hasNotText.filter@hasText.filter@hasNotText"
|
|
163
|
-
| "fictional.filter@hasNotText.filter@hasText.filter@hasNotText.filter@hasText";
|
|
164
|
-
|
|
165
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
166
|
-
|
|
167
|
-
registry.add("fictional.filter@hasNotText").getByRole("button").filter({ hasNotText: "hasNotText" }).nth(2);
|
|
168
|
-
registry.add("fictional.filter@hasNotText.filter@hasText").getByRole("button").filter({ hasText: "hasText" });
|
|
169
|
-
registry
|
|
170
|
-
.add("fictional.filter@hasNotText.filter@hasText.filter@hasNotText")
|
|
171
|
-
.getByRole("button")
|
|
172
|
-
.filter({ hasNotText: "hasNotText" });
|
|
173
|
-
registry
|
|
174
|
-
.add("fictional.filter@hasNotText.filter@hasText.filter@hasNotText.filter@hasText")
|
|
175
|
-
.getByRole("button")
|
|
176
|
-
.filter({ hasText: "hasText" })
|
|
177
|
-
.nth(2);
|
|
178
|
-
|
|
179
|
-
const locator = registry.getLocator("fictional.filter@hasNotText.filter@hasText.filter@hasNotText.filter@hasText");
|
|
180
|
-
|
|
181
|
-
expect(`${locator}`).toEqual("getByRole('button').filter({ hasText: 'hasText' }).nth(2)");
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
test("getLocator honors terminal filter and index ordering", async ({ page }) => {
|
|
185
|
-
type LocatorSchemaPaths = "fictional.filter@hasText";
|
|
186
|
-
|
|
187
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
188
|
-
|
|
189
|
-
registry
|
|
190
|
-
.add("fictional.filter@hasText")
|
|
191
|
-
.getByRole("button")
|
|
192
|
-
.filter({ hasText: "hasText" })
|
|
193
|
-
.filter({ hasText: "extra" })
|
|
194
|
-
.nth(1)
|
|
195
|
-
.filter({ hasNotText: "tail" });
|
|
196
|
-
|
|
197
|
-
const locator = registry.getLocator("fictional.filter@hasText");
|
|
198
|
-
|
|
199
|
-
expect(`${locator}`).toEqual(
|
|
200
|
-
"getByRole('button').filter({ hasText: 'hasText' }).filter({ hasText: 'extra' }).nth(1).filter({ hasNotText: 'tail' })",
|
|
201
|
-
);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
test("getLocator supports explicit last() selection for the terminal path", async ({ page }) => {
|
|
205
|
-
type LocatorSchemaPaths = "fictional.filter@hasText";
|
|
206
|
-
|
|
207
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
208
|
-
|
|
209
|
-
registry.add("fictional.filter@hasText").getByRole("button").filter({ hasText: "hasText" }).nth("last");
|
|
210
|
-
|
|
211
|
-
const locator = registry.getLocator("fictional.filter@hasText");
|
|
212
|
-
|
|
213
|
-
expect(`${locator}`).toEqual("getByRole('button').filter({ hasText: 'hasText' }).last()");
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
test('getLocator accepts "first" and "last" selections for terminal indices', async ({ page }) => {
|
|
217
|
-
type LocatorSchemaPaths = "fictional.filter@hasText";
|
|
218
|
-
|
|
219
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
220
|
-
registry.add("fictional.filter@hasText").getByRole("button").filter({ hasText: "hasText" }).nth("first");
|
|
221
|
-
|
|
222
|
-
const first = registry.getLocator("fictional.filter@hasText");
|
|
223
|
-
expect(`${first}`).toContain("first()");
|
|
224
|
-
|
|
225
|
-
const secondRegistry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
226
|
-
secondRegistry.add("fictional.filter@hasText").getByRole("button").filter({ hasText: "hasText" }).nth("last");
|
|
227
|
-
|
|
228
|
-
const last = secondRegistry.getLocator("fictional.filter@hasText");
|
|
229
|
-
expect(`${last}`).toContain("last()");
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
test("getLocator rejects missing terminal paths", async ({ page }) => {
|
|
233
|
-
type LocatorSchemaPaths = "fictional.filter@hasText";
|
|
234
|
-
|
|
235
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
236
|
-
registry.add("fictional.filter@hasText").getByRole("button");
|
|
237
|
-
|
|
238
|
-
// @ts-expect-error Testing invalid argument
|
|
239
|
-
expect(() => registry.getLocator("fictional")).toThrow('No locator schema registered for path "fictional".');
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
test("getLocator rejects partially matching paths", async ({ page }) => {
|
|
243
|
-
type LocatorSchemaPaths = "fictional.filter@hasNotText.filter@hasText.filter@hasNotText.filter@hasText";
|
|
244
|
-
|
|
245
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
246
|
-
|
|
247
|
-
registry.add("fictional.filter@hasNotText.filter@hasText.filter@hasNotText.filter@hasText").getByRole("button");
|
|
248
|
-
|
|
249
|
-
// @ts-expect-error Testing invalid argument
|
|
250
|
-
expect(() => registry.getLocator("fictional.filter@has")).toThrow(
|
|
251
|
-
'No locator schema registered for path "fictional.filter@has".',
|
|
252
|
-
);
|
|
253
|
-
});
|
package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.clearSteps.spec.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
|
|
3
|
-
const terminalPath = "body.section.button" as const;
|
|
4
|
-
|
|
5
|
-
test("clearSteps clears existing filters for a sub-path", async ({ testFilters }) => {
|
|
6
|
-
const schema = testFilters.getLocatorSchema("fictional.filter@hasText");
|
|
7
|
-
|
|
8
|
-
const original = schema.getNestedLocator();
|
|
9
|
-
expect(`${original}`).toEqual("getByRole('button').filter({ hasText: 'hasText' })");
|
|
10
|
-
|
|
11
|
-
const noFilters = schema.clearSteps("fictional.filter@hasText").getNestedLocator();
|
|
12
|
-
expect(`${noFilters}`).toEqual("getByRole('button')");
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test("clearSteps allows re-adding filters after clearing filters added through filter", async ({ testFilters }) => {
|
|
16
|
-
const original = testFilters.getNestedLocator("fictional.filter@hasText");
|
|
17
|
-
expect(`${original}`).toEqual("getByRole('button').filter({ hasText: 'hasText' })");
|
|
18
|
-
|
|
19
|
-
const locator = testFilters
|
|
20
|
-
.getLocatorSchema("fictional.filter@hasText")
|
|
21
|
-
.filter("fictional.filter@hasText", { hasText: "this filter will be removed" })
|
|
22
|
-
.clearSteps("fictional.filter@hasText")
|
|
23
|
-
.filter("fictional.filter@hasText", { hasText: /Re-added/i })
|
|
24
|
-
.getNestedLocator();
|
|
25
|
-
|
|
26
|
-
expect(`${locator}`).toEqual("getByRole('button').filter({ hasText: /Re-added/i })");
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test("clearSteps does not remove filters defined via locator options", async ({ testFilters }) => {
|
|
30
|
-
const locator = testFilters
|
|
31
|
-
.getLocatorSchema("body.section@playground")
|
|
32
|
-
.clearSteps("body.section@playground")
|
|
33
|
-
.getNestedLocator();
|
|
34
|
-
|
|
35
|
-
expect(`${locator}`).toEqual("locator('body').locator('section').filter({ hasText: /Playground/i })");
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test("filter resolves path string and locator references after clearing steps", async ({ testFilters }) => {
|
|
39
|
-
const locator = testFilters
|
|
40
|
-
.getLocatorSchema("fictional.filter@hasNotText")
|
|
41
|
-
.clearSteps("fictional.filter@hasNotText")
|
|
42
|
-
.filter("fictional.filter@hasNotText", { has: "body.section.heading" })
|
|
43
|
-
.filter("fictional.filter@hasNotText", { hasNot: testFilters.page.locator(".missing") })
|
|
44
|
-
.getNestedLocator();
|
|
45
|
-
|
|
46
|
-
expect(`${locator}`).toEqual(
|
|
47
|
-
"getByRole('button').filter({ has: getByRole('heading', { level: 2 }) }).filter({ hasNot: locator('.missing') })",
|
|
48
|
-
);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test("nth defaults to the terminal path when subPath is omitted", async ({ testFilters }) => {
|
|
52
|
-
const explicit = testFilters.getLocatorSchema(terminalPath).nth(terminalPath, 0).getNestedLocator();
|
|
53
|
-
const implicit = testFilters.getLocatorSchema(terminalPath).nth(0).getNestedLocator();
|
|
54
|
-
|
|
55
|
-
expect(`${explicit}`).toEqual("locator('body').locator('section').getByRole('button').first()");
|
|
56
|
-
expect(`${implicit}`).toEqual(`${explicit}`);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test("filter defaults to the terminal path when subPath is omitted", async ({ testFilters }) => {
|
|
60
|
-
const explicit = testFilters
|
|
61
|
-
.getLocatorSchema(terminalPath)
|
|
62
|
-
.filter(terminalPath, { hasText: /click/i })
|
|
63
|
-
.getNestedLocator();
|
|
64
|
-
const implicit = testFilters.getLocatorSchema(terminalPath).filter({ hasText: /click/i }).getNestedLocator();
|
|
65
|
-
|
|
66
|
-
expect(`${explicit}`).toEqual("locator('body').locator('section').getByRole('button').filter({ hasText: /click/i })");
|
|
67
|
-
expect(`${implicit}`).toEqual(`${explicit}`);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("clearSteps defaults to the terminal path when subPath is omitted", async ({ testFilters }) => {
|
|
71
|
-
const locator = testFilters
|
|
72
|
-
.getLocatorSchema(terminalPath)
|
|
73
|
-
.filter({ hasText: /click/i })
|
|
74
|
-
.nth(1)
|
|
75
|
-
.clearSteps()
|
|
76
|
-
.getNestedLocator();
|
|
77
|
-
|
|
78
|
-
expect(`${locator}`).toEqual("locator('body').locator('section').getByRole('button')");
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test("update defaults to the terminal path when subPath is omitted", async ({ testFilters }) => {
|
|
82
|
-
const updated = testFilters.getLocatorSchema(terminalPath).update().getByRole({ name: "Reset Color" }).getLocator();
|
|
83
|
-
|
|
84
|
-
expect(`${updated}`).toEqual("getByRole('button', { name: 'Reset Color' })");
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("replace defaults to the terminal path when subPath is omitted", async ({ testFilters }) => {
|
|
88
|
-
const locator = testFilters
|
|
89
|
-
.getLocatorSchema(terminalPath)
|
|
90
|
-
.replace()
|
|
91
|
-
.locator("button.replace", { hasText: /Replace/ })
|
|
92
|
-
.getNestedLocator();
|
|
93
|
-
|
|
94
|
-
expect(`${locator}`).toEqual(
|
|
95
|
-
"locator('body').locator('section').locator('button.replace').filter({ hasText: /Replace/ })",
|
|
96
|
-
);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test("remove defaults to the terminal path when subPath is omitted", async ({ testFilters }) => {
|
|
100
|
-
const builder = testFilters.getLocatorSchema(terminalPath).remove();
|
|
101
|
-
|
|
102
|
-
await expect(async () => builder.getNestedLocator()).rejects.toThrow(
|
|
103
|
-
'No locator schema registered for path "body.section.button".',
|
|
104
|
-
);
|
|
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
|
-
test("describe on locator schema builder overrides the resolved description only", async ({ page }) => {
|
|
8
|
-
type LocatorSchemaPaths = "panel";
|
|
9
|
-
|
|
10
|
-
const registry = createTestRegistry<LocatorSchemaPaths>(page);
|
|
11
|
-
|
|
12
|
-
registry.add("panel").locator("section.panel").describe("Original panel");
|
|
13
|
-
|
|
14
|
-
const locator = registry.getLocatorSchema("panel").describe("Override panel").getLocator();
|
|
15
|
-
|
|
16
|
-
expect(locator.description()).toEqual("Override panel");
|
|
17
|
-
expect(registry.get("panel")).toEqual({
|
|
18
|
-
description: "Original panel",
|
|
19
|
-
definition: { selector: "section.panel", type: "locator" },
|
|
20
|
-
locatorSchemaPath: "panel",
|
|
21
|
-
steps: [],
|
|
22
|
-
});
|
|
23
|
-
});
|