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,178 +0,0 @@
|
|
|
1
|
-
# Call-Site Migration: v1 -> v2 accessor syntax
|
|
2
|
-
|
|
3
|
-
## getLocator / getNestedLocator (async -> sync)
|
|
4
|
-
|
|
5
|
-
v1 returns `Promise<Locator>`. v2 returns `Locator` synchronously. Remove `await`.
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
// v1
|
|
9
|
-
const btn = await poc.getLocator("navbar.button@login");
|
|
10
|
-
await btn.click();
|
|
11
|
-
|
|
12
|
-
const nested = await poc.getNestedLocator("navbar.button@logout");
|
|
13
|
-
await nested.click();
|
|
14
|
-
|
|
15
|
-
// v2
|
|
16
|
-
await poc.getLocator("navbar.button@login").click();
|
|
17
|
-
await poc.getNestedLocator("navbar.button@logout").click();
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## getNestedLocator with index maps -> getLocatorSchema + nth
|
|
21
|
-
|
|
22
|
-
v1 accepted an optional index map object as second argument. v2 does not; use `getLocatorSchema` with `.nth()` instead.
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
// v1
|
|
26
|
-
const submit = await poc.getNestedLocator("main.form.button@submit", {
|
|
27
|
-
"main.form": 0,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// v2
|
|
31
|
-
const submit = poc
|
|
32
|
-
.getLocatorSchema("main.form.button@submit")
|
|
33
|
-
.nth("main.form", 0)
|
|
34
|
-
.getNestedLocator();
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Multiple indices:
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
// v1
|
|
41
|
-
const item = await poc.getNestedLocator("main.list.item.detail", {
|
|
42
|
-
"main.list": 0,
|
|
43
|
-
"main.list.item": 2,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// v2
|
|
47
|
-
const item = poc
|
|
48
|
-
.getLocatorSchema("main.list.item.detail")
|
|
49
|
-
.nth("main.list", 0)
|
|
50
|
-
.nth("main.list.item", 2)
|
|
51
|
-
.getNestedLocator();
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## addFilter -> filter
|
|
55
|
-
|
|
56
|
-
v1 `addFilter` on `getLocatorSchema()` becomes v2 `filter`. Method name and argument shape changed.
|
|
57
|
-
|
|
58
|
-
```ts
|
|
59
|
-
// v1
|
|
60
|
-
const filtered = await poc
|
|
61
|
-
.getLocatorSchema("main.list.item")
|
|
62
|
-
.addFilter("main.list", { hasText: "list" })
|
|
63
|
-
.addFilter("main.list.item", { hasText: "Row" })
|
|
64
|
-
.getNestedLocator({ "main.list": 0, "main.list.item": -1 });
|
|
65
|
-
|
|
66
|
-
// v2
|
|
67
|
-
const filtered = poc
|
|
68
|
-
.getLocatorSchema("main.list.item")
|
|
69
|
-
.filter("main.list", { hasText: "list" })
|
|
70
|
-
.nth("main.list", 0)
|
|
71
|
-
.filter({ hasText: "Row" }) // omitted subPath defaults to terminal path
|
|
72
|
-
.nth(-1) // omitted subPath defaults to terminal path
|
|
73
|
-
.getNestedLocator();
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
Key difference: v2 `filter` and `nth` can be interleaved in any order. v1 required all filters first, then one index map at the end.
|
|
77
|
-
|
|
78
|
-
## update (schema mutation)
|
|
79
|
-
|
|
80
|
-
v1 `update` accepted a partial schema object. v2 `update` returns a sub-builder where you chain the locator method with override options.
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
// v1
|
|
84
|
-
const patched = await poc
|
|
85
|
-
.getLocatorSchema("main.button@login")
|
|
86
|
-
.update("main.button@login", { roleOptions: { name: "Sign in" } })
|
|
87
|
-
.getNestedLocator();
|
|
88
|
-
|
|
89
|
-
// v2
|
|
90
|
-
const patched = poc
|
|
91
|
-
.getLocatorSchema("main.button@login")
|
|
92
|
-
.update() // defaults to terminal path
|
|
93
|
-
.getByRole({ name: "Sign in" }) // PATCH-style: only override options
|
|
94
|
-
.getNestedLocator();
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
v2 also adds `replace` (full replacement) and `remove` (drop a subpath from chain):
|
|
98
|
-
|
|
99
|
-
```ts
|
|
100
|
-
// replace the entire locator strategy for a subpath
|
|
101
|
-
const replaced = poc
|
|
102
|
-
.getLocatorSchema("main.button@login")
|
|
103
|
-
.replace()
|
|
104
|
-
.getByText("Sign in")
|
|
105
|
-
.getNestedLocator();
|
|
106
|
-
|
|
107
|
-
// remove a segment from the chain
|
|
108
|
-
const removed = poc
|
|
109
|
-
.getLocatorSchema("main.button@login")
|
|
110
|
-
.remove("main")
|
|
111
|
-
.getNestedLocator();
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## getLocatorSchema().getLocator() / .getNestedLocator()
|
|
115
|
-
|
|
116
|
-
v1 terminal resolution was async. v2 is sync.
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
// v1
|
|
120
|
-
const loc = await poc.getLocatorSchema("main.button@login").getLocator();
|
|
121
|
-
const nested = await poc.getLocatorSchema("main.button@login").getNestedLocator();
|
|
122
|
-
|
|
123
|
-
// v2
|
|
124
|
-
const loc = poc.getLocatorSchema("main.button@login").getLocator();
|
|
125
|
-
const nested = poc.getLocatorSchema("main.button@login").getNestedLocator();
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## describe (v2 only, no v1 equivalent)
|
|
129
|
-
|
|
130
|
-
```ts
|
|
131
|
-
const btn = poc
|
|
132
|
-
.getLocatorSchema("main.region@security.button@edit")
|
|
133
|
-
.filter({ hasText: "Change password" })
|
|
134
|
-
.describe("Change password")
|
|
135
|
-
.getNestedLocator();
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## SessionStorage signature changes
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
// v1
|
|
142
|
-
await poc.sessionStorage.set({ token: "abc" }, true); // boolean reload
|
|
143
|
-
await poc.sessionStorage.get(["token"]);
|
|
144
|
-
await poc.sessionStorage.clear();
|
|
145
|
-
|
|
146
|
-
// v2
|
|
147
|
-
await poc.sessionStorage.set({ token: "abc" }, { reload: true });
|
|
148
|
-
await poc.sessionStorage.get(["token"], { waitForContext: true });
|
|
149
|
-
await poc.sessionStorage.clear(); // clears all
|
|
150
|
-
await poc.sessionStorage.clear(["token"]); // clears specific keys
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## Import changes
|
|
154
|
-
|
|
155
|
-
```ts
|
|
156
|
-
// v1
|
|
157
|
-
import { BasePage, GetByMethod } from "pomwright";
|
|
158
|
-
|
|
159
|
-
// v1.5 bridge
|
|
160
|
-
import { BasePageV1toV2, GetByMethod } from "pomwright";
|
|
161
|
-
|
|
162
|
-
// When all schemas moved to defineLocators, remove GetByMethod import.
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
## filter has/hasNot value changes
|
|
166
|
-
|
|
167
|
-
v1 `filter.has`/`filter.hasNot` accepted `Locator` instances. v2 accepts **registry path strings** or `Locator` instances from `getLocator`/`getNestedLocator`.
|
|
168
|
-
|
|
169
|
-
```ts
|
|
170
|
-
// v1 (Locator instance in filter)
|
|
171
|
-
.addFilter("main.card", { has: someLocator })
|
|
172
|
-
|
|
173
|
-
// v2 (path string reference)
|
|
174
|
-
.filter("main.card", { has: "main.card.badge" })
|
|
175
|
-
|
|
176
|
-
// v2 (Locator instance from registry)
|
|
177
|
-
.filter("main.card", { has: poc.getNestedLocator("main.card.badge") })
|
|
178
|
-
```
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
# Schema Translation: v1 addSchema -> v2 add() DSL
|
|
2
|
-
|
|
3
|
-
## GetByMethod mapping
|
|
4
|
-
|
|
5
|
-
| v1 `locatorMethod` | v1 schema field | v1 options field | v2 method | v2 arguments |
|
|
6
|
-
|---|---|---|---|---|
|
|
7
|
-
| `GetByMethod.role` | `role` | `roleOptions` | `getByRole(role, options?)` | role value, roleOptions as second arg |
|
|
8
|
-
| `GetByMethod.text` | `text` | `textOptions` | `getByText(text, options?)` | text value, textOptions as second arg |
|
|
9
|
-
| `GetByMethod.label` | `label` | `labelOptions` | `getByLabel(text, options?)` | label value, labelOptions as second arg |
|
|
10
|
-
| `GetByMethod.placeholder` | `placeholder` | `placeholderOptions` | `getByPlaceholder(text, options?)` | placeholder value, placeholderOptions |
|
|
11
|
-
| `GetByMethod.altText` | `altText` | `altTextOptions` | `getByAltText(text, options?)` | altText value, altTextOptions |
|
|
12
|
-
| `GetByMethod.title` | `title` | `titleOptions` | `getByTitle(text, options?)` | title value, titleOptions |
|
|
13
|
-
| `GetByMethod.locator` | `locator` (string) | `locatorOptions` | `locator(selector, options?)` | locator string, locatorOptions |
|
|
14
|
-
| `GetByMethod.frameLocator` | `frameLocator` | - | `frameLocator(selector)` | frameLocator string |
|
|
15
|
-
| `GetByMethod.testId` | `testId` | - | `getByTestId(testId)` | testId value |
|
|
16
|
-
| `GetByMethod.id` | `id` | - | `getById(id)` | id string or RegExp |
|
|
17
|
-
| `GetByMethod.dataCy` | `dataCy` | - | `locator('[data-cy="value"]')` | CSS attribute selector string |
|
|
18
|
-
|
|
19
|
-
## Translation examples
|
|
20
|
-
|
|
21
|
-
### Role
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
// v1
|
|
25
|
-
this.locators.addSchema("main.button@login", {
|
|
26
|
-
role: "button",
|
|
27
|
-
roleOptions: { name: "Login" },
|
|
28
|
-
locatorMethod: GetByMethod.role,
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// v2
|
|
32
|
-
this.add("main.button@login").getByRole("button", { name: "Login" });
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### Locator (CSS/XPath)
|
|
36
|
-
|
|
37
|
-
```ts
|
|
38
|
-
// v1
|
|
39
|
-
this.locators.addSchema("main", {
|
|
40
|
-
locator: "main",
|
|
41
|
-
locatorMethod: GetByMethod.locator,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// v2
|
|
45
|
-
this.add("main").locator("main");
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Locator with options
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
// v1
|
|
52
|
-
this.locators.addSchema("body.section@playground", {
|
|
53
|
-
locator: "section",
|
|
54
|
-
locatorOptions: { hasText: /Playground/i },
|
|
55
|
-
locatorMethod: GetByMethod.locator,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// v2
|
|
59
|
-
this.add("body.section@playground").locator("section", { hasText: /Playground/i });
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Label
|
|
63
|
-
|
|
64
|
-
```ts
|
|
65
|
-
// v1
|
|
66
|
-
this.locators.addSchema("main.form.input@username", {
|
|
67
|
-
label: "Username",
|
|
68
|
-
locatorMethod: GetByMethod.label,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// v2
|
|
72
|
-
this.add("main.form.input@username").getByLabel("Username");
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### FrameLocator
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
// v1
|
|
79
|
-
this.locators.addSchema("main.frame@login", {
|
|
80
|
-
frameLocator: "#auth",
|
|
81
|
-
locatorMethod: GetByMethod.frameLocator,
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
// v2
|
|
85
|
-
this.add("main.frame@login").frameLocator("#auth");
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
Note: terminal frameLocator paths in v2 resolve to `frameLocator.owner()` (the iframe element), not the frame itself. Non-terminal frames scope into the frame for subsequent segments.
|
|
89
|
-
|
|
90
|
-
### dataCy (removed in v2)
|
|
91
|
-
|
|
92
|
-
```ts
|
|
93
|
-
// v1
|
|
94
|
-
this.locators.addSchema("main.widget", {
|
|
95
|
-
dataCy: "my-widget",
|
|
96
|
-
locatorMethod: GetByMethod.dataCy,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// v2 (translate to CSS attribute selector)
|
|
100
|
-
this.add("main.widget").locator('[data-cy="my-widget"]');
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### getById
|
|
104
|
-
|
|
105
|
-
```ts
|
|
106
|
-
// v1
|
|
107
|
-
this.locators.addSchema("main.modal@close", {
|
|
108
|
-
id: "close-modal",
|
|
109
|
-
locatorMethod: GetByMethod.id,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// v2
|
|
113
|
-
this.add("main.modal@close").getById("close-modal");
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Note: v1 regex IDs use prefix match `*[id^="pattern"]`; v2 regex IDs use substring match `[id*="pattern"]` with CSS escaping. Results may differ for edge cases.
|
|
117
|
-
|
|
118
|
-
## Filter translation
|
|
119
|
-
|
|
120
|
-
v1 `filter` property on schema -> v2 chained `.filter()` call:
|
|
121
|
-
|
|
122
|
-
```ts
|
|
123
|
-
// v1
|
|
124
|
-
this.locators.addSchema("body.section@playground", {
|
|
125
|
-
locator: "section",
|
|
126
|
-
locatorMethod: GetByMethod.locator,
|
|
127
|
-
filter: { hasText: /Playground/i },
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// v2
|
|
131
|
-
this.add("body.section@playground").locator("section").filter({ hasText: /Playground/i });
|
|
132
|
-
|
|
133
|
-
// OR, if the filter only has hasText/hasNotText, use locator options instead:
|
|
134
|
-
this.add("body.section@playground").locator("section", { hasText: /Playground/i });
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
v2 `filter` accepts `has`/`hasNot` as **registry path strings or Playwright Locator instances**. Path strings are often preferred for registry-native references:
|
|
138
|
-
|
|
139
|
-
```ts
|
|
140
|
-
// v2 filter with has/hasNot as path references
|
|
141
|
-
this.add("main.card").locator(".card").filter({
|
|
142
|
-
has: "main.card.badge", // path string, not Locator
|
|
143
|
-
hasText: "Active",
|
|
144
|
-
});
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Reusable locator patterns
|
|
148
|
-
|
|
149
|
-
### v1: LocatorSchemaWithoutPath + spread
|
|
150
|
-
|
|
151
|
-
```ts
|
|
152
|
-
const buttonSchema: LocatorSchemaWithoutPath = {
|
|
153
|
-
role: "button",
|
|
154
|
-
locatorMethod: GetByMethod.role,
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
this.locators.addSchema("main.button@submit", { ...buttonSchema, roleOptions: { name: "Submit" } });
|
|
158
|
-
this.locators.addSchema("main.button@cancel", { ...buttonSchema, roleOptions: { name: "Cancel" } });
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### v2: createReusable or path reuse
|
|
162
|
-
|
|
163
|
-
```ts
|
|
164
|
-
// Option A: createReusable
|
|
165
|
-
const button = this.locatorRegistry.createReusable.getByRole("button");
|
|
166
|
-
this.add("main.button@submit", { reuse: button }).getByRole({ name: "Submit" });
|
|
167
|
-
this.add("main.button@cancel", { reuse: button }).getByRole({ name: "Cancel" });
|
|
168
|
-
|
|
169
|
-
// Option B: reuse by path (exact clone, no override chaining; returns void so no follow-up chain)
|
|
170
|
-
this.add("main.button@submit").getByRole("button", { name: "Submit" });
|
|
171
|
-
this.add("main.button@cancel", { reuse: "main.button@submit" });
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
> Bridge note: when `BasePageV1toV2` translates remaining v1 schemas, any path already registered in `defineLocators()` is skipped (not overwritten). Keep `defineLocators()` as the source of truth and remove stale duplicates from `initLocatorSchemas()`.
|
|
175
|
-
|
|
176
|
-
## Registration with filter + nth at definition time
|
|
177
|
-
|
|
178
|
-
```ts
|
|
179
|
-
// v2 supports chaining filter and nth on add():
|
|
180
|
-
this.add("one.two").locator("div.two").filter({ hasText: "two" }).nth(0);
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
This registers the locator with a filter step and an nth step baked in.
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pomwright-v2-migration
|
|
3
|
-
description: >
|
|
4
|
-
Migrate POMWright page objects to v2 PageObject from either v1 BasePage or the v1.5 bridge
|
|
5
|
-
(BasePageV1toV2). Use when asked to migrate, convert, or upgrade POMWright page objects to v2,
|
|
6
|
-
or when working with PageObject. Covers: changing class inheritance and constructor signature,
|
|
7
|
-
translating addSchema/initLocatorSchemas to defineLocators with v2 DSL, adding
|
|
8
|
-
pageActionsToPerformAfterNavigation, updating call-site syntax (getLocator, getNestedLocator,
|
|
9
|
-
getLocatorSchema), updating filter/index/update/mutation patterns, migrating fixtures, navigation,
|
|
10
|
-
sessionStorage, logging, and adopting the @step decorator.
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
# POMWright v2 Migration (BasePage / BasePageV1toV2 -> PageObject)
|
|
14
|
-
|
|
15
|
-
Migrate page objects to `PageObject` from either v1 `BasePage` or the v1.5 bridge `BasePageV1toV2`.
|
|
16
|
-
This is the final migration target; `PageObject` is the stable v2 API.
|
|
17
|
-
|
|
18
|
-
## Determine source version
|
|
19
|
-
|
|
20
|
-
Before starting, identify which base class the POC currently extends:
|
|
21
|
-
|
|
22
|
-
| Current base class | Source version | Key differences from v2 |
|
|
23
|
-
|---|---|---|
|
|
24
|
-
| `BasePage` | v1 | Constructor requires `testInfo`, `pocName`, `PlaywrightReportLogger`; uses `initLocatorSchemas` with `addSchema`; async locator accessors; `addFilter` + index maps |
|
|
25
|
-
| `BasePageV1toV2` | v1.5 bridge | Same constructor as v1; may have both `initLocatorSchemas` and `defineLocators`; v2 accessors already available but async removed only partially |
|
|
26
|
-
|
|
27
|
-
If the source is v1 `BasePage` and has not yet been migrated through the bridge, this skill handles
|
|
28
|
-
the direct migration. All schema translation and call-site changes still apply.
|
|
29
|
-
|
|
30
|
-
## Workflow
|
|
31
|
-
|
|
32
|
-
1. **Inventory** the target POC file and its consumers (tests, fixtures, helpers that import it).
|
|
33
|
-
2. **Migrate the class declaration and constructor.** See [references/class-migration.md](references/class-migration.md).
|
|
34
|
-
3. **Migrate locator definitions** into `defineLocators()` using the v2 `add()` DSL. See [references/locator-registration.md](references/locator-registration.md).
|
|
35
|
-
4. **Remove `initLocatorSchemas()`** once all schemas are moved to `defineLocators()`.
|
|
36
|
-
5. **Add `pageActionsToPerformAfterNavigation()`** (required abstract method). See [references/class-migration.md](references/class-migration.md).
|
|
37
|
-
6. **Update call-site syntax** in tests, fixtures, and helpers. See [references/call-site-migration.md](references/call-site-migration.md).
|
|
38
|
-
7. **Migrate fixtures and helpers** (navigation, sessionStorage, logging, @step). See [references/fixture-and-helpers.md](references/fixture-and-helpers.md).
|
|
39
|
-
8. **Remove v1 imports** (`GetByMethod`, `BasePage`, `BasePageV1toV2`, `BasePageOptions`, `ExtractUrlPathType`, `ExtractBaseUrlType`, `ExtractFullUrlType`, `GetLocatorBase`, `LocatorSchemaWithoutPath`).
|
|
40
|
-
9. **Verify** by running tests.
|
|
41
|
-
|
|
42
|
-
## Key rules
|
|
43
|
-
|
|
44
|
-
- v2 `PageObject` constructor takes `(page, baseUrl, urlPath, options?)` - no `testInfo`, no `pocName`, no `PlaywrightReportLogger`.
|
|
45
|
-
- `pocName` is replaced by `options.label` (defaults to class name, so often omittable).
|
|
46
|
-
- `testInfo` and `PlaywrightReportLogger` are no longer injected into PageObject. Use the `log` fixture from `pomwright` instead if logging is needed.
|
|
47
|
-
- `defineLocators()` is required; `initLocatorSchemas()` does not exist in v2.
|
|
48
|
-
- `pageActionsToPerformAfterNavigation()` is a required abstract method; return `null` or an array of async callbacks.
|
|
49
|
-
- v2 `getLocator`/`getNestedLocator`/`getLocatorSchema` are **synchronous** (no `await`).
|
|
50
|
-
- v2 `getNestedLocator` does not accept index maps. Use `getLocatorSchema(path).nth(subPath, index).getNestedLocator()` instead.
|
|
51
|
-
- `filter` replaces v1 `addFilter`. `nth` replaces v1 index maps. Both can be chained in any order.
|
|
52
|
-
- v2 `filter.has`/`filter.hasNot` accept **registry path strings** in addition to Locator instances.
|
|
53
|
-
- `navigation` helper is exposed on PageObject: `this.navigation.gotoThisPage()`, `this.navigation.expectThisPage()`, etc.
|
|
54
|
-
- `sessionStorage` API changed: boolean parameters replaced by options objects.
|
|
55
|
-
- `@step` decorator is available for wrapping methods in Playwright test steps.
|
|
56
|
-
- v1 URL type helpers renamed: `ExtractBaseUrlType` -> `BaseUrlTypeFromOptions`, `ExtractUrlPathType` -> `UrlPathTypeFromOptions`, `ExtractFullUrlType` -> `FullUrlTypeFromOptions`. The options shape flattened from `{ urlOptions: { ... } }` to `{ baseUrlType, urlPathType }`.
|
|
57
|
-
|
|
58
|
-
## References
|
|
59
|
-
|
|
60
|
-
- **Class migration**: [references/class-migration.md](references/class-migration.md) - Inheritance, constructor, generics, abstract methods, base class hierarchy
|
|
61
|
-
- **Locator registration**: [references/locator-registration.md](references/locator-registration.md) - defineLocators, add() DSL mapping, reusable locators, filter/nth at registration, frameLocator changes
|
|
62
|
-
- **Call-site migration**: [references/call-site-migration.md](references/call-site-migration.md) - getLocator, getNestedLocator, getLocatorSchema, filter, nth, update, replace, remove, describe
|
|
63
|
-
- **Fixtures and helpers**: [references/fixture-and-helpers.md](references/fixture-and-helpers.md) - Fixture setup, navigation helper, sessionStorage, @step decorator, logging
|
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
# Call-Site Migration: v1 -> v2 accessor syntax
|
|
2
|
-
|
|
3
|
-
## getLocator / getNestedLocator (async -> sync)
|
|
4
|
-
|
|
5
|
-
v1 returns `Promise<Locator>`. v2 returns `Locator` synchronously. Remove `await`.
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
// v1
|
|
9
|
-
const btn = await poc.getLocator("navbar.button@login");
|
|
10
|
-
await btn.click();
|
|
11
|
-
|
|
12
|
-
const nested = await poc.getNestedLocator("navbar.button@logout");
|
|
13
|
-
await nested.click();
|
|
14
|
-
|
|
15
|
-
// v2
|
|
16
|
-
await poc.getLocator("navbar.button@login").click();
|
|
17
|
-
await poc.getNestedLocator("navbar.button@logout").click();
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## getNestedLocator with index maps -> getLocatorSchema + nth
|
|
21
|
-
|
|
22
|
-
v1 accepted an optional index map object as second argument. v2 does not; use `getLocatorSchema` with `.nth()` instead.
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
// v1
|
|
26
|
-
const submit = await poc.getNestedLocator("main.form.button@submit", {
|
|
27
|
-
"main.form": 0,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// v2
|
|
31
|
-
const submit = poc
|
|
32
|
-
.getLocatorSchema("main.form.button@submit")
|
|
33
|
-
.nth("main.form", 0)
|
|
34
|
-
.getNestedLocator();
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Multiple indices:
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
// v1
|
|
41
|
-
const item = await poc.getNestedLocator("main.list.item.detail", {
|
|
42
|
-
"main.list": 0,
|
|
43
|
-
"main.list.item": 2,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// v2
|
|
47
|
-
const item = poc
|
|
48
|
-
.getLocatorSchema("main.list.item.detail")
|
|
49
|
-
.nth("main.list", 0)
|
|
50
|
-
.nth("main.list.item", 2)
|
|
51
|
-
.getNestedLocator();
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
v2 also supports named index positions:
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
const first = poc
|
|
58
|
-
.getLocatorSchema("main.list.item")
|
|
59
|
-
.nth("first") // omitted subPath defaults to terminal path
|
|
60
|
-
.getNestedLocator();
|
|
61
|
-
|
|
62
|
-
const last = poc
|
|
63
|
-
.getLocatorSchema("main.list.item")
|
|
64
|
-
.nth("last")
|
|
65
|
-
.getNestedLocator();
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## addFilter -> filter
|
|
69
|
-
|
|
70
|
-
v1 `addFilter` on `getLocatorSchema()` becomes v2 `filter`. Method name and argument shape changed.
|
|
71
|
-
|
|
72
|
-
```ts
|
|
73
|
-
// v1
|
|
74
|
-
const filtered = await poc
|
|
75
|
-
.getLocatorSchema("main.list.item")
|
|
76
|
-
.addFilter("main.list", { hasText: "list" })
|
|
77
|
-
.addFilter("main.list.item", { hasText: "Row" })
|
|
78
|
-
.getNestedLocator({ "main.list": 0, "main.list.item": -1 });
|
|
79
|
-
|
|
80
|
-
// v2
|
|
81
|
-
const filtered = poc
|
|
82
|
-
.getLocatorSchema("main.list.item")
|
|
83
|
-
.filter("main.list", { hasText: "list" })
|
|
84
|
-
.nth("main.list", 0)
|
|
85
|
-
.filter({ hasText: "Row" }) // omitted subPath defaults to terminal path
|
|
86
|
-
.nth(-1) // omitted subPath defaults to terminal path
|
|
87
|
-
.getNestedLocator();
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Key differences:
|
|
91
|
-
- `addFilter` renamed to `filter`
|
|
92
|
-
- v2 `filter` and `nth` can be interleaved in any order
|
|
93
|
-
- v1 required all filters first, then one index map at the end
|
|
94
|
-
- Omitting `subPath` on `filter`/`nth` defaults to the terminal path (the path supplied to `getLocatorSchema`)
|
|
95
|
-
|
|
96
|
-
## clearSteps
|
|
97
|
-
|
|
98
|
-
v2 adds `clearSteps()` to remove all runtime steps (filter + nth) from a query builder:
|
|
99
|
-
|
|
100
|
-
```ts
|
|
101
|
-
const schema = poc.getLocatorSchema("main.list.item")
|
|
102
|
-
.filter({ hasText: "Active" })
|
|
103
|
-
.nth(0);
|
|
104
|
-
|
|
105
|
-
// Clear all steps and start fresh
|
|
106
|
-
const reset = schema.clearSteps().filter({ hasText: "Inactive" }).getNestedLocator();
|
|
107
|
-
|
|
108
|
-
// Clear steps for a specific subPath only
|
|
109
|
-
const partial = schema.clearSteps("main.list").getNestedLocator();
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## update (schema mutation)
|
|
113
|
-
|
|
114
|
-
v1 `update` accepted a partial schema object. v2 `update` returns a sub-builder where you chain the locator method with override options (PATCH-style merge).
|
|
115
|
-
|
|
116
|
-
```ts
|
|
117
|
-
// v1
|
|
118
|
-
const patched = await poc
|
|
119
|
-
.getLocatorSchema("main.button@login")
|
|
120
|
-
.update("main.button@login", { roleOptions: { name: "Sign in" } })
|
|
121
|
-
.getNestedLocator();
|
|
122
|
-
|
|
123
|
-
// v2
|
|
124
|
-
const patched = poc
|
|
125
|
-
.getLocatorSchema("main.button@login")
|
|
126
|
-
.update() // defaults to terminal path
|
|
127
|
-
.getByRole({ name: "Sign in" }) // PATCH-style: only override options
|
|
128
|
-
.getNestedLocator();
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
With explicit subPath:
|
|
132
|
-
|
|
133
|
-
```ts
|
|
134
|
-
// v2
|
|
135
|
-
const patched = poc
|
|
136
|
-
.getLocatorSchema("main.form.button@login")
|
|
137
|
-
.update("main.form")
|
|
138
|
-
.locator(".login-form-v2") // override selector for the form segment
|
|
139
|
-
.getNestedLocator();
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
## replace (full replacement)
|
|
143
|
-
|
|
144
|
-
v2 adds `replace` for POST-style full replacement of a locator strategy:
|
|
145
|
-
|
|
146
|
-
```ts
|
|
147
|
-
// v2 only
|
|
148
|
-
const replaced = poc
|
|
149
|
-
.getLocatorSchema("main.button@login")
|
|
150
|
-
.replace()
|
|
151
|
-
.getByText("Sign in") // entirely replaces the role strategy with text
|
|
152
|
-
.getNestedLocator();
|
|
153
|
-
|
|
154
|
-
// With subPath
|
|
155
|
-
const replaced = poc
|
|
156
|
-
.getLocatorSchema("main.form.button@login")
|
|
157
|
-
.replace("main.form")
|
|
158
|
-
.getByRole("region", { name: "Login" })
|
|
159
|
-
.getNestedLocator();
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
## remove (drop segment from chain)
|
|
163
|
-
|
|
164
|
-
v2 adds `remove` to soft-delete a segment from the locator chain:
|
|
165
|
-
|
|
166
|
-
```ts
|
|
167
|
-
// v2 only
|
|
168
|
-
const removed = poc
|
|
169
|
-
.getLocatorSchema("main.form.button@login")
|
|
170
|
-
.remove("main") // skips "main" when building the chain
|
|
171
|
-
.getNestedLocator();
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
Without subPath, `remove()` targets the terminal segment. Resolving immediately will throw unless the terminal definition is replaced/updated before resolve:
|
|
175
|
-
|
|
176
|
-
```ts
|
|
177
|
-
// Throws: terminal path was removed
|
|
178
|
-
expect(() =>
|
|
179
|
-
poc.getLocatorSchema("main.form.button@login").remove().getNestedLocator()
|
|
180
|
-
).toThrow(/No locator schema registered/);
|
|
181
|
-
|
|
182
|
-
// Repair terminal path before resolve
|
|
183
|
-
const repaired = poc
|
|
184
|
-
.getLocatorSchema("main.form.button@login")
|
|
185
|
-
.remove()
|
|
186
|
-
.replace("main.form.button@login")
|
|
187
|
-
.getByRole("button", { name: "Sign in" })
|
|
188
|
-
.getNestedLocator();
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
## getLocatorSchema().getLocator() / .getNestedLocator()
|
|
192
|
-
|
|
193
|
-
v1 terminal resolution was async. v2 is sync.
|
|
194
|
-
|
|
195
|
-
```ts
|
|
196
|
-
// v1
|
|
197
|
-
const loc = await poc.getLocatorSchema("main.button@login").getLocator();
|
|
198
|
-
const nested = await poc.getLocatorSchema("main.button@login").getNestedLocator();
|
|
199
|
-
|
|
200
|
-
// v2
|
|
201
|
-
const loc = poc.getLocatorSchema("main.button@login").getLocator();
|
|
202
|
-
const nested = poc.getLocatorSchema("main.button@login").getNestedLocator();
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
## describe (v2 only, no v1 equivalent)
|
|
206
|
-
|
|
207
|
-
Adds a descriptive label to the locator at runtime:
|
|
208
|
-
|
|
209
|
-
```ts
|
|
210
|
-
const btn = poc
|
|
211
|
-
.getLocatorSchema("main.region@security.button@edit")
|
|
212
|
-
.filter({ hasText: "Change password" })
|
|
213
|
-
.describe("Change password")
|
|
214
|
-
.getNestedLocator();
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## filter has/hasNot value changes
|
|
218
|
-
|
|
219
|
-
v1 `filter.has`/`filter.hasNot` accepted `Locator` instances. v2 accepts **registry path strings** or `Locator` instances from `getLocator`/`getNestedLocator`.
|
|
220
|
-
|
|
221
|
-
```ts
|
|
222
|
-
// v1 (Locator instance in filter)
|
|
223
|
-
.addFilter("main.card", { has: someLocator })
|
|
224
|
-
|
|
225
|
-
// v2 (path string reference - preferred)
|
|
226
|
-
.filter("main.card", { has: "main.card.badge" })
|
|
227
|
-
|
|
228
|
-
// v2 (Locator instance from registry - also valid)
|
|
229
|
-
.filter("main.card", { has: poc.getNestedLocator("main.card.badge") })
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## SessionStorage signature changes
|
|
233
|
-
|
|
234
|
-
```ts
|
|
235
|
-
// v1
|
|
236
|
-
await poc.sessionStorage.set({ token: "abc" }, true); // boolean reload
|
|
237
|
-
await poc.sessionStorage.get(["token"]);
|
|
238
|
-
await poc.sessionStorage.clear();
|
|
239
|
-
|
|
240
|
-
// v2
|
|
241
|
-
await poc.sessionStorage.set({ token: "abc" }, { reload: true });
|
|
242
|
-
await poc.sessionStorage.get(["token"], { waitForContext: true });
|
|
243
|
-
await poc.sessionStorage.clear(); // clears all
|
|
244
|
-
await poc.sessionStorage.clear("token"); // clears specific key
|
|
245
|
-
await poc.sessionStorage.clear(["token", "theme"]); // clears specific keys
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
Key changes:
|
|
249
|
-
- Boolean `reload` parameter -> `{ reload: true }` options object
|
|
250
|
-
- New `{ waitForContext: true }` option on `get` and `clear` for handling navigation boundaries
|
|
251
|
-
- `clear` now supports clearing specific keys (string or string array)
|
|
252
|
-
|
|
253
|
-
## Import changes
|
|
254
|
-
|
|
255
|
-
```ts
|
|
256
|
-
// v1
|
|
257
|
-
import { BasePage, GetByMethod } from "pomwright";
|
|
258
|
-
|
|
259
|
-
// v1.5 bridge
|
|
260
|
-
import { BasePageV1toV2, GetByMethod } from "pomwright";
|
|
261
|
-
|
|
262
|
-
// v2
|
|
263
|
-
import { PageObject } from "pomwright";
|
|
264
|
-
// GetByMethod is no longer needed - remove the import
|
|
265
|
-
```
|