pomwright 1.5.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +5 -5
- package/dist/index.d.mts +75 -970
- package/dist/index.d.ts +75 -970
- package/dist/index.js +585 -1872
- package/dist/index.mjs +598 -1880
- package/package.json +9 -11
- package/AGENTS.md +0 -37
- package/docs/v1/BaseApi-explanation.md +0 -63
- package/docs/v1/BasePage-explanation.md +0 -96
- package/docs/v1/LocatorSchema-explanation.md +0 -271
- package/docs/v1/LocatorSchemaPath-explanation.md +0 -165
- package/docs/v1/PlaywrightReportLogger-explanation.md +0 -56
- package/docs/v1/get-locator-methods-explanation.md +0 -250
- package/docs/v1/intro-to-using-pomwright.md +0 -899
- package/docs/v1/sessionStorage-methods-explanation.md +0 -38
- package/docs/v1/tips-folder-structure.md +0 -38
- package/docs/v1-to-v2-migration/bridge-migration-guide.md +0 -159
- package/docs/v1-to-v2-migration/direct-migration-guide.md +0 -238
- package/docs/v1-to-v2-migration/v1-to-v2-comparison.md +0 -547
- package/docs/v2/PageObject.md +0 -293
- package/docs/v2/composing-locator-modules.md +0 -93
- package/docs/v2/locator-registry.md +0 -695
- package/docs/v2/logging.md +0 -168
- package/docs/v2/overview.md +0 -515
- package/docs/v2/session-storage.md +0 -160
- package/index.ts +0 -75
- package/intTestV2/.env +0 -0
- package/intTestV2/fixtures/testApp.fixtures.ts +0 -43
- package/intTestV2/package.json +0 -22
- package/intTestV2/page-object-models/testApp/pages/iframe/iframe.locatorSchema.ts +0 -24
- package/intTestV2/page-object-models/testApp/pages/iframe/iframe.page.ts +0 -17
- package/intTestV2/page-object-models/testApp/pages/testPage.locatorSchema.ts +0 -32
- package/intTestV2/page-object-models/testApp/pages/testPage.page.ts +0 -119
- package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.locatorSchema.ts +0 -29
- package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.page.ts +0 -48
- package/intTestV2/page-object-models/testApp/pages/testPath/testPath.locatorSchema.ts +0 -9
- package/intTestV2/page-object-models/testApp/pages/testPath/testPath.page.ts +0 -23
- package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.locatorSchema.ts +0 -114
- package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.page.ts +0 -23
- package/intTestV2/page-object-models/testApp/testApp.base.ts +0 -20
- package/intTestV2/playwright.config.ts +0 -54
- package/intTestV2/server.js +0 -216
- package/intTestV2/test-data/staticPage/index.html +0 -280
- package/intTestV2/test-data/staticPage/w3images/avatar2.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar3.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar5.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar6.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/forest.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/lights.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/mountains.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/nature.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/snow.jpg +0 -0
- package/intTestV2/tests/locatorRegistry/add/add.describe.spec.ts +0 -54
- package/intTestV2/tests/locatorRegistry/add/add.filter.spec.ts +0 -143
- package/intTestV2/tests/locatorRegistry/add/add.frameLocator.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.get.clone.spec.ts +0 -76
- package/intTestV2/tests/locatorRegistry/add/add.getByAltText.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getById.spec.ts +0 -45
- package/intTestV2/tests/locatorRegistry/add/add.getByLabel.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByPlaceholder.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByRole.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByTestId.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByText.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByTitle.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.locator.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.reuseExisting.spec.ts +0 -107
- package/intTestV2/tests/locatorRegistry/add/add.reuseReusable.spec.ts +0 -311
- package/intTestV2/tests/locatorRegistry/add/add.spec.ts +0 -159
- package/intTestV2/tests/locatorRegistry/filter.cycle.spec.ts +0 -39
- package/intTestV2/tests/locatorRegistry/getLocator/getLocator.spec.ts +0 -253
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.clearSteps.spec.ts +0 -105
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.describe.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.filter.spec.ts +0 -368
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getLocator.spec.ts +0 -56
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getNestedLocator.spec.ts +0 -175
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.nth.spec.ts +0 -60
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.remove.spec.ts +0 -32
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.replace.spec.ts +0 -24
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.spec.ts +0 -110
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.update.spec.ts +0 -322
- package/intTestV2/tests/locatorRegistry/getNestedLocator/getNestedLocator.spec.ts +0 -412
- package/intTestV2/tests/locatorRegistry/registry/registry.binding.spec.ts +0 -50
- package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.spec.ts +0 -115
- package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.typecheck.ts +0 -86
- package/intTestV2/tests/locatorRegistry/validation/validation.sub-path.spec.ts +0 -45
- package/intTestV2/tests/step/step.spec.ts +0 -49
- package/intTestV2/tests/testApp/color.spec.ts +0 -15
- package/intTestV2/tests/testApp/iframe.spec.ts +0 -57
- package/intTestV2/tests/testApp/testFilters.spec.ts +0 -24
- package/intTestV2/tests/testApp/testPage.spec.ts +0 -161
- package/intTestV2/tests/testApp/testPath.spec.ts +0 -18
- package/pack-build.sh +0 -11
- package/pack-test-v2.sh +0 -36
- package/playwright.base.ts +0 -42
- package/skills/README.md +0 -56
- package/skills/pomwright-v1-5-bridge-migration/SKILL.md +0 -40
- package/skills/pomwright-v1-5-bridge-migration/references/call-site-migration.md +0 -178
- package/skills/pomwright-v1-5-bridge-migration/references/schema-translation.md +0 -183
- package/skills/pomwright-v2-migration/SKILL.md +0 -63
- package/skills/pomwright-v2-migration/references/call-site-migration.md +0 -265
- package/skills/pomwright-v2-migration/references/class-migration.md +0 -266
- package/skills/pomwright-v2-migration/references/fixture-and-helpers.md +0 -423
- package/skills/pomwright-v2-migration/references/locator-registration.md +0 -344
- package/srcV2/fixture/base.fixtures.ts +0 -23
- package/srcV2/helpers/navigation.ts +0 -153
- package/srcV2/helpers/playwrightReportLogger.ts +0 -196
- package/srcV2/helpers/sessionStorage.ts +0 -251
- package/srcV2/helpers/stepDecorator.ts +0 -106
- package/srcV2/locators/index.ts +0 -15
- package/srcV2/locators/locatorQueryBuilder.ts +0 -427
- package/srcV2/locators/locatorRegistrationBuilder.ts +0 -558
- package/srcV2/locators/locatorRegistry.ts +0 -583
- package/srcV2/locators/locatorUpdateBuilder.ts +0 -602
- package/srcV2/locators/reusableLocatorBuilder.ts +0 -200
- package/srcV2/locators/types.ts +0 -256
- package/srcV2/locators/utils.ts +0 -309
- package/srcV2/locators/v1SchemaTranslator.ts +0 -178
- package/srcV2/pageObject.ts +0 -105
|
@@ -1,427 +0,0 @@
|
|
|
1
|
-
import type { Locator } from "@playwright/test";
|
|
2
|
-
import type { LocatorRegistryInternal } from "./locatorRegistry";
|
|
3
|
-
import { buildReplacementDefinition, LocatorUpdateBuilder, mergeLocatorDefinition } from "./locatorUpdateBuilder";
|
|
4
|
-
import type {
|
|
5
|
-
FilterDefinition,
|
|
6
|
-
IndexSelector,
|
|
7
|
-
LocatorChainPaths,
|
|
8
|
-
LocatorDescription,
|
|
9
|
-
LocatorStep,
|
|
10
|
-
LocatorStrategyDefinition,
|
|
11
|
-
LocatorUpdate,
|
|
12
|
-
RegistryPath,
|
|
13
|
-
} from "./types";
|
|
14
|
-
import { cloneLocatorStrategyDefinition, expandSchemaPath, normalizeSteps } from "./utils";
|
|
15
|
-
|
|
16
|
-
export type LocatorQueryBuilderPublic<
|
|
17
|
-
LocatorSchemaPathType extends string,
|
|
18
|
-
LocatorSubstring extends RegistryPath<LocatorSchemaPathType>,
|
|
19
|
-
> = Pick<
|
|
20
|
-
LocatorQueryBuilder<LocatorSchemaPathType, LocatorSubstring>,
|
|
21
|
-
"filter" | "clearSteps" | "nth" | "describe" | "update" | "replace" | "remove" | "getLocator" | "getNestedLocator"
|
|
22
|
-
>;
|
|
23
|
-
|
|
24
|
-
export class LocatorQueryBuilder<
|
|
25
|
-
LocatorSchemaPathType extends string,
|
|
26
|
-
LocatorSubstring extends RegistryPath<LocatorSchemaPathType>,
|
|
27
|
-
> {
|
|
28
|
-
private readonly definitions = new Map<string, LocatorStrategyDefinition>();
|
|
29
|
-
private readonly perPathTypeCache = new Map<
|
|
30
|
-
string,
|
|
31
|
-
Map<LocatorStrategyDefinition["type"], LocatorStrategyDefinition>
|
|
32
|
-
>();
|
|
33
|
-
private readonly steps = new Map<
|
|
34
|
-
string,
|
|
35
|
-
LocatorStep<RegistryPath<LocatorSchemaPathType>, RegistryPath<LocatorSchemaPathType>>[]
|
|
36
|
-
>();
|
|
37
|
-
private readonly descriptions = new Map<string, LocatorDescription>();
|
|
38
|
-
private readonly tombstones = new Set<string>();
|
|
39
|
-
|
|
40
|
-
constructor(
|
|
41
|
-
private readonly registry: LocatorRegistryInternal<LocatorSchemaPathType>,
|
|
42
|
-
private readonly path: LocatorSubstring,
|
|
43
|
-
) {
|
|
44
|
-
const chain = expandSchemaPath(path);
|
|
45
|
-
let hasTerminal = false;
|
|
46
|
-
for (const part of chain) {
|
|
47
|
-
const record = this.registry.getIfExists(part as RegistryPath<LocatorSchemaPathType>);
|
|
48
|
-
if (!record) {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
const clonedDefinition = cloneLocatorStrategyDefinition(record.definition);
|
|
52
|
-
this.definitions.set(part, clonedDefinition);
|
|
53
|
-
this.ensureTypeCache(part, clonedDefinition);
|
|
54
|
-
const recordSteps = normalizeSteps<RegistryPath<LocatorSchemaPathType>, RegistryPath<LocatorSchemaPathType>>(
|
|
55
|
-
record.steps,
|
|
56
|
-
);
|
|
57
|
-
this.steps.set(part, recordSteps);
|
|
58
|
-
if (record.description !== undefined) {
|
|
59
|
-
this.descriptions.set(part, record.description);
|
|
60
|
-
}
|
|
61
|
-
if (part === path) {
|
|
62
|
-
hasTerminal = true;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
if (!hasTerminal) {
|
|
66
|
-
throw new Error(`No locator schema registered for path "${path}".`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Starts a PATCH-style update for the locator definition at the given `subPath` within this
|
|
72
|
-
* builder. Returns a builder exposing the same locator-type methods as `registry.add`, with all
|
|
73
|
-
* arguments optional to merge with the existing definition. The registry remains unchanged until
|
|
74
|
-
* you resolve with `getLocator`/`getNestedLocator`.
|
|
75
|
-
*
|
|
76
|
-
* If `subPath` is omitted, the terminal path for this builder (`path` passed to
|
|
77
|
-
* `getLocatorSchema`) is used.
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```ts
|
|
81
|
-
* getLocatorSchema("form.button")
|
|
82
|
-
* .update("form.button")
|
|
83
|
-
* .getByRole({ name: "Submit" })
|
|
84
|
-
* .getNestedLocator();
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
update(): LocatorUpdateBuilder<
|
|
88
|
-
LocatorSchemaPathType,
|
|
89
|
-
LocatorSubstring,
|
|
90
|
-
LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>
|
|
91
|
-
>;
|
|
92
|
-
update<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
93
|
-
subPath: SubPath,
|
|
94
|
-
): LocatorUpdateBuilder<LocatorSchemaPathType, LocatorSubstring, SubPath>;
|
|
95
|
-
update<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(subPath?: SubPath) {
|
|
96
|
-
const resolvedSubPath = (subPath ?? this.path) as LocatorChainPaths<
|
|
97
|
-
RegistryPath<LocatorSchemaPathType>,
|
|
98
|
-
LocatorSubstring
|
|
99
|
-
>;
|
|
100
|
-
this.ensureSubPath(resolvedSubPath);
|
|
101
|
-
return new LocatorUpdateBuilder<LocatorSchemaPathType, LocatorSubstring, typeof resolvedSubPath>(
|
|
102
|
-
this,
|
|
103
|
-
resolvedSubPath,
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Records a Playwright-style filter for the specified `subPath` within this builder. Unlike
|
|
109
|
-
* `registry.add`, `subPath` is optional here: when omitted, the terminal path for this builder is
|
|
110
|
-
* used. Provide an explicit `subPath` when targeting an ancestor segment.
|
|
111
|
-
*
|
|
112
|
-
* @example
|
|
113
|
-
* ```ts
|
|
114
|
-
* getLocatorSchema("list.item")
|
|
115
|
-
* .filter("list", { hasText: "List" })
|
|
116
|
-
* .filter("list.item", { hasText: "Row" });
|
|
117
|
-
* ```
|
|
118
|
-
*/
|
|
119
|
-
filter(filter: FilterDefinition<RegistryPath<LocatorSchemaPathType>, RegistryPath<LocatorSchemaPathType>>): this;
|
|
120
|
-
filter<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
121
|
-
subPath: SubPath,
|
|
122
|
-
filter: FilterDefinition<RegistryPath<LocatorSchemaPathType>, RegistryPath<LocatorSchemaPathType>>,
|
|
123
|
-
): this;
|
|
124
|
-
filter<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
125
|
-
...args:
|
|
126
|
-
| [FilterDefinition<RegistryPath<LocatorSchemaPathType>, RegistryPath<LocatorSchemaPathType>>]
|
|
127
|
-
| [SubPath, FilterDefinition<RegistryPath<LocatorSchemaPathType>, RegistryPath<LocatorSchemaPathType>>]
|
|
128
|
-
) {
|
|
129
|
-
const hasExplicitSubPath = args.length === 2;
|
|
130
|
-
const [subPathOrFilter, maybeFilter] = args;
|
|
131
|
-
const resolvedSubPath = (hasExplicitSubPath ? subPathOrFilter : this.path) as LocatorChainPaths<
|
|
132
|
-
RegistryPath<LocatorSchemaPathType>,
|
|
133
|
-
LocatorSubstring
|
|
134
|
-
>;
|
|
135
|
-
const filter = (hasExplicitSubPath ? maybeFilter : subPathOrFilter) as FilterDefinition<
|
|
136
|
-
RegistryPath<LocatorSchemaPathType>,
|
|
137
|
-
RegistryPath<LocatorSchemaPathType>
|
|
138
|
-
>;
|
|
139
|
-
|
|
140
|
-
this.ensureSubPath(resolvedSubPath);
|
|
141
|
-
const existing = this.steps.get(resolvedSubPath) ?? [];
|
|
142
|
-
existing.push({ kind: "filter", filter });
|
|
143
|
-
this.steps.set(resolvedSubPath, existing);
|
|
144
|
-
return this;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Clears all recorded `filter`/`nth` steps for the specified `subPath` in this builder, leaving
|
|
149
|
-
* the locator definition intact. If `subPath` is omitted, the terminal path for this builder is
|
|
150
|
-
* used; provide an explicit `subPath` to clear ancestor steps.
|
|
151
|
-
*
|
|
152
|
-
* @example
|
|
153
|
-
* ```ts
|
|
154
|
-
* getLocatorSchema("list.item").clearSteps("list.item").getNestedLocator();
|
|
155
|
-
* ```
|
|
156
|
-
*/
|
|
157
|
-
clearSteps(): this;
|
|
158
|
-
clearSteps<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
159
|
-
subPath: SubPath,
|
|
160
|
-
): this;
|
|
161
|
-
clearSteps<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
162
|
-
subPath?: SubPath,
|
|
163
|
-
) {
|
|
164
|
-
const resolvedSubPath = (subPath ?? this.path) as LocatorChainPaths<
|
|
165
|
-
RegistryPath<LocatorSchemaPathType>,
|
|
166
|
-
LocatorSubstring
|
|
167
|
-
>;
|
|
168
|
-
this.ensureSubPath(resolvedSubPath);
|
|
169
|
-
this.steps.set(resolvedSubPath, []);
|
|
170
|
-
return this;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Records an index selector for the specified `subPath` in this builder. Indices are applied in
|
|
175
|
-
* the order they are chained and require that the subPath already exists on the builder. If
|
|
176
|
-
* `subPath` is omitted, the terminal path for this builder is used; provide an explicit `subPath`
|
|
177
|
-
* to target ancestor segments.
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* ```ts
|
|
181
|
-
* getLocatorSchema("list.item").nth("list.item", 2).getNestedLocator();
|
|
182
|
-
* ```
|
|
183
|
-
*/
|
|
184
|
-
nth(index: IndexSelector): this;
|
|
185
|
-
nth<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
186
|
-
subPath: SubPath,
|
|
187
|
-
index: IndexSelector,
|
|
188
|
-
): this;
|
|
189
|
-
nth<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
190
|
-
...args: [IndexSelector] | [SubPath, IndexSelector]
|
|
191
|
-
) {
|
|
192
|
-
const hasExplicitSubPath = args.length === 2;
|
|
193
|
-
const [subPathOrIndex, maybeIndex] = args;
|
|
194
|
-
const resolvedSubPath = (hasExplicitSubPath ? subPathOrIndex : this.path) as LocatorChainPaths<
|
|
195
|
-
RegistryPath<LocatorSchemaPathType>,
|
|
196
|
-
LocatorSubstring
|
|
197
|
-
>;
|
|
198
|
-
const index = (hasExplicitSubPath ? maybeIndex : subPathOrIndex) as IndexSelector;
|
|
199
|
-
|
|
200
|
-
this.ensureSubPath(resolvedSubPath);
|
|
201
|
-
const existing = this.steps.get(resolvedSubPath) ?? [];
|
|
202
|
-
existing.push({ kind: "index", index });
|
|
203
|
-
this.steps.set(resolvedSubPath, existing);
|
|
204
|
-
return this;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Adds or overrides the description for the terminal path of this builder. The description is
|
|
209
|
-
* applied only to the resolved terminal locator and does not mutate registry state.
|
|
210
|
-
*
|
|
211
|
-
* @example
|
|
212
|
-
* ```ts
|
|
213
|
-
* getLocatorSchema("section.button")
|
|
214
|
-
* .describe("Save button")
|
|
215
|
-
* .getNestedLocator();
|
|
216
|
-
* ```
|
|
217
|
-
*/
|
|
218
|
-
describe(description: LocatorDescription) {
|
|
219
|
-
this.ensureSubPath(this.path);
|
|
220
|
-
this.descriptions.set(this.path, description);
|
|
221
|
-
return this;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/** @internal */
|
|
225
|
-
applyUpdate<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
226
|
-
subPath: SubPath,
|
|
227
|
-
updates: LocatorUpdate,
|
|
228
|
-
) {
|
|
229
|
-
this.ensureSubPath(subPath);
|
|
230
|
-
if (!this.definitions.has(subPath) && this.tombstones.has(subPath)) {
|
|
231
|
-
const baseline = this.registry.get(subPath as RegistryPath<LocatorSchemaPathType>).definition;
|
|
232
|
-
const baselineClone = cloneLocatorStrategyDefinition(baseline);
|
|
233
|
-
this.definitions.set(subPath, baselineClone);
|
|
234
|
-
this.steps.set(subPath, []);
|
|
235
|
-
this.tombstones.delete(subPath);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const current = this.definitions.get(subPath);
|
|
239
|
-
if (!current) {
|
|
240
|
-
throw new Error(`No locator schema registered for sub-path "${subPath}".`);
|
|
241
|
-
}
|
|
242
|
-
const baseline = this.registry.get(subPath as RegistryPath<LocatorSchemaPathType>).definition;
|
|
243
|
-
const cacheForPath = this.ensureTypeCache(subPath, cloneLocatorStrategyDefinition(baseline));
|
|
244
|
-
const cachedDefinition = cacheForPath.get(updates.type);
|
|
245
|
-
const merged = mergeLocatorDefinition(current, updates, subPath, cachedDefinition, baseline);
|
|
246
|
-
const mergedClone = cloneLocatorStrategyDefinition(merged);
|
|
247
|
-
cacheForPath.set(mergedClone.type, mergedClone);
|
|
248
|
-
this.definitions.set(subPath, mergedClone);
|
|
249
|
-
return this;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Starts a POST-style replacement for the locator definition at the given `subPath` within this
|
|
254
|
-
* builder. Returns a builder exposing the same locator-type methods as `registry.add`, requiring
|
|
255
|
-
* primary arguments where Playwright does. Registry state is unchanged; the replacement applies
|
|
256
|
-
* to the builder clone when resolved. If `subPath` is omitted, the terminal path for this
|
|
257
|
-
* builder is used.
|
|
258
|
-
*
|
|
259
|
-
* @example
|
|
260
|
-
* ```ts
|
|
261
|
-
* getLocatorSchema("section.button")
|
|
262
|
-
* .replace("section.button")
|
|
263
|
-
* .getByRole("button", { name: "Save" })
|
|
264
|
-
* .getNestedLocator();
|
|
265
|
-
* ```
|
|
266
|
-
*/
|
|
267
|
-
replace(): LocatorUpdateBuilder<
|
|
268
|
-
LocatorSchemaPathType,
|
|
269
|
-
LocatorSubstring,
|
|
270
|
-
LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>
|
|
271
|
-
>;
|
|
272
|
-
replace<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
273
|
-
subPath: SubPath,
|
|
274
|
-
): LocatorUpdateBuilder<LocatorSchemaPathType, LocatorSubstring, SubPath>;
|
|
275
|
-
replace<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(subPath?: SubPath) {
|
|
276
|
-
const resolvedSubPath = (subPath ?? this.path) as LocatorChainPaths<
|
|
277
|
-
RegistryPath<LocatorSchemaPathType>,
|
|
278
|
-
LocatorSubstring
|
|
279
|
-
>;
|
|
280
|
-
this.ensureSubPath(resolvedSubPath);
|
|
281
|
-
return new LocatorUpdateBuilder<LocatorSchemaPathType, LocatorSubstring, typeof resolvedSubPath>(
|
|
282
|
-
this,
|
|
283
|
-
resolvedSubPath,
|
|
284
|
-
"replace",
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/** @internal */
|
|
289
|
-
applyReplacement<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
290
|
-
subPath: SubPath,
|
|
291
|
-
updates: LocatorUpdate,
|
|
292
|
-
) {
|
|
293
|
-
this.ensureSubPath(subPath);
|
|
294
|
-
if (this.tombstones.has(subPath) && !this.definitions.has(subPath)) {
|
|
295
|
-
this.steps.set(subPath, []);
|
|
296
|
-
this.tombstones.delete(subPath);
|
|
297
|
-
}
|
|
298
|
-
const nextDefinition = buildReplacementDefinition(updates, subPath);
|
|
299
|
-
const cloned = cloneLocatorStrategyDefinition(nextDefinition);
|
|
300
|
-
const cacheForPath = this.ensureTypeCache(subPath, cloned);
|
|
301
|
-
cacheForPath.set(cloned.type, cloneLocatorStrategyDefinition(cloned));
|
|
302
|
-
this.definitions.set(subPath, cloned);
|
|
303
|
-
return this;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Soft-deletes the definition and steps for the given `subPath` on this builder clone, adding a
|
|
308
|
-
* tombstone. Non-terminal removals are skipped during resolution; terminal removals throw unless
|
|
309
|
-
* repopulated with `update`/`replace` before resolving. If `subPath` is omitted, the terminal
|
|
310
|
-
* path for this builder is used.
|
|
311
|
-
*
|
|
312
|
-
* @example
|
|
313
|
-
* ```ts
|
|
314
|
-
* const builder = getLocatorSchema("section.button");
|
|
315
|
-
* builder.remove("section.button");
|
|
316
|
-
* expect(() => builder.getNestedLocator()).toThrow();
|
|
317
|
-
* ```
|
|
318
|
-
*/
|
|
319
|
-
remove(): this;
|
|
320
|
-
remove<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(
|
|
321
|
-
subPath: SubPath,
|
|
322
|
-
): this;
|
|
323
|
-
remove<SubPath extends LocatorChainPaths<RegistryPath<LocatorSchemaPathType>, LocatorSubstring>>(subPath?: SubPath) {
|
|
324
|
-
const resolvedSubPath = (subPath ?? this.path) as LocatorChainPaths<
|
|
325
|
-
RegistryPath<LocatorSchemaPathType>,
|
|
326
|
-
LocatorSubstring
|
|
327
|
-
>;
|
|
328
|
-
this.ensureSubPath(resolvedSubPath);
|
|
329
|
-
this.definitions.delete(resolvedSubPath);
|
|
330
|
-
this.steps.delete(resolvedSubPath);
|
|
331
|
-
this.perPathTypeCache.delete(resolvedSubPath);
|
|
332
|
-
this.descriptions.delete(resolvedSubPath);
|
|
333
|
-
this.tombstones.add(resolvedSubPath);
|
|
334
|
-
return this;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Resolves and returns the Playwright {@link Locator} for the terminal path of this builder,
|
|
339
|
-
* applying only the terminal definition and its steps. Throws if the terminal path has been
|
|
340
|
-
* removed or is otherwise missing.
|
|
341
|
-
*
|
|
342
|
-
* @example
|
|
343
|
-
* ```ts
|
|
344
|
-
* const locator = getLocatorSchema("form.submit").getLocator();
|
|
345
|
-
* ```
|
|
346
|
-
*/
|
|
347
|
-
getLocator() {
|
|
348
|
-
const definition = this.definitions.get(this.path);
|
|
349
|
-
|
|
350
|
-
if (!definition) {
|
|
351
|
-
throw new Error(`No locator schema registered for path "${this.path}".`);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
const stepsForPath = this.steps.get(this.path) ?? [];
|
|
355
|
-
|
|
356
|
-
const definitions = new Map<string, LocatorStrategyDefinition>([[this.path, definition]]);
|
|
357
|
-
const steps = new Map<
|
|
358
|
-
string,
|
|
359
|
-
LocatorStep<RegistryPath<LocatorSchemaPathType>, RegistryPath<LocatorSchemaPathType>>[]
|
|
360
|
-
>([
|
|
361
|
-
[
|
|
362
|
-
this.path,
|
|
363
|
-
normalizeSteps<RegistryPath<LocatorSchemaPathType>, RegistryPath<LocatorSchemaPathType>>(stepsForPath),
|
|
364
|
-
],
|
|
365
|
-
]);
|
|
366
|
-
|
|
367
|
-
const { locator } = this.registry.buildLocatorChain(
|
|
368
|
-
this.path,
|
|
369
|
-
definitions,
|
|
370
|
-
steps,
|
|
371
|
-
this.tombstones,
|
|
372
|
-
this.descriptions.get(this.path),
|
|
373
|
-
);
|
|
374
|
-
if (!locator) {
|
|
375
|
-
throw new Error(`Unable to resolve direct locator for path "${this.path}".`);
|
|
376
|
-
}
|
|
377
|
-
return locator as Locator;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Resolves the chained Playwright {@link Locator} for this builder’s root path, traversing each
|
|
382
|
-
* registered segment and applying recorded steps. Throws if any required segment is missing.
|
|
383
|
-
*
|
|
384
|
-
* @example
|
|
385
|
-
* ```ts
|
|
386
|
-
* const nested = getLocatorSchema("list.item")
|
|
387
|
-
* .filter("list", { hasText: "List" })
|
|
388
|
-
* .getNestedLocator();
|
|
389
|
-
* ```
|
|
390
|
-
*/
|
|
391
|
-
getNestedLocator() {
|
|
392
|
-
const { locator } = this.resolve();
|
|
393
|
-
if (!locator) {
|
|
394
|
-
throw new Error(`Unable to resolve nested locator for path "${this.path}".`);
|
|
395
|
-
}
|
|
396
|
-
return locator;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
private ensureSubPath(subPath: string) {
|
|
400
|
-
if (!this.definitions.has(subPath) && !this.tombstones.has(subPath)) {
|
|
401
|
-
throw new Error(`"${subPath}" is not a valid sub-path of "${this.path}".`);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
private resolve() {
|
|
406
|
-
return this.registry.buildLocatorChain(
|
|
407
|
-
this.path,
|
|
408
|
-
this.definitions,
|
|
409
|
-
this.steps,
|
|
410
|
-
this.tombstones,
|
|
411
|
-
this.descriptions.get(this.path),
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
private ensureTypeCache(subPath: string, baseline: LocatorStrategyDefinition) {
|
|
416
|
-
if (!this.perPathTypeCache.has(subPath)) {
|
|
417
|
-
this.perPathTypeCache.set(
|
|
418
|
-
subPath,
|
|
419
|
-
new Map<LocatorStrategyDefinition["type"], LocatorStrategyDefinition>([
|
|
420
|
-
[baseline.type, cloneLocatorStrategyDefinition(baseline)],
|
|
421
|
-
]),
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
return this.perPathTypeCache.get(subPath) as Map<LocatorStrategyDefinition["type"], LocatorStrategyDefinition>;
|
|
426
|
-
}
|
|
427
|
-
}
|