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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pomwright",
3
- "version": "1.5.0",
3
+ "version": "2.0.0",
4
4
  "description": "POMWright is a complementary test framework for Playwright written in TypeScript.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,6 +17,12 @@
17
17
  "main": "dist/index.js",
18
18
  "module": "dist/index.mjs",
19
19
  "types": "dist/index.d.ts",
20
+ "files": [
21
+ "dist/**",
22
+ "README.md",
23
+ "LICENSE",
24
+ "CHANGELOG.md"
25
+ ],
20
26
  "keywords": [
21
27
  "Playwright",
22
28
  "POM",
@@ -43,8 +49,7 @@
43
49
  "@changesets/cli": "^2.29.7",
44
50
  "@types/node": "^24.5.2",
45
51
  "tsup": "^8.5.0",
46
- "typescript": "^5.9.2",
47
- "vitest": "^3.2.4"
52
+ "typescript": "^5.9.2"
48
53
  },
49
54
  "peerDependencies": {
50
55
  "@playwright/test": ">=1.57.0 <2.0.0"
@@ -53,15 +58,8 @@
53
58
  "build": "tsup index.ts --format cjs,esm --dts",
54
59
  "release": "pnpm run build && changeset publish",
55
60
  "lint": "biome check ./src",
56
- "lint:v2": "biome check ./srcV2",
57
- "lint:all": "pnpm lint && pnpm lint:v2",
58
61
  "format": "biome format ./src --write",
59
- "format:v2": "biome format ./srcV2 --write",
60
- "format:all": "pnpm format && pnpm format:v2",
61
62
  "pack-test": "bash pack-test.sh",
62
- "pack-test:v2": "bash pack-test-v2.sh",
63
- "test": "vitest run && bash pack-test.sh",
64
- "test:v2": "bash pack-test-v2.sh",
65
- "test:all": "pnpm test && pnpm test:v2"
63
+ "test": "pnpm pack-test"
66
64
  }
67
65
  }
