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.
Files changed (117) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +5 -5
  3. package/dist/index.d.mts +91 -989
  4. package/dist/index.d.ts +91 -989
  5. package/dist/index.js +627 -1887
  6. package/dist/index.mjs +633 -1888
  7. package/package.json +9 -11
  8. package/AGENTS.md +0 -37
  9. package/docs/v1/BaseApi-explanation.md +0 -63
  10. package/docs/v1/BasePage-explanation.md +0 -96
  11. package/docs/v1/LocatorSchema-explanation.md +0 -271
  12. package/docs/v1/LocatorSchemaPath-explanation.md +0 -165
  13. package/docs/v1/PlaywrightReportLogger-explanation.md +0 -56
  14. package/docs/v1/get-locator-methods-explanation.md +0 -250
  15. package/docs/v1/intro-to-using-pomwright.md +0 -899
  16. package/docs/v1/sessionStorage-methods-explanation.md +0 -38
  17. package/docs/v1/tips-folder-structure.md +0 -38
  18. package/docs/v1-to-v2-migration/bridge-migration-guide.md +0 -159
  19. package/docs/v1-to-v2-migration/direct-migration-guide.md +0 -238
  20. package/docs/v1-to-v2-migration/v1-to-v2-comparison.md +0 -547
  21. package/docs/v2/PageObject.md +0 -293
  22. package/docs/v2/composing-locator-modules.md +0 -93
  23. package/docs/v2/locator-registry.md +0 -693
  24. package/docs/v2/logging.md +0 -168
  25. package/docs/v2/overview.md +0 -515
  26. package/docs/v2/session-storage.md +0 -160
  27. package/index.ts +0 -75
  28. package/intTestV2/.env +0 -0
  29. package/intTestV2/fixtures/testApp.fixtures.ts +0 -43
  30. package/intTestV2/package.json +0 -22
  31. package/intTestV2/page-object-models/testApp/pages/iframe/iframe.locatorSchema.ts +0 -24
  32. package/intTestV2/page-object-models/testApp/pages/iframe/iframe.page.ts +0 -17
  33. package/intTestV2/page-object-models/testApp/pages/testPage.locatorSchema.ts +0 -32
  34. package/intTestV2/page-object-models/testApp/pages/testPage.page.ts +0 -119
  35. package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.locatorSchema.ts +0 -29
  36. package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.page.ts +0 -48
  37. package/intTestV2/page-object-models/testApp/pages/testPath/testPath.locatorSchema.ts +0 -9
  38. package/intTestV2/page-object-models/testApp/pages/testPath/testPath.page.ts +0 -23
  39. package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.locatorSchema.ts +0 -114
  40. package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.page.ts +0 -23
  41. package/intTestV2/page-object-models/testApp/testApp.base.ts +0 -20
  42. package/intTestV2/playwright.config.ts +0 -54
  43. package/intTestV2/server.js +0 -216
  44. package/intTestV2/test-data/staticPage/index.html +0 -280
  45. package/intTestV2/test-data/staticPage/w3images/avatar2.png +0 -0
  46. package/intTestV2/test-data/staticPage/w3images/avatar3.png +0 -0
  47. package/intTestV2/test-data/staticPage/w3images/avatar5.png +0 -0
  48. package/intTestV2/test-data/staticPage/w3images/avatar6.png +0 -0
  49. package/intTestV2/test-data/staticPage/w3images/forest.jpg +0 -0
  50. package/intTestV2/test-data/staticPage/w3images/lights.jpg +0 -0
  51. package/intTestV2/test-data/staticPage/w3images/mountains.jpg +0 -0
  52. package/intTestV2/test-data/staticPage/w3images/nature.jpg +0 -0
  53. package/intTestV2/test-data/staticPage/w3images/snow.jpg +0 -0
  54. package/intTestV2/tests/locatorRegistry/add/add.describe.spec.ts +0 -54
  55. package/intTestV2/tests/locatorRegistry/add/add.filter.spec.ts +0 -143
  56. package/intTestV2/tests/locatorRegistry/add/add.frameLocator.spec.ts +0 -23
  57. package/intTestV2/tests/locatorRegistry/add/add.getByAltText.spec.ts +0 -23
  58. package/intTestV2/tests/locatorRegistry/add/add.getById.spec.ts +0 -45
  59. package/intTestV2/tests/locatorRegistry/add/add.getByLabel.spec.ts +0 -23
  60. package/intTestV2/tests/locatorRegistry/add/add.getByPlaceholder.spec.ts +0 -23
  61. package/intTestV2/tests/locatorRegistry/add/add.getByRole.spec.ts +0 -23
  62. package/intTestV2/tests/locatorRegistry/add/add.getByTestId.spec.ts +0 -23
  63. package/intTestV2/tests/locatorRegistry/add/add.getByText.spec.ts +0 -23
  64. package/intTestV2/tests/locatorRegistry/add/add.getByTitle.spec.ts +0 -23
  65. package/intTestV2/tests/locatorRegistry/add/add.locator.spec.ts +0 -23
  66. package/intTestV2/tests/locatorRegistry/add/add.reuseExisting.spec.ts +0 -66
  67. package/intTestV2/tests/locatorRegistry/add/add.reuseReusable.spec.ts +0 -311
  68. package/intTestV2/tests/locatorRegistry/add/add.spec.ts +0 -159
  69. package/intTestV2/tests/locatorRegistry/filter.cycle.spec.ts +0 -39
  70. package/intTestV2/tests/locatorRegistry/getLocator/getLocator.spec.ts +0 -253
  71. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.clearSteps.spec.ts +0 -105
  72. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.describe.spec.ts +0 -23
  73. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.filter.spec.ts +0 -368
  74. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getLocator.spec.ts +0 -56
  75. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getNestedLocator.spec.ts +0 -175
  76. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.nth.spec.ts +0 -60
  77. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.remove.spec.ts +0 -32
  78. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.replace.spec.ts +0 -24
  79. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.spec.ts +0 -110
  80. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.update.spec.ts +0 -322
  81. package/intTestV2/tests/locatorRegistry/getNestedLocator/getNestedLocator.spec.ts +0 -412
  82. package/intTestV2/tests/locatorRegistry/registry/registry.binding.spec.ts +0 -50
  83. package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.spec.ts +0 -115
  84. package/intTestV2/tests/locatorRegistry/validation/validation.sub-path.spec.ts +0 -45
  85. package/intTestV2/tests/step/step.spec.ts +0 -49
  86. package/intTestV2/tests/testApp/color.spec.ts +0 -15
  87. package/intTestV2/tests/testApp/iframe.spec.ts +0 -57
  88. package/intTestV2/tests/testApp/testFilters.spec.ts +0 -24
  89. package/intTestV2/tests/testApp/testPage.spec.ts +0 -161
  90. package/intTestV2/tests/testApp/testPath.spec.ts +0 -18
  91. package/pack-build.sh +0 -11
  92. package/pack-test-v2.sh +0 -36
  93. package/playwright.base.ts +0 -42
  94. package/skills/README.md +0 -56
  95. package/skills/pomwright-v1-5-bridge-migration/SKILL.md +0 -40
  96. package/skills/pomwright-v1-5-bridge-migration/references/call-site-migration.md +0 -178
  97. package/skills/pomwright-v1-5-bridge-migration/references/schema-translation.md +0 -183
  98. package/skills/pomwright-v2-migration/SKILL.md +0 -63
  99. package/skills/pomwright-v2-migration/references/call-site-migration.md +0 -265
  100. package/skills/pomwright-v2-migration/references/class-migration.md +0 -266
  101. package/skills/pomwright-v2-migration/references/fixture-and-helpers.md +0 -423
  102. package/skills/pomwright-v2-migration/references/locator-registration.md +0 -344
  103. package/srcV2/fixture/base.fixtures.ts +0 -23
  104. package/srcV2/helpers/navigation.ts +0 -153
  105. package/srcV2/helpers/playwrightReportLogger.ts +0 -196
  106. package/srcV2/helpers/sessionStorage.ts +0 -251
  107. package/srcV2/helpers/stepDecorator.ts +0 -106
  108. package/srcV2/locators/index.ts +0 -15
  109. package/srcV2/locators/locatorQueryBuilder.ts +0 -427
  110. package/srcV2/locators/locatorRegistrationBuilder.ts +0 -558
  111. package/srcV2/locators/locatorRegistry.ts +0 -541
  112. package/srcV2/locators/locatorUpdateBuilder.ts +0 -602
  113. package/srcV2/locators/reusableLocatorBuilder.ts +0 -200
  114. package/srcV2/locators/types.ts +0 -256
  115. package/srcV2/locators/utils.ts +0 -309
  116. package/srcV2/locators/v1SchemaTranslator.ts +0 -178
  117. package/srcV2/pageObject.ts +0 -105
