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,602 +0,0 @@
1
- import type { Page } from "@playwright/test";
2
- import type { LocatorQueryBuilder } from "./locatorQueryBuilder";
3
- import type {
4
- LocatorChainPaths,
5
- LocatorStrategyDefinition,
6
- LocatorUpdate,
7
- RegistryPath,
8
- RoleDefinition,
9
- } from "./types";
10
- import { normalizeIdValue } from "./utils";
11
-
12
- const parseUpdateArguments = <Primary, OptionsType>(
13
- primaryOrOptions?: Primary | OptionsType,
14
- options?: OptionsType,
15
- optionsProvided?: boolean,
16
- ) => {
17
- let primary: Primary | undefined;
18
- let parsedOptions: OptionsType | undefined;
19
- let hasOptions = optionsProvided ?? false;
20
-
21
- if (options !== undefined) {
22
- parsedOptions = options;
23
- hasOptions = true;
24
- }
25
-
26
- if (primaryOrOptions !== undefined) {
27
- const treatAsOptions =
28
- !hasOptions &&
29
- options === undefined &&
30
- typeof primaryOrOptions === "object" &&
31
- !(primaryOrOptions instanceof RegExp);
32
-
33
- if (treatAsOptions) {
34
- parsedOptions = primaryOrOptions as OptionsType;
35
- hasOptions = true;
36
- } else {
37
- primary = primaryOrOptions as Primary;
38
- }
39
- }
40
-
41
- return { primary, options: parsedOptions, hasOptions };
42
- };
43
-
44
- const mergeOptions = <OptionsType>(
45
- currentOptions: OptionsType | undefined,
46
- updates: { options?: OptionsType } | undefined,
47
- ) => {
48
- if (updates && "options" in updates) {
49
- const updateOptions = updates.options;
50
- if (updateOptions && typeof updateOptions === "object") {
51
- return {
52
- ...(typeof currentOptions === "object" && currentOptions !== null ? currentOptions : {}),
53
- ...updateOptions,
54
- } as OptionsType;
55
- }
56
- return updateOptions as OptionsType;
57
- }
58
-
59
- return currentOptions as OptionsType;
60
- };
61
-
62
- type UpdateArgsWithOptions<Primary, Options> = [] | [Primary] | [Options] | [Primary, Options];
63
-
64
- type UpdateArgsWithoutOptions<Primary> = [] | [Primary];
65
-
66
- const mergeLocatorDefinition = (
67
- current: LocatorStrategyDefinition,
68
- updates: LocatorUpdate,
69
- path: string,
70
- preferredSource?: LocatorStrategyDefinition,
71
- baseline?: LocatorStrategyDefinition,
72
- ): LocatorStrategyDefinition => {
73
- if (!updates || typeof updates !== "object" || !("type" in updates)) {
74
- throw new Error(`Locator update for "${path}" requires a "type" property.`);
75
- }
76
-
77
- const source = <TType extends LocatorStrategyDefinition["type"]>(targetType: TType) => {
78
- if (current.type === targetType) {
79
- return current as Extract<LocatorStrategyDefinition, { type: TType }>;
80
- }
81
- if (preferredSource?.type === targetType) {
82
- return preferredSource as Extract<LocatorStrategyDefinition, { type: TType }>;
83
- }
84
- if (baseline?.type === targetType) {
85
- return baseline as Extract<LocatorStrategyDefinition, { type: TType }>;
86
- }
87
- return undefined;
88
- };
89
-
90
- switch (updates.type) {
91
- case "role": {
92
- const roleSource = source("role");
93
- const role = updates.role ?? roleSource?.role;
94
- if (role === undefined) {
95
- throw new Error(`Locator update for "${path}" of type "role" requires a "role" value.`);
96
- }
97
- const options = mergeOptions(roleSource?.options, updates);
98
- return options !== undefined
99
- ? ({ type: "role", role, options } as RoleDefinition)
100
- : ({ type: "role", role } as RoleDefinition);
101
- }
102
- case "text": {
103
- const textSource = source("text");
104
- const text = updates.text ?? textSource?.text;
105
- if (text === undefined) {
106
- throw new Error(`Locator update for "${path}" of type "text" requires a "text" value.`);
107
- }
108
- const options = mergeOptions(textSource?.options, updates);
109
- return options !== undefined
110
- ? ({ type: "text", text, options } as LocatorStrategyDefinition)
111
- : ({ type: "text", text } as LocatorStrategyDefinition);
112
- }
113
- case "label": {
114
- const textSource = source("label");
115
- const text = updates.text ?? textSource?.text;
116
- if (text === undefined) {
117
- throw new Error(`Locator update for "${path}" of type "label" requires a "text" value.`);
118
- }
119
- const options = mergeOptions(textSource?.options, updates);
120
- return options !== undefined
121
- ? ({ type: "label", text, options } as LocatorStrategyDefinition)
122
- : ({ type: "label", text } as LocatorStrategyDefinition);
123
- }
124
- case "placeholder": {
125
- const textSource = source("placeholder");
126
- const text = updates.text ?? textSource?.text;
127
- if (text === undefined) {
128
- throw new Error(`Locator update for "${path}" of type "placeholder" requires a "text" value.`);
129
- }
130
- const options = mergeOptions(textSource?.options, updates);
131
- return options !== undefined
132
- ? ({ type: "placeholder", text, options } as LocatorStrategyDefinition)
133
- : ({ type: "placeholder", text } as LocatorStrategyDefinition);
134
- }
135
- case "altText": {
136
- const textSource = source("altText");
137
- const text = updates.text ?? textSource?.text;
138
- if (text === undefined) {
139
- throw new Error(`Locator update for "${path}" of type "altText" requires a "text" value.`);
140
- }
141
- const options = mergeOptions(textSource?.options, updates);
142
- return options !== undefined
143
- ? ({ type: "altText", text, options } as LocatorStrategyDefinition)
144
- : ({ type: "altText", text } as LocatorStrategyDefinition);
145
- }
146
- case "title": {
147
- const textSource = source("title");
148
- const text = updates.text ?? textSource?.text;
149
- if (text === undefined) {
150
- throw new Error(`Locator update for "${path}" of type "title" requires a "text" value.`);
151
- }
152
- const options = mergeOptions(textSource?.options, updates);
153
- return options !== undefined
154
- ? ({ type: "title", text, options } as LocatorStrategyDefinition)
155
- : ({ type: "title", text } as LocatorStrategyDefinition);
156
- }
157
- case "locator": {
158
- const selectorSource = source("locator");
159
- const selector = updates.selector ?? selectorSource?.selector;
160
- if (selector === undefined) {
161
- throw new Error(`Locator update for "${path}" of type "locator" requires a "selector" value.`);
162
- }
163
- const options = mergeOptions(selectorSource?.options, updates);
164
- return options !== undefined
165
- ? ({ type: "locator", selector, options } as LocatorStrategyDefinition)
166
- : ({ type: "locator", selector } as LocatorStrategyDefinition);
167
- }
168
- case "frameLocator": {
169
- const selectorSource = source("frameLocator");
170
- const selector = updates.selector ?? selectorSource?.selector;
171
- if (selector === undefined) {
172
- throw new Error(`Locator update for "${path}" of type "frameLocator" requires a "selector" value.`);
173
- }
174
- return { type: "frameLocator", selector } as LocatorStrategyDefinition;
175
- }
176
- case "testId": {
177
- const testIdSource = source("testId");
178
- const testId = updates.testId ?? testIdSource?.testId;
179
- if (testId === undefined) {
180
- throw new Error(`Locator update for "${path}" of type "testId" requires a "testId" value.`);
181
- }
182
- return { type: "testId", testId } as LocatorStrategyDefinition;
183
- }
184
- case "id": {
185
- const idSource = source("id");
186
- const rawId = updates.id ?? idSource?.id;
187
- const id = normalizeIdValue(rawId);
188
- if (id === undefined) {
189
- throw new Error(`Locator update for "${path}" of type "id" requires an "id" value.`);
190
- }
191
- return { type: "id", id } as LocatorStrategyDefinition;
192
- }
193
- default: {
194
- const exhaustive: never = updates;
195
- return exhaustive;
196
- }
197
- }
198
- };
199
-
200
- const buildReplacementDefinition = (updates: LocatorUpdate, path: string): LocatorStrategyDefinition => {
201
- if (!updates || typeof updates !== "object" || !("type" in updates)) {
202
- throw new Error(`Locator replace for "${path}" requires a "type" property.`);
203
- }
204
-
205
- switch (updates.type) {
206
- case "role": {
207
- const { role, options } = updates;
208
- if (role === undefined) {
209
- throw new Error(`Locator replace for "${path}" of type "role" requires a "role" value.`);
210
- }
211
- return options !== undefined
212
- ? ({ type: "role", role, options } as RoleDefinition)
213
- : ({ type: "role", role } as RoleDefinition);
214
- }
215
- case "text": {
216
- const { text, options } = updates;
217
- if (text === undefined) {
218
- throw new Error(`Locator replace for "${path}" of type "text" requires a "text" value.`);
219
- }
220
- return options !== undefined
221
- ? ({ type: "text", text, options } as LocatorStrategyDefinition)
222
- : ({ type: "text", text } as LocatorStrategyDefinition);
223
- }
224
- case "label": {
225
- const { text, options } = updates;
226
- if (text === undefined) {
227
- throw new Error(`Locator replace for "${path}" of type "label" requires a "text" value.`);
228
- }
229
- return options !== undefined
230
- ? ({ type: "label", text, options } as LocatorStrategyDefinition)
231
- : ({ type: "label", text } as LocatorStrategyDefinition);
232
- }
233
- case "placeholder": {
234
- const { text, options } = updates;
235
- if (text === undefined) {
236
- throw new Error(`Locator replace for "${path}" of type "placeholder" requires a "text" value.`);
237
- }
238
- return options !== undefined
239
- ? ({ type: "placeholder", text, options } as LocatorStrategyDefinition)
240
- : ({ type: "placeholder", text } as LocatorStrategyDefinition);
241
- }
242
- case "altText": {
243
- const { text, options } = updates;
244
- if (text === undefined) {
245
- throw new Error(`Locator replace for "${path}" of type "altText" requires a "text" value.`);
246
- }
247
- return options !== undefined
248
- ? ({ type: "altText", text, options } as LocatorStrategyDefinition)
249
- : ({ type: "altText", text } as LocatorStrategyDefinition);
250
- }
251
- case "title": {
252
- const { text, options } = updates;
253
- if (text === undefined) {
254
- throw new Error(`Locator replace for "${path}" of type "title" requires a "text" value.`);
255
- }
256
- return options !== undefined
257
- ? ({ type: "title", text, options } as LocatorStrategyDefinition)
258
- : ({ type: "title", text } as LocatorStrategyDefinition);
259
- }
260
- case "locator": {
261
- const { selector, options } = updates;
262
- if (selector === undefined) {
263
- throw new Error(`Locator replace for "${path}" of type "locator" requires a "selector" value.`);
264
- }
265
- return options !== undefined
266
- ? ({ type: "locator", selector, options } as LocatorStrategyDefinition)
267
- : ({ type: "locator", selector } as LocatorStrategyDefinition);
268
- }
269
- case "frameLocator": {
270
- const { selector } = updates;
271
- if (selector === undefined) {
272
- throw new Error(`Locator replace for "${path}" of type "frameLocator" requires a "selector" value.`);
273
- }
274
- return { type: "frameLocator", selector } as LocatorStrategyDefinition;
275
- }
276
- case "testId": {
277
- const { testId } = updates;
278
- if (testId === undefined) {
279
- throw new Error(`Locator replace for "${path}" of type "testId" requires a "testId" value.`);
280
- }
281
- return { type: "testId", testId } as LocatorStrategyDefinition;
282
- }
283
- case "id": {
284
- const rawId = updates.id;
285
- const id = normalizeIdValue(rawId);
286
- if (id === undefined) {
287
- throw new Error(`Locator replace for "${path}" of type "id" requires an "id" value.`);
288
- }
289
- return { type: "id", id } as LocatorStrategyDefinition;
290
- }
291
- default: {
292
- const exhaustive: never = updates;
293
- return exhaustive;
294
- }
295
- }
296
- };
297
- export class LocatorUpdateBuilder<
298
- LocatorSchemaPathType extends string,
299
- LocatorSubstring extends RegistryPath<LocatorSchemaPathType>,
300
- SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>,
301
- > {
302
- constructor(
303
- private readonly parent: LocatorQueryBuilder<LocatorSchemaPathType, LocatorSubstring>,
304
- private readonly subPath: SubPath,
305
- private readonly mode: "update" | "replace" = "update",
306
- ) {}
307
-
308
- /**
309
- * Defines or patches a `getByRole` locator strategy for the target subpath. In `update` mode the
310
- * `role` and `options` arguments are optional (PATCH semantics); in `replace` mode they follow
311
- * Playwright requirements (POST semantics) and `role` is required.
312
- *
313
- * @example
314
- * ```ts
315
- * getLocatorSchema("form.button")
316
- * .update("form.button")
317
- * .getByRole({ name: "Save" })
318
- * .getNestedLocator();
319
- * ```
320
- */
321
- getByRole(...args: UpdateArgsWithOptions<RoleDefinition["role"], RoleDefinition["options"]>) {
322
- const [roleOrOptions, options] = args;
323
- const {
324
- primary: role,
325
- options: parsedOptions,
326
- hasOptions,
327
- } = parseUpdateArguments<RoleDefinition["role"], RoleDefinition["options"]>(
328
- roleOrOptions,
329
- options,
330
- args.length >= 2,
331
- );
332
-
333
- const definition: LocatorUpdate = {
334
- type: "role",
335
- ...(role !== undefined ? { role } : {}),
336
- ...(hasOptions ? { options: parsedOptions } : {}),
337
- };
338
-
339
- return this.commit(definition);
340
- }
341
-
342
- /**
343
- * Defines or patches a `getByText` locator strategy for the target subpath. In `update` mode,
344
- * text/options are optional; in `replace` mode text is required.
345
- *
346
- * @example
347
- * ```ts
348
- * getLocatorSchema("banner.message")
349
- * .replace("banner.message")
350
- * .getByText(/Updated/, { exact: false })
351
- * .getNestedLocator();
352
- * ```
353
- */
354
- getByText(...args: UpdateArgsWithOptions<Parameters<Page["getByText"]>[0], Parameters<Page["getByText"]>[1]>) {
355
- const [textOrOptions, options] = args;
356
- const {
357
- primary: text,
358
- options: parsedOptions,
359
- hasOptions,
360
- } = parseUpdateArguments<Parameters<Page["getByText"]>[0], Parameters<Page["getByText"]>[1]>(
361
- textOrOptions,
362
- options,
363
- args.length >= 2,
364
- );
365
-
366
- const definition: LocatorUpdate = {
367
- type: "text",
368
- ...(text !== undefined ? { text } : {}),
369
- ...(hasOptions ? { options: parsedOptions } : {}),
370
- };
371
-
372
- return this.commit(definition);
373
- }
374
-
375
- /**
376
- * Defines or patches a `getByLabel` locator strategy for the target subpath. In `update` mode the
377
- * label text/options are optional; in `replace` mode text is required.
378
- *
379
- * @example
380
- * ```ts
381
- * getLocatorSchema("form.email").update("form.email").getByLabel({ exact: true }).getNestedLocator();
382
- * ```
383
- */
384
- getByLabel(...args: UpdateArgsWithOptions<Parameters<Page["getByLabel"]>[0], Parameters<Page["getByLabel"]>[1]>) {
385
- const [textOrOptions, options] = args;
386
- const {
387
- primary: text,
388
- options: parsedOptions,
389
- hasOptions,
390
- } = parseUpdateArguments<Parameters<Page["getByLabel"]>[0], Parameters<Page["getByLabel"]>[1]>(
391
- textOrOptions,
392
- options,
393
- args.length >= 2,
394
- );
395
-
396
- const definition: LocatorUpdate = {
397
- type: "label",
398
- ...(text !== undefined ? { text } : {}),
399
- ...(hasOptions ? { options: parsedOptions } : {}),
400
- };
401
-
402
- return this.commit(definition);
403
- }
404
-
405
- /**
406
- * Defines or patches a `getByPlaceholder` locator strategy for the target subpath. In `update`
407
- * mode text/options are optional; in `replace` mode text is required.
408
- *
409
- * @example
410
- * ```ts
411
- * getLocatorSchema("form.search").update("form.search").getByPlaceholder({ exact: true }).getNestedLocator();
412
- * ```
413
- */
414
- getByPlaceholder(
415
- ...args: UpdateArgsWithOptions<Parameters<Page["getByPlaceholder"]>[0], Parameters<Page["getByPlaceholder"]>[1]>
416
- ) {
417
- const [textOrOptions, options] = args;
418
- const {
419
- primary: text,
420
- options: parsedOptions,
421
- hasOptions,
422
- } = parseUpdateArguments<Parameters<Page["getByPlaceholder"]>[0], Parameters<Page["getByPlaceholder"]>[1]>(
423
- textOrOptions,
424
- options,
425
- args.length >= 2,
426
- );
427
-
428
- const definition: LocatorUpdate = {
429
- type: "placeholder",
430
- ...(text !== undefined ? { text } : {}),
431
- ...(hasOptions ? { options: parsedOptions } : {}),
432
- };
433
-
434
- return this.commit(definition);
435
- }
436
-
437
- /**
438
- * Defines or patches a `getByAltText` locator strategy for the target subpath. In `update` mode
439
- * text/options are optional; in `replace` mode text is required.
440
- *
441
- * @example
442
- * ```ts
443
- * getLocatorSchema("image.logo").replace("image.logo").getByAltText("Logo").getNestedLocator();
444
- * ```
445
- */
446
- getByAltText(
447
- ...args: UpdateArgsWithOptions<Parameters<Page["getByAltText"]>[0], Parameters<Page["getByAltText"]>[1]>
448
- ) {
449
- const [textOrOptions, options] = args;
450
- const {
451
- primary: text,
452
- options: parsedOptions,
453
- hasOptions,
454
- } = parseUpdateArguments<Parameters<Page["getByAltText"]>[0], Parameters<Page["getByAltText"]>[1]>(
455
- textOrOptions,
456
- options,
457
- args.length >= 2,
458
- );
459
-
460
- const definition: LocatorUpdate = {
461
- type: "altText",
462
- ...(text !== undefined ? { text } : {}),
463
- ...(hasOptions ? { options: parsedOptions } : {}),
464
- };
465
-
466
- return this.commit(definition);
467
- }
468
-
469
- /**
470
- * Defines or patches a `getByTitle` locator strategy for the target subpath. In `update` mode
471
- * text/options are optional; in `replace` mode text is required.
472
- *
473
- * @example
474
- * ```ts
475
- * getLocatorSchema("icon.info").update("icon.info").getByTitle({ exact: true }).getNestedLocator();
476
- * ```
477
- */
478
- getByTitle(...args: UpdateArgsWithOptions<Parameters<Page["getByTitle"]>[0], Parameters<Page["getByTitle"]>[1]>) {
479
- const [textOrOptions, options] = args;
480
- const {
481
- primary: text,
482
- options: parsedOptions,
483
- hasOptions,
484
- } = parseUpdateArguments<Parameters<Page["getByTitle"]>[0], Parameters<Page["getByTitle"]>[1]>(
485
- textOrOptions,
486
- options,
487
- args.length >= 2,
488
- );
489
-
490
- const definition: LocatorUpdate = {
491
- type: "title",
492
- ...(text !== undefined ? { text } : {}),
493
- ...(hasOptions ? { options: parsedOptions } : {}),
494
- };
495
-
496
- return this.commit(definition);
497
- }
498
-
499
- /**
500
- * Defines or patches a `locator` strategy for the target subpath. In `update` mode selector and
501
- * options are optional and merge with the existing definition; in `replace` mode selector is
502
- * required.
503
- *
504
- * @example
505
- * ```ts
506
- * getLocatorSchema("list.items")
507
- * .replace("list.items")
508
- * .locator("ul > li", { hasText: /Row/ })
509
- * .getNestedLocator();
510
- * ```
511
- */
512
- locator(...args: UpdateArgsWithOptions<Parameters<Page["locator"]>[0], Parameters<Page["locator"]>[1]>) {
513
- const [selectorOrOptions, options] = args;
514
- const {
515
- primary: selector,
516
- options: parsedOptions,
517
- hasOptions,
518
- } = parseUpdateArguments<Parameters<Page["locator"]>[0], Parameters<Page["locator"]>[1]>(
519
- selectorOrOptions,
520
- options,
521
- args.length >= 2,
522
- );
523
-
524
- const definition: LocatorUpdate = {
525
- type: "locator",
526
- ...(selector !== undefined ? { selector } : {}),
527
- ...(hasOptions ? { options: parsedOptions } : {}),
528
- };
529
-
530
- return this.commit(definition);
531
- }
532
-
533
- /**
534
- * Defines or patches a `frameLocator` strategy for the target subpath. In `update` mode the
535
- * selector is optional and, when omitted, inherits the existing selector; in `replace` mode the
536
- * selector is required.
537
- *
538
- * @example
539
- * ```ts
540
- * getLocatorSchema("frame.login").replace("frame.login").frameLocator("iframe.auth").getNestedLocator();
541
- * ```
542
- */
543
- frameLocator(...args: UpdateArgsWithoutOptions<Parameters<Page["frameLocator"]>[0]>) {
544
- const [selector] = args;
545
-
546
- const definition: LocatorUpdate = {
547
- type: "frameLocator",
548
- ...(selector !== undefined ? { selector } : {}),
549
- };
550
-
551
- return this.commit(definition);
552
- }
553
-
554
- /**
555
- * Defines or patches a `getByTestId` locator strategy for the target subpath. In `update` mode
556
- * `testId` is optional and merges with existing options; in `replace` mode it is required.
557
- *
558
- * @example
559
- * ```ts
560
- * getLocatorSchema("card.title").update("card.title").getByTestId().getNestedLocator();
561
- * ```
562
- */
563
- getByTestId(...args: UpdateArgsWithoutOptions<Parameters<Page["getByTestId"]>[0]>) {
564
- const [testId] = args;
565
-
566
- const definition: LocatorUpdate = {
567
- type: "testId",
568
- ...(testId !== undefined ? { testId } : {}),
569
- };
570
-
571
- return this.commit(definition);
572
- }
573
-
574
- /**
575
- * Defines or patches an `id` locator strategy for the target subpath. In `update` mode the id is
576
- * optional and will be normalized if provided; in `replace` mode the id is required.
577
- *
578
- * @example
579
- * ```ts
580
- * getLocatorSchema("modal.close").update("modal.close").getById().getNestedLocator();
581
- * ```
582
- */
583
- getById(...args: UpdateArgsWithoutOptions<string | RegExp>) {
584
- const [idValue] = args;
585
- const id = idValue !== undefined ? normalizeIdValue(idValue) : undefined;
586
-
587
- const definition: LocatorUpdate = {
588
- type: "id",
589
- ...(id !== undefined ? { id } : {}),
590
- };
591
-
592
- return this.commit(definition);
593
- }
594
-
595
- private commit(definition: LocatorUpdate) {
596
- return this.mode === "replace"
597
- ? this.parent.applyReplacement(this.subPath, definition)
598
- : this.parent.applyUpdate(this.subPath, definition);
599
- }
600
- }
601
-
602
- export { buildReplacementDefinition, mergeLocatorDefinition };