package/AGENTS.md DELETED
@@ -1,37 +0,0 @@
1
- # Agent Guidelines for POMWright
2
-
3
- This repository carries both the **v1** codepath (`src`, `intTest`) and the ongoing **v2** refactor (`srcV2`, `intTestV2`). Use the guidance below whenever you modify files in this repo.
4
-
5
- ## Development priorities
6
-
7
- - Focus exclusively on the v2 codepath for implementation work. Do **not** change v1 (`src`, `intTest`); it is retained only for side-by-side comparison and regression awareness.
8
- - Preserve the fluent locator registry API introduced in v2 (via `LocatorRegistry`, `bindLocatorAccessors`, and the thenable builders) and keep examples/tests aligned with it.
9
- - Design v2 around the Page Object Model pattern expressed through functional programming: features should be as independent and composable as possible so users can adopt only what they need.
10
- - Write documentation under `docsV2/` for v2 work while consulting v1 docs in `docs/` for context and completeness.
11
- - Always consult the drift tracker at `docsV2/v1-v2-drift.md` before making changes, and update it immediately when you spot new breaking changes, regressions, or bug fixes.
12
- - Prefer migration helpers/shims over strict runtime compatibility with v1 APIs; clear improvements in functionality and syntax take priority over backwards compatibility.
13
-
14
- ## Coding style
15
-
16
- - Follow the `.editorconfig` (tabs, size 2) and existing TypeScript conventions in the project.
17
- - Use pnpm for scripts and dependency management.
18
- - Prefer descriptive naming for locator paths and avoid anonymous segments; the registry validates dot-delimited paths with no leading/trailing dots.
19
- - Avoid `//biome-ignore` where possible by addressing the underlying lint/type issue; when necessary, include a short justification with the directive.
20
- - Do not wrap imports in `try/catch` blocks.
21
-
22
- ## Testing and quality
23
-
24
- - Always run and fix `pnpm pack-test:v2` and `pnpm lint:v2` before committing. Use `lint:v2` to avoid unrelated v1 noise.
25
- - If you add or change locators or behavioural contracts, expand integration coverage in `intTestV2`; err on the side of more tests while keeping existing cases intact.
26
- - Existing tests in `intTestV2` should be maintained and keep their scope/cases. If a change would require large edits to a case, prefer adding new tests instead.
27
-
28
- ## Commit and PR expectations
29
-
30
- - Keep commits scoped and descriptive; call out the v2 focus explicitly.
31
- - Keep docs and examples showing both v1 and v2 patterns where relevant to ease migration, but prioritize clear improvements in functionality and syntax over backwards compatibility.
32
-
33
- ## Notes on locator work
34
-
35
- - Use v2’s builder DSL (`locators.add('path').getByRole(...)`, filters/index steps, frame handling) for new schemas and tests.
36
- - Prefer migration helpers/shims over trying to keep strict runtime compatibility with v1 APIs.
37
- - Document any intentionally breaking changes and provide migration tips where possible—capture them in `docsV2/v1-v2-drift.md` as they arise.
@@ -1,63 +0,0 @@
1
- # BaseApi
2
-
3
- The `BaseApi` class offers a minimal foundation for writing API helpers in POMWright. It wraps Playwright's `APIRequestContext` and integrates with the shared [`PlaywrightReportLogger`](./PlaywrightReportLogger-explanation.md).
4
-
5
- ## Constructor
6
-
7
- ```ts
8
- constructor(baseUrl: string, apiName: string, context: APIRequestContext, pwrl: PlaywrightReportLogger)
9
- ```
10
-
11
- * `baseUrl` – root address used to build request URLs.
12
- * `apiName` – human‑readable identifier; also used as a logging prefix.
13
- * `context` – Playwright [`APIRequestContext`](https://playwright.dev/docs/api/class-apirequestcontext).
14
- * `pwrl` – logger instance supplied by the test fixtures. A child logger is created for the API class.
15
-
16
- The class stores these values on the instance and exposes the `request` and `log` properties for use in subclasses.
17
-
18
- ## Example
19
-
20
- ```ts
21
- import type { APIRequestContext } from "@playwright/test";
22
- import { BaseApi, type PlaywrightReportLogger } from "pomwright";
23
-
24
- class MyApi extends BaseApi {
25
- constructor(baseUrl: string, context: APIRequestContext, pwrl: PlaywrightReportLogger) {
26
- super(baseUrl, MyApi.name, context, pwrl);
27
- }
28
-
29
- v1 = {
30
- users: {
31
- id: {
32
- get: async (id: string, status: number = 200) => {
33
- const response = await this.request.get(`/api/users/${id}`);
34
- expect(response.status(), "should have status code: 200").toBe(status);
35
- const body = await response.json();
36
- return body;
37
- },
38
- //...etc.
39
- }
40
- },
41
- products: {
42
- //...etc.
43
- }
44
- }
45
- }
46
- ```
47
-
48
- Then in a test you'd do:
49
-
50
- ```ts
51
- test("some test", { tag: ["@api", "@user"] }, async ({ myApi }) => {
52
- // Create user
53
-
54
- const existingUser = await myApi.v1.users.id.get(userId); // 200 (default) user found
55
-
56
- // Delete user
57
-
58
- const deletedUser = await myApi.v1.users.id.get(userId, 204); // 204 user not found successfully
59
-
60
- })
61
- ```
62
-
63
- `BaseApi` does not dictate how requests are made; you are free to add domain‑specific methods using the provided `request` context and logger.
@@ -1,96 +0,0 @@
1
- # BasePage
2
-
3
- `BasePage` is the foundation for all Page Object Classes (POCs) in POMWright. It provides common plumbing for Playwright pages, logging, locator management and session storage.
4
-
5
- ## Generics
6
-
7
- ```ts
8
- BasePage<LocatorSchemaPathType, Options = { urlOptions: { baseUrlType: string; urlPathType: string } }, LocatorSubstring>
9
- ```
10
-
11
- * **LocatorSchemaPathType** – union of valid locator paths for the POC.
12
- * **Options** – optional configuration that allows the `baseUrl` or `urlPath` to be typed as a `RegExp` when dynamic values are required for mapping certain resource paths. See [intTest/page-object-models/testApp/with-options/base/baseWithOptions.page.ts](../intTest/page-object-models/testApp/with-options/base/baseWithOptions.page.ts)
13
- * **LocatorSubstring** – internal type used when working with sub paths; normally left undefined.
14
-
15
- ## Constructor
16
-
17
- ```ts
18
- constructor(
19
- page: Page,
20
- testInfo: TestInfo,
21
- baseUrl: ExtractBaseUrlType<Options>,
22
- urlPath: ExtractUrlPathType<Options>,
23
- pocName: string,
24
- pwrl: PlaywrightReportLogger
25
- )
26
- ```
27
-
28
- The base class stores these values and derives `fullUrl`. A child [`PlaywrightReportLogger`](./PlaywrightReportLogger-explanation.md) is created for the POC and a [`SessionStorage`](./sessionStorage-methods-explanation.md) helper is exposed as `sessionStorage`.
29
-
30
- ## Required implementation
31
-
32
- Every POC extending `BasePage` must:
33
-
34
- 1. Define a `LocatorSchemaPath` union describing available locators.
35
- 2. Implement the `initLocatorSchemas()` method which adds schemas to the internal `GetLocatorBase` instance.
36
-
37
- ```ts
38
- // login.page.ts
39
- import type { Page, TestInfo } from "@playwright/test";
40
- import { BasePage, type PlaywrightReportLogger } from "pomwright";
41
- import { test } from "@fixtures/all.fixtures";
42
- import { type LocatorSchemaPath, initLocatorSchemas } from "./login.locatorSchema";
43
-
44
- export default class Login extends BasePage<LocatorSchemaPath> {
45
- constructor(page: Page, testInfo: TestInfo, pwrl: PlaywrightReportLogger) {
46
- super(page, testInfo, "https://example.com", "/login", Login.name, pwrl);
47
- }
48
-
49
- protected initLocatorSchemas() {
50
- initLocatorSchemas(this.locators);
51
- }
52
-
53
- public async login(user: string, pass: string) {
54
- await test.step(`${this.pocName}: Fill login form and login`, async () => {
55
-
56
- await test.step(`${this.pocName}: Fill username field`, async () => {
57
- const locator = await this.getNestedLocator("main.section@login.form.textbox@username");
58
- await locator.fill(user);
59
- await locator.blur();
60
- });
61
-
62
- await test.step(`${this.pocName}: Fill password field`, async () => {
63
- const locator = await this.getNestedLocator("main.section@login.form.textbox@password");
64
- await locator.fill(pass);
65
- await locator.blur();
66
- });
67
-
68
- await test.step(`${this.pocName}: Click login button`, async () => {
69
- const locator = await this.getNestedLocator("main.section@login.button@login");
70
- await locator.click();
71
- });
72
-
73
- /**
74
- * We probably don't want to await navigation here, instead we do it in the test,
75
- * using the POC representing the page we are navigated to (e.g. /profile)
76
- */
77
- });
78
- }
79
- }
80
- ```
81
-
82
- ## Helper methods
83
-
84
- `BasePage` exposes a small API built around `LocatorSchema` definitions:
85
-
86
- * `getLocatorSchema(path)` – returns a chainable object; see [locator methods](./get-locator-methods-explanation.md).
87
- * `getLocator(path)` – wrapper method for `getLocatorSchema(path).getLocator();` - resolves the locator for the final segment of a path, e.g. the Locator created from the LocatorSchema the full LocatorSchemaPath references.
88
- * `getNestedLocator(path, indices?)` – wrapper method for `getLocatorSchema(path).getNestedLocator();` - automatically chains locators along the path and optionally selects nth occurrences.
89
-
90
- All locators are strongly typed, giving compile‑time suggestions and preventing typos in `LocatorSchemaPath` strings.
91
-
92
- ## Recommendation
93
-
94
- Instead of extending each of your POC's with BasePage from POMWright, opt instead to create an abstract BasePage class for your domain and have it extend BasePage from POMWright. Then have each of your POC's extend your abstract POC instead. This allows us to easily sentralize common helper methods, LocatorSchema, etc. and reuse it across all our POC's for the given domain.
95
-
96
- For examples see [intTest/page-object-models/testApp](../intTest/page-object-models/testApp)
@@ -1,271 +0,0 @@
1
- # LocatorSchema
2
-
3
- A `LocatorSchema` describes how to find an element in the DOM. Instead of storing Playwright `Locator` objects directly, POMWright keeps these schema definitions and resolves them only when a test requests the locator. The same schema can be reused across multiple page objects and test files without risking stale references.
4
-
5
- Every schema must set `locatorMethod` to one of the [`GetByMethod`](../src/helpers/locatorSchema.interface.ts) enum values. The matching selector fields listed below determine which Playwright API call is executed under the hood. You can provide more than one selector field, but the method chosen by `locatorMethod` is the one that will be used when the locator is created.
6
-
7
- When you register a schema with `GetLocatorBase.addSchema(path, schemaDetails)` the `locatorSchemaPath` is stored automatically and becomes part of the structured logs produced by POMWright.
8
-
9
- ## Selector strategies
10
-
11
- > Note: You can define both "role" and "locator" on the same LocatorSchema, but which one is used is dictated by "locatorMethod". Too keep things clean I recommend only defining the actual type of Playwright Locator you'll be using.
12
-
13
- Each selector strategy maps directly to a Playwright locator helper. The snippets below show the POMWright configuration alongside the equivalent raw Playwright call.
14
-
15
- ### `role` and `roleOptions`
16
-
17
- Use [ARIA roles](https://playwright.dev/docs/api/class-page#page-get-by-role) as your primary selector. The optional `roleOptions` map to the options object accepted by `page.getByRole()`.
18
-
19
- ```ts
20
- locators.addSchema("content.button@edit", {
21
- role: "button",
22
- roleOptions: { name: "Edit" },
23
- locatorMethod: GetByMethod.role
24
- });
25
- ```
26
-
27
- Playwright equivalent:
28
-
29
- ```ts
30
- page.getByRole("button", { name: "Edit" });
31
- ```
32
-
33
- ### `text` and `textOptions`
34
-
35
- Match visible text using the same semantics as [`page.getByText()`](https://playwright.dev/docs/api/class-page#page-get-by-text).
36
-
37
- ```ts
38
- locators.addSchema("content.link.help", {
39
- text: "Need help?",
40
- textOptions: { exact: true },
41
- locatorMethod: GetByMethod.text
42
- });
43
- ```
44
-
45
- Playwright equivalent:
46
-
47
- ```ts
48
- page.getByText("Need help?", { exact: true });
49
- ```
50
-
51
- ### `label` and `labelOptions`
52
-
53
- Reference form controls by their accessible label. `labelOptions` accepts the same arguments as [`page.getByLabel()`](https://playwright.dev/docs/api/class-page#page-get-by-label).
54
-
55
- ```ts
56
- locators.addSchema("content.form.password", {
57
- label: "Password",
58
- locatorMethod: GetByMethod.label
59
- });
60
- ```
61
-
62
- Playwright equivalent:
63
-
64
- ```ts
65
- page.getByLabel("Password");
66
- ```
67
-
68
- ### `placeholder` and `placeholderOptions`
69
-
70
- Target elements by placeholder text via [`page.getByPlaceholder()`](https://playwright.dev/docs/api/class-page#page-get-by-placeholder).
71
-
72
- ```ts
73
- locators.addSchema("content.form.search", {
74
- placeholder: "Search",
75
- placeholderOptions: { exact: true },
76
- locatorMethod: GetByMethod.placeholder
77
- });
78
- ```
79
-
80
- Playwright equivalent:
81
-
82
- ```ts
83
- page.getByPlaceholder("Search", { exact: true });
84
- ```
85
-
86
- ### `altText` and `altTextOptions`
87
-
88
- Resolve images and other elements with alternative text via [`page.getByAltText()`](https://playwright.dev/docs/api/class-page#page-get-by-alt-text).
89
-
90
- ```ts
91
- locators.addSchema("content.hero.image", {
92
- altText: "Company logo",
93
- locatorMethod: GetByMethod.altText
94
- });
95
- ```
96
-
97
- Playwright equivalent:
98
-
99
- ```ts
100
- page.getByAltText("Company logo");
101
- ```
102
-
103
- ### `title` and `titleOptions`
104
-
105
- Tap into the [`title` attribute](https://playwright.dev/docs/api/class-page#page-get-by-title) of an element.
106
-
107
- ```ts
108
- locators.addSchema("content.tooltip.info", {
109
- title: "More information",
110
- locatorMethod: GetByMethod.title
111
- });
112
- ```
113
-
114
- Playwright equivalent:
115
-
116
- ```ts
117
- page.getByTitle("More information");
118
- ```
119
-
120
- ### `locator` and `locatorOptions`
121
-
122
- Fallback to raw selectors or locator chaining with [`page.locator()`](https://playwright.dev/docs/api/class-page#page-locator). `locatorOptions` is passed straight through to the Playwright call.
123
-
124
- ```ts
125
- locators.addSchema("content.main", {
126
- locator: "main",
127
- locatorOptions: { hasText: "Profile" },
128
- locatorMethod: GetByMethod.locator
129
- });
130
- ```
131
-
132
- Playwright equivalent:
133
-
134
- ```ts
135
- page.locator("main", { hasText: "Profile" });
136
- ```
137
-
138
- ### `frameLocator`
139
-
140
- Create [`FrameLocator`](https://playwright.dev/docs/api/class-page#page-frame-locator) instances when your DOM interaction starts inside an iframe.
141
-
142
- ```ts
143
- locators.addSchema("iframe.login", {
144
- frameLocator: "#auth-frame",
145
- locatorMethod: GetByMethod.frameLocator
146
- });
147
- ```
148
-
149
- Playwright equivalent:
150
-
151
- ```ts
152
- page.frameLocator("#auth-frame");
153
- ```
154
-
155
- ### `testId`
156
-
157
- Call [`page.getByTestId()`](https://playwright.dev/docs/api/class-page#page-get-by-test-id) by setting the `testId` field.
158
-
159
- ```ts
160
- locators.addSchema("content.button.reset", {
161
- testId: "reset-btn",
162
- locatorMethod: GetByMethod.testId
163
- });
164
- ```
165
-
166
- Playwright equivalent:
167
-
168
- ```ts
169
- page.getByTestId("reset-btn");
170
- ```
171
-
172
- ### `dataCy`
173
-
174
- `dataCy` is a POMWright convenience for the legacy `data-cy` attribute used in Cypress-based projects. Under the hood it still calls `page.locator()` with the [`data-cy=` selector engine](https://playwright.dev/docs/extensibility#custom-selector-engines) registered by `BasePage`.
175
-
176
- ```ts
177
- locators.addSchema("content.card.actions", {
178
- dataCy: "card-actions",
179
- locatorMethod: GetByMethod.dataCy
180
- });
181
- ```
182
-
183
- Playwright equivalent:
184
-
185
- ```ts
186
- page.locator("data-cy=card-actions");
187
- ```
188
-
189
- If you prefer to control the selector string yourself you can pass the full expression (`"data-cy=card-actions"`) and it will be used verbatim.
190
-
191
- ### `id`
192
-
193
- `id` is the second POMWright-specific helper. Provide either the raw id string or a `RegExp`. Strings are normalised to CSS id selectors, so `"details"`, `"#details"`, and `"id=details"` all resolve to the same element. A regular expression matches the start of the `id` attribute, allowing you to capture generated identifiers.
194
-
195
- ```ts
196
- locators.addSchema("content.region.details", {
197
- id: "profile-details",
198
- locatorMethod: GetByMethod.id
199
- });
200
-
201
- locators.addSchema("content.region.dynamic", {
202
- id: /^region-/,
203
- locatorMethod: GetByMethod.id
204
- });
205
- ```
206
-
207
- Playwright equivalent:
208
-
209
- ```ts
210
- page.locator("#profile-details");
211
- page.locator('*[id^="region-"]');
212
- ```
213
-
214
- ### `filter`
215
-
216
- Any schema can define a `filter` object with the same shape as [`locator.filter()`](https://playwright.dev/docs/api/class-locator#locator-filter). Filters are applied immediately after the initial Playwright locator is created.
217
-
218
- ```ts
219
- locators.addSchema("content.list.item", {
220
- role: "listitem",
221
- locatorMethod: GetByMethod.role,
222
- filter: { hasText: /Primary Colors/i }
223
- });
224
- ```
225
-
226
- Playwright equivalent:
227
-
228
- ```ts
229
- page.getByRole("listitem").filter({ hasText: /Primary Colors/i });
230
- ```
231
-
232
- ## Putting it together
233
-
234
- Schemas are typically registered inside `initLocatorSchemas()` of a `BasePage` subclass. The example below demonstrates reusable fragments and multiple selector strategies working together.
235
-
236
- ```ts
237
- import { GetByMethod, type GetLocatorBase, type LocatorSchemaWithoutPath } from "pomwright";
238
- type LocatorSchemaPath =
239
- | "main"
240
- | "main.button"
241
- | "main.button@continue"
242
- | "main.button@back";
243
-
244
- export function initLocatorSchemas(locators: GetLocatorBase<LocatorSchemaPath>) {
245
- locators.addSchema("main", {
246
- locator: "main",
247
- locatorMethod: GetByMethod.locator
248
- });
249
-
250
- const button: LocatorSchemaWithoutPath = {
251
- role: "button",
252
- locatorMethod: GetByMethod.role
253
- };
254
-
255
- locators.addSchema("main.button", {
256
- ...button
257
- });
258
-
259
- locators.addSchema("main.button@continue", {
260
- ...button,
261
- roleOptions: { name: "Continue" }
262
- });
263
-
264
- locators.addSchema("main.button@back", {
265
- ...button,
266
- roleOptions: { name: "Back" }
267
- });
268
- }
269
- ```
270
-
271
- Once registered, the schemas can be consumed through the BasePage helpers documented in [`docs/get-locator-methods-explanation.md`](./get-locator-methods-explanation.md).
@@ -1,165 +0,0 @@
1
- # LocatorSchemaPath
2
-
3
- A `LocatorSchemaPath` is the unique key that identifies a `LocatorSchema`. Paths let POMWright build nested Playwright locators while keeping the definitions type‑safe and searchable.
4
-
5
- ## Path syntax
6
-
7
- A `LocatorSchemaPath` is declared as a union of string literals.
8
-
9
- ```ts
10
- type LocatorSchemaPath = "main";
11
- ```
12
-
13
- Each word or segment of a string are separated by `.` (dot), where each dot represents a new element in the chain. Thus we end up with paths describing the hierarchy of elements on a page through dot notation.
14
-
15
- ```ts
16
- type LocatorSchemaPath =
17
- | "main"
18
- | "main.heading";
19
- ```
20
-
21
- In other words, each `.` (dot) separates a new segment in the chain. A LocatorSchemaPath string:
22
-
23
- - Cannot be empty.
24
- - The string cannot start or end with `.`.
25
- - The string cannot contain consecutive dots.
26
-
27
- A path must start and end with a "word", a word is any combination of characters except `.` (dot). The following paths will throw during runtime:
28
-
29
- ```ts
30
- // These throw at runtime
31
- type LocatorSchemaPath =
32
- | "" // empty string
33
- | ".main" // starting with a dot
34
- | "main." // ending with a dot
35
- | "main..heading" // consecutive dots
36
- ```
37
-
38
- Every path represents a chain of locators that describe the hierarchy of elements on the page. POMWright enforces uniqueness, so registering the same path twice causes fixture initialisation to fail before any test using them can runs.
39
-
40
- ```ts
41
- import { GetByMethod, type GetLocatorBase } from "pomwright";
42
-
43
- export type LocatorSchemaPath =
44
- | "main"
45
- | "main.heading";
46
-
47
- export function initLocatorSchemas(locators: GetLocatorBase<LocatorSchemaPath>) {
48
- locators.addSchema("main.heading", { /* ... */ });
49
- locators.addSchema("main.heading", { /* ... */ }); // duplicate – throws
50
- }
51
- ```
52
-
53
- ## Referencing schemas
54
-
55
- Each path declared in the type must be implemented with `addSchema` inside `initLocatorSchemas`. Missing implementations raise a `not implemented` error when the fixtures are created, helping you catch mistakes early.
56
-
57
- Locator paths can be shared across Page Object Classes by re‑exporting the union of strings:
58
-
59
- ```ts
60
- import { GetByMethod, type GetLocatorBase } from "pomwright";
61
- import {
62
- type LocatorSchemaPath as common,
63
- initLocatorSchemas as initCommon
64
- } from "../page-components/common.locatorSchema";
65
-
66
- export type LocatorSchemaPath =
67
- | common
68
- | "main.heading";
69
-
70
- export function initLocatorSchemas(locators: GetLocatorBase<LocatorSchemaPath>) {
71
- initCommon(locators);
72
-
73
- locators.addSchema("main.heading", {
74
- role: "heading",
75
- roleOptions: { name: "Welcome!" },
76
- locatorMethod: GetByMethod.role
77
- });
78
- }
79
- ```
80
-
81
- ## Descriptive segments
82
-
83
- A path may include segments that exist purely for readability. POMWright skips any missing intermediate keys when chaining the locator.
84
-
85
- ```ts
86
- import { GetByMethod, type GetLocatorBase } from "pomwright";
87
-
88
- type LocatorSchemaPath =
89
- | "main"
90
- | "main.button.continue"; // "button" communicates intent
91
-
92
- export function initLocatorSchemas(locators: GetLocatorBase<LocatorSchemaPath>) {
93
-
94
- locators.addSchema("main", {
95
- locator: "main",
96
- locatorMethod: GetByMethod.locator
97
- });
98
-
99
- locators.addSchema("main.button.continue", {
100
- role: "button",
101
- roleOptions: { name: "Continue" },
102
- locatorMethod: GetByMethod.role
103
- });
104
- }
105
- ```
106
-
107
- You can also suffix segments with a friendly name using `@`. POMWright treats `@` like any other character—it simply improves readability for humans. You're free to use any special character to improve readability.
108
-
109
- ```ts
110
- import { GetByMethod, type GetLocatorBase, type LocatorSchemaWithoutPath } from "pomwright";
111
-
112
- type LocatorSchemaPath =
113
- | "main"
114
- | "main.button"
115
- | "main.button@continue"
116
- | "main.button@back"; // "button" is here used for human context
117
-
118
- export function initLocatorSchemas(locators: GetLocatorBase<LocatorSchemaPath>) {
119
-
120
- locators.addSchema("main", {
121
- locator: "main",
122
- locatorMethod: GetByMethod.locator
123
- });
124
-
125
- const button: LocatorSchemaWithoutPath = {
126
- role: "button",
127
- locatorMethod: GetByMethod.role
128
- }
129
-
130
- locators.addSchema("main.button", {
131
- ...button,
132
- });
133
-
134
- locators.addSchema("main.button@continue", {
135
- ...button,
136
- roleOptions: { name: "Continue" }
137
- });
138
-
139
- locators.addSchema("main.button@back", {
140
- ...button,
141
- roleOptions: { name: "Back" }
142
- });
143
- }
144
- ```
145
-
146
- > Use something like `main.button` when you need a broad locator (for example, to count buttons) and `main.button@continue` or `main.button@back` when you need a specific instance.
147
-
148
- The portion before `@` usually describes the element type (`section`, `button`), while the part after `@` is a friendly identifier (`playground`, `reset`). This makes long chains readable while still conveying intent.
149
-
150
- > **Note:** There is nothing special about the character `@`, in the eyes of POMWright it's just another character in a word. The only "special" character is `.` dot.
151
-
152
- Remember: the goal is not to mirror the DOM structure 1:1. Just enough to ensure a descriptive and unique path to the elements you interact with and validate through the use of simple Locators.
153
-
154
- ## LocatorSchemaPath, Sub-paths and IntelliSense
155
-
156
- Every dot‑delimited segment forms a sub path. Sub paths power IntelliSense and let you scope updates or filters to a specific part of the chain.
157
-
158
- ```ts
159
- const resetBtn = await profile
160
- .getLocatorSchema("body.section@playground.button@reset")
161
- .addFilter("body.section@playground", { hasText: /Primary Colors/i })
162
- .getNestedLocator();
163
- ```
164
-
165
- The TypeScript union of all paths enables autocomplete, prevents typos, and makes refactors simple. Update a single `LocatorSchema` definition and every test using that path immediately benefits from the change.