@rettangoli/vt 1.0.1 → 1.0.2
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/README.md +1 -0
- package/package.json +1 -1
- package/src/createSteps.js +46 -15
- package/src/validation.js +10 -3
package/README.md
CHANGED
|
@@ -126,6 +126,7 @@ Step action reference:
|
|
|
126
126
|
|
|
127
127
|
- `docs/step-actions.md`
|
|
128
128
|
- canonical format is structured action objects (`- action: ...`); legacy one-line string steps are not supported.
|
|
129
|
+
- `action: select` accepts exactly one of `testId` or `selector` for interaction targeting.
|
|
129
130
|
- `assert` supports `js` deep-equal checks for object/array values.
|
|
130
131
|
|
|
131
132
|
Screenshot naming:
|
package/package.json
CHANGED
package/src/createSteps.js
CHANGED
|
@@ -180,6 +180,27 @@ function requireStructuredString(stepObject, key, actionName) {
|
|
|
180
180
|
return value;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
function resolveStructuredSelectTarget(stepObject, actionName) {
|
|
184
|
+
const hasTestId = Object.prototype.hasOwnProperty.call(stepObject, "testId");
|
|
185
|
+
const hasSelector = Object.prototype.hasOwnProperty.call(stepObject, "selector");
|
|
186
|
+
|
|
187
|
+
if (hasTestId === hasSelector) {
|
|
188
|
+
throw new Error(`Structured action "${actionName}" requires exactly one of \`testId\` or \`selector\`.`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (hasTestId) {
|
|
192
|
+
return {
|
|
193
|
+
type: "testId",
|
|
194
|
+
value: requireStructuredString(stepObject, "testId", actionName),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
type: "selector",
|
|
200
|
+
value: requireStructuredString(stepObject, "selector", actionName),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
183
204
|
function requireStructuredNumber(stepObject, key, actionName) {
|
|
184
205
|
const value = stepObject[key];
|
|
185
206
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -224,13 +245,13 @@ function normalizeStructuredActionStep(stepObject) {
|
|
|
224
245
|
}
|
|
225
246
|
|
|
226
247
|
if (action === "select") {
|
|
227
|
-
assertStructuredKeys(stepObject, new Set(["action", "testId", "steps"]), action);
|
|
228
|
-
const
|
|
248
|
+
assertStructuredKeys(stepObject, new Set(["action", "testId", "selector", "steps"]), action);
|
|
249
|
+
const target = resolveStructuredSelectTarget(stepObject, action);
|
|
229
250
|
if (!Array.isArray(stepObject.steps)) {
|
|
230
251
|
throw new Error('Structured action "select" requires array `steps`.');
|
|
231
252
|
}
|
|
232
253
|
const nestedSteps = stepObject.steps.map((nestedStep) => normalizeStepValue(nestedStep));
|
|
233
|
-
return { kind: "block", command: "select", args: [
|
|
254
|
+
return { kind: "block", command: "select", args: [`${target.type}=${target.value}`], nestedSteps };
|
|
234
255
|
}
|
|
235
256
|
|
|
236
257
|
if (action === "click" || action === "dblclick" || action === "hover" || action === "rclick") {
|
|
@@ -828,22 +849,32 @@ async function assertStructured(page, assertionConfig, selectedElement) {
|
|
|
828
849
|
}
|
|
829
850
|
|
|
830
851
|
async function select(page, args) {
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
const
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
)
|
|
840
|
-
|
|
852
|
+
const { named, positional } = parseNamedArgs(args);
|
|
853
|
+
const testId = typeof named.testId === "string" && named.testId.length > 0
|
|
854
|
+
? named.testId
|
|
855
|
+
: positional[0];
|
|
856
|
+
const selector = typeof named.selector === "string" && named.selector.length > 0
|
|
857
|
+
? named.selector
|
|
858
|
+
: undefined;
|
|
859
|
+
|
|
860
|
+
if ((testId ? 1 : 0) + (selector ? 1 : 0) !== 1) {
|
|
861
|
+
throw new Error("`select` requires exactly one target: `testId` or `selector`.");
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
const hostElementLocator = selector
|
|
865
|
+
? page.locator(selector)
|
|
866
|
+
: page.getByTestId(testId);
|
|
867
|
+
|
|
868
|
+
const interactiveElementLocator = hostElementLocator
|
|
869
|
+
.locator('input, textarea, button, select, a')
|
|
870
|
+
.first();
|
|
871
|
+
|
|
841
872
|
const count = await interactiveElementLocator.count();
|
|
842
|
-
|
|
873
|
+
|
|
843
874
|
if (count > 0) {
|
|
844
875
|
return interactiveElementLocator;
|
|
845
876
|
}
|
|
846
|
-
|
|
877
|
+
|
|
847
878
|
return hostElementLocator;
|
|
848
879
|
}
|
|
849
880
|
|
package/src/validation.js
CHANGED
|
@@ -273,11 +273,18 @@ function validateStructuredActionStep(step, stepPath) {
|
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
if (action === "select") {
|
|
276
|
-
assertNoUnknownStepKeys(step, stepPath, new Set(["action", "testId", "steps"]));
|
|
276
|
+
assertNoUnknownStepKeys(step, stepPath, new Set(["action", "testId", "selector", "steps"]));
|
|
277
277
|
validateOptionalString(step.testId, `${stepPath}.testId`);
|
|
278
|
+
validateOptionalString(step.selector, `${stepPath}.selector`);
|
|
278
279
|
assert(
|
|
279
|
-
|
|
280
|
-
|
|
280
|
+
(
|
|
281
|
+
typeof step.testId === "string"
|
|
282
|
+
&& step.testId.trim().length > 0
|
|
283
|
+
) !== (
|
|
284
|
+
typeof step.selector === "string"
|
|
285
|
+
&& step.selector.trim().length > 0
|
|
286
|
+
),
|
|
287
|
+
`"${stepPath}" for action=select requires exactly one of "testId" or "selector".`,
|
|
281
288
|
);
|
|
282
289
|
assert(Array.isArray(step.steps), `"${stepPath}.steps" must be an array for action=select.`);
|
|
283
290
|
step.steps.forEach((nestedStep, nestedIndex) => {
|