pomwright 1.2.0 → 1.3.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/dist/index.js CHANGED
@@ -18,8 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
20
  // index.ts
21
- var POMWright_exports = {};
22
- __export(POMWright_exports, {
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
23
  BaseApi: () => BaseApi,
24
24
  BasePage: () => BasePage,
25
25
  GetByMethod: () => GetByMethod,
@@ -27,7 +27,7 @@ __export(POMWright_exports, {
27
27
  PlaywrightReportLogger: () => PlaywrightReportLogger,
28
28
  test: () => test3
29
29
  });
30
- module.exports = __toCommonJS(POMWright_exports);
30
+ module.exports = __toCommonJS(index_exports);
31
31
 
32
32
  // src/basePage.ts
33
33
  var import_test3 = require("@playwright/test");
@@ -427,6 +427,11 @@ var GetLocatorBase = class {
427
427
  * Throws an error if a schema already exists at that path.
428
428
  */
429
429
  addSchema(locatorSchemaPath, schemaDetails) {
430
+ if (locatorSchemaPath.length === 0 || locatorSchemaPath.startsWith(".") || locatorSchemaPath.endsWith(".") || locatorSchemaPath.includes("..")) {
431
+ throw new Error(
432
+ `[${this.pageObjectClass.pocName}] Invalid LocatorSchemaPath '${locatorSchemaPath}'. LocatorSchemaPath must not be empty, start or end with a '.', or contain consecutive '.'.`
433
+ );
434
+ }
430
435
  const newLocatorSchema = this.createLocatorSchema(schemaDetails, locatorSchemaPath);
431
436
  const existingSchemaFunc = this.safeGetLocatorSchema(locatorSchemaPath);
432
437
  if (existingSchemaFunc) {
@@ -807,7 +812,7 @@ var SessionStorage = class {
807
812
  const item = sessionStorage.getItem(key);
808
813
  try {
809
814
  storage[key] = item ? JSON.parse(item) : null;
810
- } catch (e) {
815
+ } catch (_e) {
811
816
  storage[key] = item;
812
817
  }
813
818
  }
@@ -857,7 +862,7 @@ var SessionStorage = class {
857
862
  contextExists = await this.page.evaluate(() => {
858
863
  return typeof window !== "undefined" && window.sessionStorage !== void 0;
859
864
  });
860
- } catch (e) {
865
+ } catch (_e) {
861
866
  contextExists = false;
862
867
  }
863
868
  if (contextExists) {
@@ -888,7 +893,7 @@ var SessionStorage = class {
888
893
  const allData = await this.readFromSessionStorage();
889
894
  if (keys && keys.length > 0) {
890
895
  for (const key of keys) {
891
- if (Object.prototype.hasOwnProperty.call(allData, key)) {
896
+ if (Object.hasOwn(allData, key)) {
892
897
  result[key] = allData[key];
893
898
  }
894
899
  }
@@ -1000,7 +1005,7 @@ var BasePage = class {
1000
1005
  * Ensures a flexible approach to URL matching (string or regex-based).
1001
1006
  */
1002
1007
  constructFullUrl(baseUrl, urlPath) {
1003
- const escapeStringForRegExp = (str) => str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
1008
+ const escapeStringForRegExp = (str) => str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
1004
1009
  if (typeof baseUrl === "string" && typeof urlPath === "string") {
1005
1010
  return `${baseUrl}${urlPath}`;
1006
1011
  }
@@ -1234,7 +1239,7 @@ ${args.join("\n\n")}`
1234
1239
  const parsedMessage = JSON.parse(log.message);
1235
1240
  messageContentType = "application/json";
1236
1241
  messageBody = JSON.stringify(parsedMessage, null, 2);
1237
- } catch (error) {
1242
+ } catch (_error) {
1238
1243
  messageContentType = "text/plain";
1239
1244
  messageBody = log.message;
1240
1245
  }
package/dist/index.mjs CHANGED
@@ -396,6 +396,11 @@ var GetLocatorBase = class {
396
396
  * Throws an error if a schema already exists at that path.
397
397
  */
398
398
  addSchema(locatorSchemaPath, schemaDetails) {
399
+ if (locatorSchemaPath.length === 0 || locatorSchemaPath.startsWith(".") || locatorSchemaPath.endsWith(".") || locatorSchemaPath.includes("..")) {
400
+ throw new Error(
401
+ `[${this.pageObjectClass.pocName}] Invalid LocatorSchemaPath '${locatorSchemaPath}'. LocatorSchemaPath must not be empty, start or end with a '.', or contain consecutive '.'.`
402
+ );
403
+ }
399
404
  const newLocatorSchema = this.createLocatorSchema(schemaDetails, locatorSchemaPath);
400
405
  const existingSchemaFunc = this.safeGetLocatorSchema(locatorSchemaPath);
401
406
  if (existingSchemaFunc) {
@@ -776,7 +781,7 @@ var SessionStorage = class {
776
781
  const item = sessionStorage.getItem(key);
777
782
  try {
778
783
  storage[key] = item ? JSON.parse(item) : null;
779
- } catch (e) {
784
+ } catch (_e) {
780
785
  storage[key] = item;
781
786
  }
782
787
  }
@@ -826,7 +831,7 @@ var SessionStorage = class {
826
831
  contextExists = await this.page.evaluate(() => {
827
832
  return typeof window !== "undefined" && window.sessionStorage !== void 0;
828
833
  });
829
- } catch (e) {
834
+ } catch (_e) {
830
835
  contextExists = false;
831
836
  }
832
837
  if (contextExists) {
@@ -857,7 +862,7 @@ var SessionStorage = class {
857
862
  const allData = await this.readFromSessionStorage();
858
863
  if (keys && keys.length > 0) {
859
864
  for (const key of keys) {
860
- if (Object.prototype.hasOwnProperty.call(allData, key)) {
865
+ if (Object.hasOwn(allData, key)) {
861
866
  result[key] = allData[key];
862
867
  }
863
868
  }
@@ -969,7 +974,7 @@ var BasePage = class {
969
974
  * Ensures a flexible approach to URL matching (string or regex-based).
970
975
  */
971
976
  constructFullUrl(baseUrl, urlPath) {
972
- const escapeStringForRegExp = (str) => str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
977
+ const escapeStringForRegExp = (str) => str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
973
978
  if (typeof baseUrl === "string" && typeof urlPath === "string") {
974
979
  return `${baseUrl}${urlPath}`;
975
980
  }
@@ -1203,7 +1208,7 @@ ${args.join("\n\n")}`
1203
1208
  const parsedMessage = JSON.parse(log.message);
1204
1209
  messageContentType = "application/json";
1205
1210
  messageBody = JSON.stringify(parsedMessage, null, 2);
1206
- } catch (error) {
1211
+ } catch (_error) {
1207
1212
  messageContentType = "text/plain";
1208
1213
  messageBody = log.message;
1209
1214
  }
@@ -0,0 +1,63 @@
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.
@@ -0,0 +1,96 @@
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)
@@ -0,0 +1,271 @@
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).