@@ -1,266 +0,0 @@
1
- # Class Migration: Inheritance, Constructor, Generics, Abstract Methods
2
-
3
- ## Inheritance change
4
-
5
- ```ts
6
- // v1
7
- import { BasePage } from "pomwright";
8
- class MyPage extends BasePage<Paths> { ... }
9
-
10
- // v1.5 bridge
11
- import { BasePageV1toV2 } from "pomwright";
12
- class MyPage extends BasePageV1toV2<Paths> { ... }
13
-
14
- // v2
15
- import { PageObject } from "pomwright";
16
- class MyPage extends PageObject<Paths> { ... }
17
- ```
18
-
19
- ## Constructor signature
20
-
21
- v1/bridge constructor:
22
-
23
- ```ts
24
- constructor(
25
- page: Page,
26
- testInfo: TestInfo,
27
- baseUrl: string | RegExp,
28
- urlPath: string | RegExp,
29
- pocName: string,
30
- pwrl: PlaywrightReportLogger,
31
- )
32
- ```
33
-
34
- v2 constructor:
35
-
36
- ```ts
37
- constructor(
38
- page: Page,
39
- baseUrl: string | RegExp,
40
- urlPath: string | RegExp,
41
- options?: { label?: string; navOptions?: NavigationOptions },
42
- )
43
- ```
44
-
45
- Changes:
46
- - `testInfo` removed entirely (not needed by PageObject).
47
- - `pocName` replaced by `options.label`. Defaults to `this.constructor.name`, so it can usually be omitted unless the v1 pocName differed from the class name.
48
- - `PlaywrightReportLogger` removed from constructor; use the `log` fixture from `pomwright` in tests instead.
49
- - Optional `navOptions` added for configuring `waitUntil` and `waitForLoadState` defaults.
50
-
51
- ### Migration example: concrete page object
52
-
53
- ```ts
54
- // v1
55
- import type { Page, TestInfo } from "@playwright/test";
56
- import { BasePage, type PlaywrightReportLogger } from "pomwright";
57
-
58
- export default class LoginPage extends BasePage<Paths> {
59
- constructor(page: Page, testInfo: TestInfo, pwrl: PlaywrightReportLogger) {
60
- super(page, testInfo, "https://example.com", "/login", "LoginPage", pwrl);
61
- }
62
- }
63
-
64
- // v2
65
- import type { Page } from "@playwright/test";
66
- import { PageObject } from "pomwright";
67
-
68
- export default class LoginPage extends PageObject<Paths> {
69
- constructor(page: Page) {
70
- super(page, "https://example.com", "/login");
71
- // label defaults to "LoginPage" (class name), so no need to pass it
72
- }
73
- }
74
- ```
75
-
76
- If pocName differed from the class name:
77
-
78
- ```ts
79
- // v1
80
- super(page, testInfo, "https://example.com", "/login", "MyCustomLabel", pwrl);
81
-
82
- // v2
83
- super(page, "https://example.com", "/login", { label: "MyCustomLabel" });
84
- ```
85
-
86
- ### Migration example: abstract base class
87
-
88
- v1 abstract base classes typically wrap `baseUrl` and forward the rest:
89
-
90
- ```ts
91
- // v1
92
- import type { Page, TestInfo } from "@playwright/test";
93
- import { BasePage, type PlaywrightReportLogger } from "pomwright";
94
-
95
- export default abstract class AppBase<Paths extends string> extends BasePage<Paths> {
96
- constructor(page: Page, testInfo: TestInfo, urlPath: string, pocName: string, pwrl: PlaywrightReportLogger) {
97
- super(page, testInfo, "http://localhost:8080", urlPath, pocName, pwrl);
98
- }
99
- }
100
-
101
- // v2
102
- import type { Page } from "@playwright/test";
103
- import { type NavigationOptions, PageObject, type UrlPathTypeFromOptions, type UrlTypeOptions } from "pomwright";
104
-
105
- type BaseOptions<Options extends UrlTypeOptions> = {
106
- baseUrlType: string;
107
- urlPathType: UrlPathTypeFromOptions<Options>;
108
- };
109
-
110
- export default abstract class AppBase<
111
- Paths extends string,
112
- Options extends UrlTypeOptions = { baseUrlType: string; urlPathType: string },
113
- > extends PageObject<Paths, BaseOptions<Options>> {
114
- protected constructor(
115
- page: Page,
116
- urlPath: UrlPathTypeFromOptions<BaseOptions<Options>>,
117
- options?: { label?: string; navOptions?: NavigationOptions },
118
- ) {
119
- super(page, "http://localhost:8080", urlPath, options);
120
- }
121
- }
122
- ```
123
-
124
- Concrete subclass in v2:
125
-
126
- ```ts
127
- import type { Page } from "@playwright/test";
128
- import AppBase from "../base/appBase";
129
-
130
- export default class LoginPage extends AppBase<Paths> {
131
- constructor(page: Page) {
132
- super(page, "/login");
133
- }
134
- }
135
- ```
136
-
137
- ## Generic type parameters
138
-
139
- ### Simple case (string baseUrl, string urlPath)
140
-
141
- ```ts
142
- // v1
143
- class MyPage extends BasePage<Paths> { ... }
144
-
145
- // v2 (identical shape, just different base class)
146
- class MyPage extends PageObject<Paths> { ... }
147
- ```
148
-
149
- ### With URL type options (e.g. RegExp urlPath)
150
-
151
- ```ts
152
- // v1
153
- import { type BasePageOptions, type ExtractUrlPathType, BasePage } from "pomwright";
154
-
155
- class ColorPage extends BasePage<
156
- Paths,
157
- { urlOptions: { baseUrlType: string; urlPathType: RegExp } }
158
- > { ... }
159
-
160
- // v2 (flattened options shape, renamed types)
161
- import { type UrlTypeOptions, type UrlPathTypeFromOptions, PageObject } from "pomwright";
162
-
163
- class ColorPage extends PageObject<
164
- Paths,
165
- { baseUrlType: string; urlPathType: RegExp }
166
- > { ... }
167
- ```
168
-
169
- ### URL type helper renames
170
-
171
- | v1 | v2 |
172
- |---|---|
173
- | `BasePageOptions` | `UrlTypeOptions` |
174
- | `ExtractBaseUrlType<T>` | `BaseUrlTypeFromOptions<T>` |
175
- | `ExtractUrlPathType<T>` | `UrlPathTypeFromOptions<T>` |
176
- | `ExtractFullUrlType<T>` | `FullUrlTypeFromOptions<T>` |
177
-
178
- The options shape itself flattened:
179
-
180
- ```ts
181
- // v1
182
- { urlOptions: { baseUrlType: string; urlPathType: RegExp } }
183
-
184
- // v2
185
- { baseUrlType: string; urlPathType: RegExp }
186
- ```
187
-
188
- ## Required abstract methods
189
-
190
- v2 `PageObject` requires two abstract methods:
191
-
192
- ### defineLocators()
193
-
194
- Same as bridge. See [locator-registration.md](locator-registration.md) for the full DSL mapping.
195
-
196
- ```ts
197
- protected defineLocators(): void {
198
- this.add("main").locator("main");
199
- this.add("main.button@login").getByRole("button", { name: "Login" });
200
- }
201
- ```
202
-
203
- ### pageActionsToPerformAfterNavigation()
204
-
205
- New in v2. Returns an array of async callbacks to run after `navigation.gotoThisPage()`, or `null` if none are needed.
206
-
207
- ```ts
208
- // No post-navigation actions
209
- protected pageActionsToPerformAfterNavigation(): (() => Promise<void>)[] | null {
210
- return null;
211
- }
212
-
213
- // With post-navigation actions (e.g., wait for loading state)
214
- protected pageActionsToPerformAfterNavigation(): (() => Promise<void>)[] | null {
215
- return [
216
- async () => {
217
- await this.getNestedLocator("main.spinner").waitFor({ state: "hidden" });
218
- },
219
- ];
220
- }
221
- ```
222
-
223
- If the v1 page object had post-navigation logic scattered in tests (e.g., waiting for elements after `page.goto`), consider moving it here.
224
-
225
- ## Properties available on PageObject
226
-
227
- | Property | Description |
228
- |---|---|
229
- | `this.page` | Playwright `Page` instance |
230
- | `this.baseUrl` | Base URL (string or RegExp) |
231
- | `this.urlPath` | URL path (string or RegExp) |
232
- | `this.fullUrl` | Composed full URL |
233
- | `this.label` | PageObject identifier (defaults to class name) |
234
- | `this.sessionStorage` | SessionStorage helper |
235
- | `this.navigation` | Navigation helper (type depends on URL types) |
236
- | `this.locatorRegistry` | Internal LocatorRegistry (for sharing with external `defineLocators` functions) |
237
- | `this.add` | Locator registration accessor |
238
- | `this.getLocator` | Terminal locator accessor |
239
- | `this.getNestedLocator` | Chained locator accessor |
240
- | `this.getLocatorSchema` | Schema query builder accessor |
241
-
242
- ## Removed v1 properties
243
-
244
- | v1 property | v2 replacement |
245
- |---|---|
246
- | `this.testInfo` | Not available; use test fixture if needed |
247
- | `this.log` | Not built-in; use `log` fixture from `pomwright` |
248
- | `this.pocName` | `this.label` |
249
- | `this.selector` | Not available; locator strategies are in the registry |
250
- | `this.locators` (GetLocatorBase) | `this.locatorRegistry` / `this.add` / `this.getLocator` etc. |
251
-
252
- ## Import changes
253
-
254
- ```ts
255
- // v1
256
- import { BasePage, GetByMethod, type BasePageOptions, type ExtractUrlPathType,
257
- type ExtractBaseUrlType, type ExtractFullUrlType, type GetLocatorBase,
258
- type PlaywrightReportLogger, type LocatorSchemaWithoutPath } from "pomwright";
259
-
260
- // v2
261
- import { PageObject, type UrlTypeOptions, type UrlPathTypeFromOptions,
262
- type BaseUrlTypeFromOptions, type FullUrlTypeFromOptions,
263
- type LocatorRegistry, type NavigationOptions } from "pomwright";
264
- ```
265
-
266
- Remove imports that no longer exist: `GetByMethod`, `BasePage`, `BasePageV1toV2`, `BasePageOptions`, `ExtractUrlPathType`, `ExtractBaseUrlType`, `ExtractFullUrlType`, `GetLocatorBase`, `LocatorSchemaWithoutPath`.
@@ -1,423 +0,0 @@
1
- # Fixtures and Helpers: Navigation, SessionStorage, @step, Logging
2
-
3
- ## Fixture migration
4
-
5
- v1 fixtures inject `page`, `log`, and `testInfo` into PageObject constructors. v2 fixtures only inject `page`.
6
-
7
- ```ts
8
- // v1
9
- import TestPage from "./testPage.page";
10
- import { test as base } from "pomwright";
11
-
12
- type Fixtures = {
13
- testPage: TestPage;
14
- };
15
-
16
- const test = base.extend<Fixtures>({
17
- testPage: async ({ page, log }, use, testInfo) => {
18
- const testPage = new TestPage(page, testInfo, log);
19
- await use(testPage);
20
- },
21
- });
22
-
23
- export { test };
24
-
25
- // v2
26
- import TestPage from "./testPage.page";
27
- import { test as base } from "pomwright";
28
-
29
- type Fixtures = {
30
- testPage: TestPage;
31
- };
32
-
33
- const test = base.extend<Fixtures>({
34
- testPage: async ({ page }, use) => {
35
- const testPage = new TestPage(page);
36
- await use(testPage);
37
- },
38
- });
39
-
40
- export { test };
41
- ```
42
-
43
- Key changes:
44
- - Remove `testInfo` parameter from fixture callback (no longer needed by PageObject).
45
- - Remove `log` parameter from fixture callback (no longer injected into PageObject).
46
- - Constructor call simplified to `new TestPage(page)`.
47
- - The `log` fixture from `pomwright` is still available in tests if needed for test-level logging.
48
-
49
- ## Navigation helper
50
-
51
- v2 `PageObject` exposes a `navigation` property with URL-based navigation methods. This replaces manual `page.goto()` patterns from v1.
52
-
53
- ### Available when fullUrl is string (baseUrl: string, urlPath: string)
54
-
55
- ```ts
56
- // Navigate to the PageObject's own URL
57
- await poc.navigation.gotoThisPage();
58
-
59
- // Navigate to a different path under the same baseUrl
60
- await poc.navigation.goto("/other-path");
61
-
62
- // Assert current page matches this PageObject's URL
63
- await poc.navigation.expectThisPage();
64
-
65
- // Assert current page does NOT match this PageObject's URL
66
- await poc.navigation.expectAnotherPage();
67
- ```
68
-
69
- ### Available when fullUrl is RegExp (baseUrl or urlPath is RegExp)
70
-
71
- ```ts
72
- // Only assertion methods available (no goto - can't construct URL from RegExp)
73
- await poc.navigation.expectThisPage();
74
- await poc.navigation.expectAnotherPage();
75
- ```
76
-
77
- ### Navigation options
78
-
79
- ```ts
80
- // At construction time (defaults for all navigation calls)
81
- super(page, "https://example.com", "/login", {
82
- navOptions: {
83
- waitUntil: "networkidle",
84
- waitForLoadState: "domcontentloaded",
85
- },
86
- });
87
-
88
- // Per navigation call (overrides defaults)
89
- await poc.navigation.gotoThisPage({
90
- waitUntil: "commit",
91
- waitForLoadState: "load",
92
- });
93
- ```
94
-
95
- ### Post-navigation actions
96
-
97
- The `pageActionsToPerformAfterNavigation()` method runs automatically after `navigation.gotoThisPage()` and `navigation.expectThisPage()`:
98
-
99
- ```ts
100
- protected pageActionsToPerformAfterNavigation(): (() => Promise<void>)[] | null {
101
- return [
102
- async () => {
103
- // Wait for page to be ready
104
- await this.getNestedLocator("main.spinner").waitFor({ state: "hidden" });
105
- },
106
- async () => {
107
- // Additional setup
108
- await this.getNestedLocator("main.content").waitFor({ state: "visible" });
109
- },
110
- ];
111
- }
112
- ```
113
-
114
- ### Migration from v1 navigation patterns
115
-
116
- ```ts
117
- // v1 (manual navigation in tests)
118
- test("login flow", async ({ loginPage }) => {
119
- await loginPage.page.goto(loginPage.fullUrl);
120
- await loginPage.page.waitForLoadState("networkidle");
121
- // ... test logic
122
- });
123
-
124
- // v2 (navigation helper)
125
- test("login flow", async ({ loginPage }) => {
126
- await loginPage.navigation.gotoThisPage();
127
- // post-navigation actions run automatically
128
- // ... test logic
129
- });
130
- ```
131
-
132
- ## SessionStorage helper
133
-
134
- Available on PageObject as `this.sessionStorage`. API changed from v1.
135
-
136
- ### Constructor
137
-
138
- ```ts
139
- // v1: SessionStorage was instantiated internally by BasePage
140
- // v2: SessionStorage is instantiated internally by PageObject
141
- // Both expose it as this.sessionStorage
142
-
143
- // v2 also supports standalone usage:
144
- import { SessionStorage } from "pomwright";
145
- const sessionStorage = new SessionStorage(page, { label: "MyLabel" });
146
- ```
147
-
148
- ### Method signatures
149
-
150
- ```ts
151
- // set: write items to sessionStorage
152
- await poc.sessionStorage.set({ token: "abc", theme: "dark" });
153
- await poc.sessionStorage.set({ token: "abc" }, { reload: true }); // reload page after
154
- await poc.sessionStorage.set({ token: "abc" }, { waitForContext: true }); // wait for page context
155
-
156
- // setOnNextNavigation: queue items to be written on next page navigation
157
- await poc.sessionStorage.setOnNextNavigation({ token: "abc" });
158
-
159
- // get: read items from sessionStorage
160
- const all = await poc.sessionStorage.get(); // all items
161
- const specific = await poc.sessionStorage.get(["token", "theme"]); // specific keys
162
- const waited = await poc.sessionStorage.get(["token"], { waitForContext: true });
163
-
164
- // clear: remove items from sessionStorage
165
- await poc.sessionStorage.clear(); // all items
166
- await poc.sessionStorage.clear("token"); // specific key
167
- await poc.sessionStorage.clear(["token", "theme"]); // specific keys
168
- await poc.sessionStorage.clear("token", { waitForContext: true }); // with wait
169
- ```
170
-
171
- ### v1 -> v2 signature changes
172
-
173
- | v1 | v2 |
174
- |---|---|
175
- | `.set(states, reload: boolean)` | `.set(states, { reload?: boolean; waitForContext?: boolean })` |
176
- | `.get()` | `.get(keys?, { waitForContext?: boolean })` |
177
- | `.clear()` | `.clear(keys?, { waitForContext?: boolean })` |
178
-
179
- ## @step decorator
180
-
181
- v2 provides a `@step` decorator that wraps methods in `test.step()` for Playwright reporting.
182
-
183
- ```ts
184
- import { step } from "pomwright";
185
-
186
- class LoginPage extends PageObject<Paths> {
187
- // Step title defaults to "LoginPage.login"
188
- @step
189
- async login(username: string, password: string) {
190
- await this.getNestedLocator("main.form.input@username").fill(username);
191
- await this.getNestedLocator("main.form.input@password").fill(password);
192
- await this.getNestedLocator("main.form.button@submit").click();
193
- }
194
-
195
- // Custom step title
196
- @step("Perform logout")
197
- async logout() {
198
- await this.getNestedLocator("topMenu.button@logout").click();
199
- }
200
-
201
- // With Playwright step options
202
- @step({ box: true })
203
- async waitForDashboard() {
204
- await this.getNestedLocator("main.dashboard").waitFor({ state: "visible" });
205
- }
206
-
207
- // Custom title + options
208
- @step("Submit login form", { box: true, timeout: 5000 })
209
- async submitForm() {
210
- await this.getNestedLocator("main.form.button@submit").click();
211
- }
212
- }
213
- ```
214
-
215
- ### Decorator forms
216
-
217
- | Form | Description |
218
- |---|---|
219
- | `@step` | No parentheses; title defaults to `ClassName.methodName` |
220
- | `@step()` | Empty call; same as `@step` |
221
- | `@step("title")` | Custom step title |
222
- | `@step({ box: true })` | Playwright step options |
223
- | `@step("title", { box: true })` | Custom title + options |
224
-
225
- ### Migration from v1 manual test.step patterns
226
-
227
- ```ts
228
- // v1 (manual step wrapping in the POC)
229
- async login(username: string) {
230
- await test.step("LoginPage.login", async () => {
231
- const input = await this.getNestedLocator("main.form.input@username");
232
- await input.fill(username);
233
- });
234
- }
235
-
236
- // v2 (decorator)
237
- @step()
238
- async login(username: string) {
239
- await this.getNestedLocator("main.form.input@username").fill(username);
240
- }
241
- ```
242
-
243
- ## Logging
244
-
245
- ### v1: Logger injected into constructor
246
-
247
- ```ts
248
- // v1
249
- class LoginPage extends BasePage<Paths> {
250
- constructor(page: Page, testInfo: TestInfo, pwrl: PlaywrightReportLogger) {
251
- super(page, testInfo, "https://example.com", "/login", "LoginPage", pwrl);
252
- }
253
-
254
- async doSomething() {
255
- this.log.info("Doing something"); // this.log available on BasePage
256
- }
257
- }
258
-
259
- // v1 fixture
260
- const test = base.extend<Fixtures>({
261
- loginPage: async ({ page, log }, use, testInfo) => {
262
- await use(new LoginPage(page, testInfo, log));
263
- },
264
- });
265
- ```
266
-
267
- ### v2: Logger decoupled from PageObject
268
-
269
- PageObject does not have a built-in `this.log`. If logging is needed:
270
-
271
- **Option A: Use the `log` fixture in tests (recommended)**
272
-
273
- ```ts
274
- import { test } from "pomwright";
275
-
276
- test("login flow", async ({ page, log }) => {
277
- log.info("Starting login flow");
278
- const loginPage = new LoginPage(page);
279
- // ...
280
- });
281
- ```
282
-
283
- **Option B: Pass logger to PageObject manually**
284
-
285
- ```ts
286
- import { type PlaywrightReportLogger, PageObject } from "pomwright";
287
-
288
- class LoginPage extends PageObject<Paths> {
289
- constructor(page: Page, private log: PlaywrightReportLogger) {
290
- super(page, "https://example.com", "/login");
291
- }
292
-
293
- @step()
294
- async doSomething() {
295
- this.log.info("Doing something");
296
- }
297
- }
298
-
299
- // Fixture
300
- const test = base.extend<Fixtures>({
301
- loginPage: async ({ page, log }, use) => {
302
- await use(new LoginPage(page, log));
303
- },
304
- });
305
- ```
306
-
307
- **Option C: Create a child logger in the fixture**
308
-
309
- ```ts
310
- const test = base.extend<Fixtures>({
311
- loginPage: async ({ page, log }, use) => {
312
- const childLog = log.getNewChildLogger("LoginPage");
313
- await use(new LoginPage(page, childLog));
314
- },
315
- });
316
- ```
317
-
318
- ## Complete migration example
319
-
320
- ### v1 (before)
321
-
322
- ```ts
323
- // loginPage.page.ts
324
- import type { Page, TestInfo } from "@playwright/test";
325
- import { BasePage, GetByMethod, type PlaywrightReportLogger } from "pomwright";
326
-
327
- type Paths = "main" | "main.form" | "main.form.input@username" | "main.form.button@submit";
328
-
329
- export default class LoginPage extends BasePage<Paths> {
330
- constructor(page: Page, testInfo: TestInfo, pwrl: PlaywrightReportLogger) {
331
- super(page, testInfo, "https://example.com", "/login", "LoginPage", pwrl);
332
- }
333
-
334
- protected initLocatorSchemas() {
335
- this.locators.addSchema("main", { locator: "main", locatorMethod: GetByMethod.locator });
336
- this.locators.addSchema("main.form", { locator: "form.login", locatorMethod: GetByMethod.locator });
337
- this.locators.addSchema("main.form.input@username", { label: "Username", locatorMethod: GetByMethod.label });
338
- this.locators.addSchema("main.form.button@submit", {
339
- role: "button", roleOptions: { name: "Submit" }, locatorMethod: GetByMethod.role,
340
- });
341
- }
342
-
343
- async login(username: string) {
344
- const input = await this.getNestedLocator("main.form.input@username");
345
- await input.fill(username);
346
- const btn = await this.getNestedLocator("main.form.button@submit");
347
- await btn.click();
348
- }
349
- }
350
-
351
- // fixture
352
- const test = base.extend<Fixtures>({
353
- loginPage: async ({ page, log }, use, testInfo) => {
354
- await use(new LoginPage(page, testInfo, log));
355
- },
356
- });
357
-
358
- // test
359
- test("login", async ({ loginPage }) => {
360
- await loginPage.page.goto(loginPage.fullUrl);
361
- await loginPage.login("admin");
362
- });
363
- ```
364
-
365
- ### v2 (after)
366
-
367
- ```ts
368
- // loginPage.locatorSchema.ts
369
- import type { LocatorRegistry } from "pomwright";
370
-
371
- export type Paths = "main" | "main.form" | "main.form.input@username" | "main.form.button@submit";
372
-
373
- export function defineLocators(registry: LocatorRegistry<Paths>) {
374
- registry.add("main").locator("main");
375
- registry.add("main.form").locator("form.login");
376
- registry.add("main.form.input@username").getByLabel("Username");
377
- registry.add("main.form.button@submit").getByRole("button", { name: "Submit" });
378
- }
379
- ```
380
-
381
- ```ts
382
- // loginPage.page.ts
383
- import type { Page } from "@playwright/test";
384
- import { PageObject, step } from "pomwright";
385
- import { defineLocators, type Paths } from "./loginPage.locatorSchema";
386
-
387
- export default class LoginPage extends PageObject<Paths> {
388
- constructor(page: Page) {
389
- super(page, "https://example.com", "/login");
390
- }
391
-
392
- protected defineLocators(): void {
393
- defineLocators(this.locatorRegistry);
394
- }
395
-
396
- protected pageActionsToPerformAfterNavigation(): (() => Promise<void>)[] | null {
397
- return null;
398
- }
399
-
400
- @step()
401
- async login(username: string) {
402
- await this.getNestedLocator("main.form.input@username").fill(username);
403
- await this.getNestedLocator("main.form.button@submit").click();
404
- }
405
- }
406
- ```
407
-
408
- ```ts
409
- // fixture
410
- const test = base.extend<Fixtures>({
411
- loginPage: async ({ page }, use) => {
412
- await use(new LoginPage(page));
413
- },
414
- });
415
- ```
416
-
417
- ```ts
418
- // test
419
- test("login", async ({ loginPage }) => {
420
- await loginPage.navigation.gotoThisPage();
421
- await loginPage.login("admin");
422
- });
423
- ```