@piwitests/reporter 0.58.0 → 0.59.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
|
@@ -634,6 +634,7 @@ function toWireTestCase(tc) {
|
|
|
634
634
|
timeout: rest.timeout ?? null,
|
|
635
635
|
error: rest.error,
|
|
636
636
|
retries: rest.retries,
|
|
637
|
+
repeatEachIndex: rest.repeatEachIndex ?? 0,
|
|
637
638
|
attempts: rest.attempts || null,
|
|
638
639
|
workerIndex: rest.workerIndex ?? null,
|
|
639
640
|
shardIndex: rest.shardIndex ?? null,
|
|
@@ -686,7 +687,13 @@ function isFailingStatus(status) {
|
|
|
686
687
|
function computeDistinctRunCounts(testCases) {
|
|
687
688
|
const final = /* @__PURE__ */ new Map();
|
|
688
689
|
for (const tc of testCases) {
|
|
689
|
-
const key = tc.testId ?? [
|
|
690
|
+
const key = tc.testId ?? [
|
|
691
|
+
tc.title,
|
|
692
|
+
tc.location,
|
|
693
|
+
(tc.suitePath ?? []).join(""),
|
|
694
|
+
browserProjectName(tc.browser),
|
|
695
|
+
tc.repeatEachIndex ?? 0
|
|
696
|
+
].join("\0");
|
|
690
697
|
const status = tc.status ?? "";
|
|
691
698
|
const retries = tc.retries ?? 0;
|
|
692
699
|
const prev = final.get(key);
|
|
@@ -844,6 +851,7 @@ var Uploader = class {
|
|
|
844
851
|
title: testCase.title,
|
|
845
852
|
location: testCase.location,
|
|
846
853
|
retries: testCase.retries ?? 0,
|
|
854
|
+
repeatEachIndex: testCase.repeatEachIndex ?? 0,
|
|
847
855
|
suitePath: testCase.suitePath ?? null
|
|
848
856
|
})
|
|
849
857
|
);
|
|
@@ -9541,6 +9549,7 @@ function caseLocateUrl(serverUrl, runId, test) {
|
|
|
9541
9549
|
`retry=${test.retry}`
|
|
9542
9550
|
];
|
|
9543
9551
|
if (test.browser) params.push(`browser=${encodeURIComponent(test.browser)}`);
|
|
9552
|
+
if (test.repeatEachIndex) params.push(`repeat=${test.repeatEachIndex}`);
|
|
9544
9553
|
return `${serverUrl.replace(/\/+$/, "")}/test-runs/${runId}/locate?${params.join("&")}`;
|
|
9545
9554
|
}
|
|
9546
9555
|
function formatFailureLine(link) {
|
|
@@ -11039,6 +11048,7 @@ var PiwiDashboardReporter = class _PiwiDashboardReporter {
|
|
|
11039
11048
|
type: "begin",
|
|
11040
11049
|
title: test.title,
|
|
11041
11050
|
location: testLocation(test, this.testPathBase),
|
|
11051
|
+
repeatEachIndex: test.repeatEachIndex,
|
|
11042
11052
|
workerIndex: workerIndexOf(result),
|
|
11043
11053
|
shardIndex: this.shardInfo?.current ?? null,
|
|
11044
11054
|
browser: this.metadataCollector.getBrowserConfig(test) || void 0,
|
|
@@ -11146,6 +11156,8 @@ var PiwiDashboardReporter = class _PiwiDashboardReporter {
|
|
|
11146
11156
|
// Playwright reports the same line, so synthesize it.
|
|
11147
11157
|
error: expectedFailureError(result.status, annotations) ?? buildErrorText(result, this.testPathBase),
|
|
11148
11158
|
retries: result.retry,
|
|
11159
|
+
// Each `--repeat-each` repetition is a test of its own, with its own attempts.
|
|
11160
|
+
repeatEachIndex: test.repeatEachIndex,
|
|
11149
11161
|
attempts: attempts.map((a) => ({ ...a })),
|
|
11150
11162
|
workerIndex: workerIndexOf(result),
|
|
11151
11163
|
shardIndex: this.shardInfo?.current ?? null,
|
|
@@ -11232,6 +11244,7 @@ var PiwiDashboardReporter = class _PiwiDashboardReporter {
|
|
|
11232
11244
|
file: testFile(test, this.testPathBase),
|
|
11233
11245
|
retry: result.retry,
|
|
11234
11246
|
browser: typeof testCase.browser?.projectName === "string" ? testCase.browser.projectName : null,
|
|
11247
|
+
repeatEachIndex: test.repeatEachIndex,
|
|
11235
11248
|
headline: failureHeadline(testCase.error, testCase.performanceMetrics?.steps)
|
|
11236
11249
|
});
|
|
11237
11250
|
}
|
|
@@ -11350,6 +11363,7 @@ var PiwiDashboardReporter = class _PiwiDashboardReporter {
|
|
|
11350
11363
|
timeout: test.timeout ?? null,
|
|
11351
11364
|
error: null,
|
|
11352
11365
|
retries: 0,
|
|
11366
|
+
repeatEachIndex: test.repeatEachIndex,
|
|
11353
11367
|
workerIndex: null,
|
|
11354
11368
|
shardIndex: this.shardInfo?.current ?? null,
|
|
11355
11369
|
startedAt: null,
|
|
@@ -11874,10 +11888,11 @@ function installPickerOverlay(arg) {
|
|
|
11874
11888
|
}
|
|
11875
11889
|
const Z = 2147483600;
|
|
11876
11890
|
const testIdAttr = arg.testIdAttribute || "data-testid";
|
|
11891
|
+
const enterReaches = arg.transport === "global";
|
|
11877
11892
|
const words = {
|
|
11878
11893
|
banner: "Piwi inspector \u2014 click any element to generate locators for it",
|
|
11879
|
-
keys: "\u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
11880
|
-
keysHovering: "click to pick \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
11894
|
+
keys: enterReaches ? "Enter picks the focused element \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip" : "\u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
11895
|
+
keysHovering: enterReaches ? "click or Enter to pick \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip" : "click to pick \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
11881
11896
|
analyzing: "Analyzing element\u2026"
|
|
11882
11897
|
};
|
|
11883
11898
|
for (const key of Object.keys(words)) {
|
|
@@ -11972,6 +11987,16 @@ function installPickerOverlay(arg) {
|
|
|
11972
11987
|
const cls = (el.getAttribute && el.getAttribute("class") || "").split(/\s+/).find((c) => c.length > 1);
|
|
11973
11988
|
return cls ? `locator(${quoteJs(`.${cls}`)})` : tag;
|
|
11974
11989
|
};
|
|
11990
|
+
const parentOf = (node) => {
|
|
11991
|
+
if (node.parentElement) return node.parentElement;
|
|
11992
|
+
const root = node.getRootNode ? node.getRootNode() : null;
|
|
11993
|
+
return root && root !== doc && root.host ? root.host : null;
|
|
11994
|
+
};
|
|
11995
|
+
const targetOf = (e) => {
|
|
11996
|
+
const path32 = typeof e.composedPath === "function" ? e.composedPath() : null;
|
|
11997
|
+
const first = path32 && path32.length ? path32[0] : null;
|
|
11998
|
+
return first && first.nodeType === 1 ? first : e.target;
|
|
11999
|
+
};
|
|
11975
12000
|
const buildChain = (raw) => {
|
|
11976
12001
|
const chain2 = [];
|
|
11977
12002
|
let node = raw;
|
|
@@ -11979,7 +12004,7 @@ function installPickerOverlay(arg) {
|
|
|
11979
12004
|
const tag = (node.tagName || "").toLowerCase();
|
|
11980
12005
|
if (tag === "body" || tag === "html") break;
|
|
11981
12006
|
chain2.push(node);
|
|
11982
|
-
node = node
|
|
12007
|
+
node = parentOf(node);
|
|
11983
12008
|
}
|
|
11984
12009
|
return chain2.length ? chain2 : [raw];
|
|
11985
12010
|
};
|
|
@@ -12070,10 +12095,14 @@ function installPickerOverlay(arg) {
|
|
|
12070
12095
|
}
|
|
12071
12096
|
};
|
|
12072
12097
|
const onMove = (e) => {
|
|
12073
|
-
const raw = e
|
|
12098
|
+
const raw = targetOf(e);
|
|
12074
12099
|
if (!raw || isOwn(raw)) {
|
|
12100
|
+
chain = [];
|
|
12101
|
+
idx = 0;
|
|
12102
|
+
lastRaw = null;
|
|
12075
12103
|
highlight.style.display = "none";
|
|
12076
12104
|
label.style.display = "none";
|
|
12105
|
+
foot.textContent = words.keys;
|
|
12077
12106
|
return;
|
|
12078
12107
|
}
|
|
12079
12108
|
if (raw !== lastRaw) {
|
|
@@ -12152,17 +12181,30 @@ function installPickerOverlay(arg) {
|
|
|
12152
12181
|
const onClick = (e) => {
|
|
12153
12182
|
stop(e);
|
|
12154
12183
|
const el = current();
|
|
12155
|
-
if (!el || isOwn(e
|
|
12184
|
+
if (!el || isOwn(targetOf(e))) return;
|
|
12156
12185
|
reportPicked(el);
|
|
12157
12186
|
};
|
|
12187
|
+
const focused = () => {
|
|
12188
|
+
let el = doc.activeElement;
|
|
12189
|
+
while (el && el.shadowRoot && el.shadowRoot.activeElement) el = el.shadowRoot.activeElement;
|
|
12190
|
+
const tag = (el && el.tagName || "").toLowerCase();
|
|
12191
|
+
return !el || tag === "body" || tag === "html" || isOwn(el) ? null : el;
|
|
12192
|
+
};
|
|
12158
12193
|
const onKey = (e) => {
|
|
12159
12194
|
if (e.key === "Escape") {
|
|
12160
12195
|
stop(e);
|
|
12161
12196
|
reportSkipped();
|
|
12162
12197
|
return;
|
|
12163
12198
|
}
|
|
12199
|
+
if (e.key === "Enter" && !e.isComposing) {
|
|
12200
|
+
stop(e);
|
|
12201
|
+
const el = current() || focused();
|
|
12202
|
+
if (el) reportPicked(el);
|
|
12203
|
+
return;
|
|
12204
|
+
}
|
|
12164
12205
|
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
|
12165
12206
|
stop(e);
|
|
12207
|
+
if (!chain.length) return;
|
|
12166
12208
|
if (e.key === "ArrowUp") idx = Math.min(idx + 1, chain.length - 1);
|
|
12167
12209
|
else idx = Math.max(idx - 1, 0);
|
|
12168
12210
|
refresh();
|
|
@@ -12236,12 +12278,43 @@ function showAnchorPicker(arg) {
|
|
|
12236
12278
|
const al = n.getAttribute && n.getAttribute("aria-level");
|
|
12237
12279
|
return al && /^\d+$/.test(al) ? Number(al) : null;
|
|
12238
12280
|
};
|
|
12281
|
+
const parentOf = (n) => {
|
|
12282
|
+
if (n.parentElement) return n.parentElement;
|
|
12283
|
+
const root = n.getRootNode ? n.getRootNode() : null;
|
|
12284
|
+
return root && root !== doc && root.host ? root.host : null;
|
|
12285
|
+
};
|
|
12286
|
+
const shadowRoots = [];
|
|
12287
|
+
const collectRoots = (root) => {
|
|
12288
|
+
const all = root.querySelectorAll("*");
|
|
12289
|
+
for (let i = 0; i < all.length; i++) {
|
|
12290
|
+
const sr = all[i].shadowRoot;
|
|
12291
|
+
if (sr) {
|
|
12292
|
+
shadowRoots.push(sr);
|
|
12293
|
+
collectRoots(sr);
|
|
12294
|
+
}
|
|
12295
|
+
}
|
|
12296
|
+
};
|
|
12297
|
+
try {
|
|
12298
|
+
collectRoots(doc);
|
|
12299
|
+
} catch {
|
|
12300
|
+
shadowRoots.length = 0;
|
|
12301
|
+
}
|
|
12302
|
+
const within = (node2, scope) => {
|
|
12303
|
+
if (scope === doc) return true;
|
|
12304
|
+
for (let n = node2; n; n = parentOf(n)) if (n === scope) return true;
|
|
12305
|
+
return false;
|
|
12306
|
+
};
|
|
12307
|
+
const queryAll = (scope, sel) => {
|
|
12308
|
+
const found = Array.from(scope.querySelectorAll(sel));
|
|
12309
|
+
for (const sr of shadowRoots) if (within(sr.host, scope)) found.push(...Array.from(sr.querySelectorAll(sel)));
|
|
12310
|
+
return found;
|
|
12311
|
+
};
|
|
12239
12312
|
const leafCountable = !!leafTestId || roleOf2(el) === leafRole;
|
|
12240
12313
|
const leafMatches = (scope) => {
|
|
12241
12314
|
try {
|
|
12242
|
-
if (leafTestId) return scope
|
|
12315
|
+
if (leafTestId) return queryAll(scope, `[${testIdAttr}=${JSON.stringify(leafTestId)}]`).length;
|
|
12243
12316
|
if (!leafCountable) return -1;
|
|
12244
|
-
const nodes = scope
|
|
12317
|
+
const nodes = queryAll(scope, roleSources);
|
|
12245
12318
|
if (nodes.length > 2e3) return -1;
|
|
12246
12319
|
let matched = 0;
|
|
12247
12320
|
for (let i = 0; i < nodes.length; i++) {
|
|
@@ -12257,20 +12330,20 @@ function showAnchorPicker(arg) {
|
|
|
12257
12330
|
};
|
|
12258
12331
|
let roleNodes = [];
|
|
12259
12332
|
try {
|
|
12260
|
-
const all = doc
|
|
12261
|
-
if (all.length <= 4e3) roleNodes =
|
|
12333
|
+
const all = queryAll(doc, roleSources);
|
|
12334
|
+
if (all.length <= 4e3) roleNodes = all;
|
|
12262
12335
|
} catch {
|
|
12263
12336
|
roleNodes = [];
|
|
12264
12337
|
}
|
|
12265
12338
|
const count = (sel) => {
|
|
12266
12339
|
try {
|
|
12267
|
-
return doc
|
|
12340
|
+
return queryAll(doc, sel).length;
|
|
12268
12341
|
} catch {
|
|
12269
12342
|
return void 0;
|
|
12270
12343
|
}
|
|
12271
12344
|
};
|
|
12272
12345
|
const rows = [];
|
|
12273
|
-
let node = el
|
|
12346
|
+
let node = parentOf(el);
|
|
12274
12347
|
let depth = 0;
|
|
12275
12348
|
while (node && depth < 12) {
|
|
12276
12349
|
depth++;
|
|
@@ -12307,7 +12380,7 @@ function showAnchorPicker(arg) {
|
|
|
12307
12380
|
hookLabel,
|
|
12308
12381
|
selectable: !!(testId || id || role && (ariaLabel || info.roleCount === 1))
|
|
12309
12382
|
});
|
|
12310
|
-
node = node
|
|
12383
|
+
node = parentOf(node);
|
|
12311
12384
|
}
|
|
12312
12385
|
if (rows.length === 0) {
|
|
12313
12386
|
g.__piwiAnchorState = "skipped";
|
|
@@ -12336,9 +12409,9 @@ function showAnchorPicker(arg) {
|
|
|
12336
12409
|
footer.style.cssText = "margin:10px 0;font-weight:600;";
|
|
12337
12410
|
const segMatches = (scope, info) => {
|
|
12338
12411
|
try {
|
|
12339
|
-
if (info.testId) return
|
|
12340
|
-
if (info.id) return
|
|
12341
|
-
const nodes =
|
|
12412
|
+
if (info.testId) return queryAll(scope, `[${testIdAttr}=${JSON.stringify(info.testId)}]`);
|
|
12413
|
+
if (info.id) return queryAll(scope, `#${doc.defaultView.CSS.escape(info.id)}`);
|
|
12414
|
+
const nodes = queryAll(scope, roleSources);
|
|
12342
12415
|
if (nodes.length > 2e3) return [];
|
|
12343
12416
|
return nodes.filter(
|
|
12344
12417
|
(n) => roleOf2(n) === info.role && (!info.ariaLabel || n.getAttribute && n.getAttribute("aria-label") === info.ariaLabel)
|
|
@@ -412,10 +412,11 @@ function installPickerOverlay(arg) {
|
|
|
412
412
|
}
|
|
413
413
|
const Z = 2147483600;
|
|
414
414
|
const testIdAttr = arg.testIdAttribute || "data-testid";
|
|
415
|
+
const enterReaches = arg.transport === "global";
|
|
415
416
|
const words = {
|
|
416
417
|
banner: "Piwi inspector \u2014 click any element to generate locators for it",
|
|
417
|
-
keys: "\u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
418
|
-
keysHovering: "click to pick \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
418
|
+
keys: enterReaches ? "Enter picks the focused element \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip" : "\u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
419
|
+
keysHovering: enterReaches ? "click or Enter to pick \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip" : "click to pick \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
419
420
|
analyzing: "Analyzing element\u2026"
|
|
420
421
|
};
|
|
421
422
|
for (const key of Object.keys(words)) {
|
|
@@ -510,6 +511,16 @@ function installPickerOverlay(arg) {
|
|
|
510
511
|
const cls = (el.getAttribute && el.getAttribute("class") || "").split(/\s+/).find((c) => c.length > 1);
|
|
511
512
|
return cls ? `locator(${quoteJs(`.${cls}`)})` : tag;
|
|
512
513
|
};
|
|
514
|
+
const parentOf = (node) => {
|
|
515
|
+
if (node.parentElement) return node.parentElement;
|
|
516
|
+
const root = node.getRootNode ? node.getRootNode() : null;
|
|
517
|
+
return root && root !== doc && root.host ? root.host : null;
|
|
518
|
+
};
|
|
519
|
+
const targetOf = (e) => {
|
|
520
|
+
const path13 = typeof e.composedPath === "function" ? e.composedPath() : null;
|
|
521
|
+
const first = path13 && path13.length ? path13[0] : null;
|
|
522
|
+
return first && first.nodeType === 1 ? first : e.target;
|
|
523
|
+
};
|
|
513
524
|
const buildChain = (raw) => {
|
|
514
525
|
const chain2 = [];
|
|
515
526
|
let node = raw;
|
|
@@ -517,7 +528,7 @@ function installPickerOverlay(arg) {
|
|
|
517
528
|
const tag = (node.tagName || "").toLowerCase();
|
|
518
529
|
if (tag === "body" || tag === "html") break;
|
|
519
530
|
chain2.push(node);
|
|
520
|
-
node = node
|
|
531
|
+
node = parentOf(node);
|
|
521
532
|
}
|
|
522
533
|
return chain2.length ? chain2 : [raw];
|
|
523
534
|
};
|
|
@@ -608,10 +619,14 @@ function installPickerOverlay(arg) {
|
|
|
608
619
|
}
|
|
609
620
|
};
|
|
610
621
|
const onMove = (e) => {
|
|
611
|
-
const raw = e
|
|
622
|
+
const raw = targetOf(e);
|
|
612
623
|
if (!raw || isOwn(raw)) {
|
|
624
|
+
chain = [];
|
|
625
|
+
idx = 0;
|
|
626
|
+
lastRaw = null;
|
|
613
627
|
highlight.style.display = "none";
|
|
614
628
|
label.style.display = "none";
|
|
629
|
+
foot.textContent = words.keys;
|
|
615
630
|
return;
|
|
616
631
|
}
|
|
617
632
|
if (raw !== lastRaw) {
|
|
@@ -690,17 +705,30 @@ function installPickerOverlay(arg) {
|
|
|
690
705
|
const onClick = (e) => {
|
|
691
706
|
stop(e);
|
|
692
707
|
const el = current();
|
|
693
|
-
if (!el || isOwn(e
|
|
708
|
+
if (!el || isOwn(targetOf(e))) return;
|
|
694
709
|
reportPicked(el);
|
|
695
710
|
};
|
|
711
|
+
const focused = () => {
|
|
712
|
+
let el = doc.activeElement;
|
|
713
|
+
while (el && el.shadowRoot && el.shadowRoot.activeElement) el = el.shadowRoot.activeElement;
|
|
714
|
+
const tag = (el && el.tagName || "").toLowerCase();
|
|
715
|
+
return !el || tag === "body" || tag === "html" || isOwn(el) ? null : el;
|
|
716
|
+
};
|
|
696
717
|
const onKey = (e) => {
|
|
697
718
|
if (e.key === "Escape") {
|
|
698
719
|
stop(e);
|
|
699
720
|
reportSkipped();
|
|
700
721
|
return;
|
|
701
722
|
}
|
|
723
|
+
if (e.key === "Enter" && !e.isComposing) {
|
|
724
|
+
stop(e);
|
|
725
|
+
const el = current() || focused();
|
|
726
|
+
if (el) reportPicked(el);
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
702
729
|
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
|
703
730
|
stop(e);
|
|
731
|
+
if (!chain.length) return;
|
|
704
732
|
if (e.key === "ArrowUp") idx = Math.min(idx + 1, chain.length - 1);
|
|
705
733
|
else idx = Math.max(idx - 1, 0);
|
|
706
734
|
refresh();
|
|
@@ -774,12 +802,43 @@ function showAnchorPicker(arg) {
|
|
|
774
802
|
const al = n.getAttribute && n.getAttribute("aria-level");
|
|
775
803
|
return al && /^\d+$/.test(al) ? Number(al) : null;
|
|
776
804
|
};
|
|
805
|
+
const parentOf = (n) => {
|
|
806
|
+
if (n.parentElement) return n.parentElement;
|
|
807
|
+
const root = n.getRootNode ? n.getRootNode() : null;
|
|
808
|
+
return root && root !== doc && root.host ? root.host : null;
|
|
809
|
+
};
|
|
810
|
+
const shadowRoots = [];
|
|
811
|
+
const collectRoots = (root) => {
|
|
812
|
+
const all = root.querySelectorAll("*");
|
|
813
|
+
for (let i = 0; i < all.length; i++) {
|
|
814
|
+
const sr = all[i].shadowRoot;
|
|
815
|
+
if (sr) {
|
|
816
|
+
shadowRoots.push(sr);
|
|
817
|
+
collectRoots(sr);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
try {
|
|
822
|
+
collectRoots(doc);
|
|
823
|
+
} catch {
|
|
824
|
+
shadowRoots.length = 0;
|
|
825
|
+
}
|
|
826
|
+
const within = (node2, scope) => {
|
|
827
|
+
if (scope === doc) return true;
|
|
828
|
+
for (let n = node2; n; n = parentOf(n)) if (n === scope) return true;
|
|
829
|
+
return false;
|
|
830
|
+
};
|
|
831
|
+
const queryAll = (scope, sel) => {
|
|
832
|
+
const found = Array.from(scope.querySelectorAll(sel));
|
|
833
|
+
for (const sr of shadowRoots) if (within(sr.host, scope)) found.push(...Array.from(sr.querySelectorAll(sel)));
|
|
834
|
+
return found;
|
|
835
|
+
};
|
|
777
836
|
const leafCountable = !!leafTestId || roleOf2(el) === leafRole;
|
|
778
837
|
const leafMatches = (scope) => {
|
|
779
838
|
try {
|
|
780
|
-
if (leafTestId) return scope
|
|
839
|
+
if (leafTestId) return queryAll(scope, `[${testIdAttr}=${JSON.stringify(leafTestId)}]`).length;
|
|
781
840
|
if (!leafCountable) return -1;
|
|
782
|
-
const nodes = scope
|
|
841
|
+
const nodes = queryAll(scope, roleSources);
|
|
783
842
|
if (nodes.length > 2e3) return -1;
|
|
784
843
|
let matched = 0;
|
|
785
844
|
for (let i = 0; i < nodes.length; i++) {
|
|
@@ -795,20 +854,20 @@ function showAnchorPicker(arg) {
|
|
|
795
854
|
};
|
|
796
855
|
let roleNodes = [];
|
|
797
856
|
try {
|
|
798
|
-
const all = doc
|
|
799
|
-
if (all.length <= 4e3) roleNodes =
|
|
857
|
+
const all = queryAll(doc, roleSources);
|
|
858
|
+
if (all.length <= 4e3) roleNodes = all;
|
|
800
859
|
} catch {
|
|
801
860
|
roleNodes = [];
|
|
802
861
|
}
|
|
803
862
|
const count = (sel) => {
|
|
804
863
|
try {
|
|
805
|
-
return doc
|
|
864
|
+
return queryAll(doc, sel).length;
|
|
806
865
|
} catch {
|
|
807
866
|
return void 0;
|
|
808
867
|
}
|
|
809
868
|
};
|
|
810
869
|
const rows = [];
|
|
811
|
-
let node = el
|
|
870
|
+
let node = parentOf(el);
|
|
812
871
|
let depth = 0;
|
|
813
872
|
while (node && depth < 12) {
|
|
814
873
|
depth++;
|
|
@@ -845,7 +904,7 @@ function showAnchorPicker(arg) {
|
|
|
845
904
|
hookLabel,
|
|
846
905
|
selectable: !!(testId || id || role && (ariaLabel || info.roleCount === 1))
|
|
847
906
|
});
|
|
848
|
-
node = node
|
|
907
|
+
node = parentOf(node);
|
|
849
908
|
}
|
|
850
909
|
if (rows.length === 0) {
|
|
851
910
|
g.__piwiAnchorState = "skipped";
|
|
@@ -874,9 +933,9 @@ function showAnchorPicker(arg) {
|
|
|
874
933
|
footer.style.cssText = "margin:10px 0;font-weight:600;";
|
|
875
934
|
const segMatches = (scope, info) => {
|
|
876
935
|
try {
|
|
877
|
-
if (info.testId) return
|
|
878
|
-
if (info.id) return
|
|
879
|
-
const nodes =
|
|
936
|
+
if (info.testId) return queryAll(scope, `[${testIdAttr}=${JSON.stringify(info.testId)}]`);
|
|
937
|
+
if (info.id) return queryAll(scope, `#${doc.defaultView.CSS.escape(info.id)}`);
|
|
938
|
+
const nodes = queryAll(scope, roleSources);
|
|
880
939
|
if (nodes.length > 2e3) return [];
|
|
881
940
|
return nodes.filter(
|
|
882
941
|
(n) => roleOf2(n) === info.role && (!info.ariaLabel || n.getAttribute && n.getAttribute("aria-label") === info.ariaLabel)
|
|
@@ -379,10 +379,11 @@ function installPickerOverlay(arg) {
|
|
|
379
379
|
}
|
|
380
380
|
const Z = 2147483600;
|
|
381
381
|
const testIdAttr = arg.testIdAttribute || "data-testid";
|
|
382
|
+
const enterReaches = arg.transport === "global";
|
|
382
383
|
const words = {
|
|
383
384
|
banner: "Piwi inspector \u2014 click any element to generate locators for it",
|
|
384
|
-
keys: "\u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
385
|
-
keysHovering: "click to pick \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
385
|
+
keys: enterReaches ? "Enter picks the focused element \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip" : "\u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
386
|
+
keysHovering: enterReaches ? "click or Enter to pick \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip" : "click to pick \xB7 \u2191 parent \xB7 \u2193 child \xB7 Esc skip",
|
|
386
387
|
analyzing: "Analyzing element\u2026"
|
|
387
388
|
};
|
|
388
389
|
for (const key of Object.keys(words)) {
|
|
@@ -477,6 +478,16 @@ function installPickerOverlay(arg) {
|
|
|
477
478
|
const cls = (el.getAttribute && el.getAttribute("class") || "").split(/\s+/).find((c) => c.length > 1);
|
|
478
479
|
return cls ? `locator(${quoteJs(`.${cls}`)})` : tag;
|
|
479
480
|
};
|
|
481
|
+
const parentOf = (node) => {
|
|
482
|
+
if (node.parentElement) return node.parentElement;
|
|
483
|
+
const root = node.getRootNode ? node.getRootNode() : null;
|
|
484
|
+
return root && root !== doc && root.host ? root.host : null;
|
|
485
|
+
};
|
|
486
|
+
const targetOf = (e) => {
|
|
487
|
+
const path3 = typeof e.composedPath === "function" ? e.composedPath() : null;
|
|
488
|
+
const first = path3 && path3.length ? path3[0] : null;
|
|
489
|
+
return first && first.nodeType === 1 ? first : e.target;
|
|
490
|
+
};
|
|
480
491
|
const buildChain = (raw) => {
|
|
481
492
|
const chain2 = [];
|
|
482
493
|
let node = raw;
|
|
@@ -484,7 +495,7 @@ function installPickerOverlay(arg) {
|
|
|
484
495
|
const tag = (node.tagName || "").toLowerCase();
|
|
485
496
|
if (tag === "body" || tag === "html") break;
|
|
486
497
|
chain2.push(node);
|
|
487
|
-
node = node
|
|
498
|
+
node = parentOf(node);
|
|
488
499
|
}
|
|
489
500
|
return chain2.length ? chain2 : [raw];
|
|
490
501
|
};
|
|
@@ -575,10 +586,14 @@ function installPickerOverlay(arg) {
|
|
|
575
586
|
}
|
|
576
587
|
};
|
|
577
588
|
const onMove = (e) => {
|
|
578
|
-
const raw = e
|
|
589
|
+
const raw = targetOf(e);
|
|
579
590
|
if (!raw || isOwn(raw)) {
|
|
591
|
+
chain = [];
|
|
592
|
+
idx = 0;
|
|
593
|
+
lastRaw = null;
|
|
580
594
|
highlight.style.display = "none";
|
|
581
595
|
label.style.display = "none";
|
|
596
|
+
foot.textContent = words.keys;
|
|
582
597
|
return;
|
|
583
598
|
}
|
|
584
599
|
if (raw !== lastRaw) {
|
|
@@ -657,17 +672,30 @@ function installPickerOverlay(arg) {
|
|
|
657
672
|
const onClick = (e) => {
|
|
658
673
|
stop(e);
|
|
659
674
|
const el = current();
|
|
660
|
-
if (!el || isOwn(e
|
|
675
|
+
if (!el || isOwn(targetOf(e))) return;
|
|
661
676
|
reportPicked(el);
|
|
662
677
|
};
|
|
678
|
+
const focused = () => {
|
|
679
|
+
let el = doc.activeElement;
|
|
680
|
+
while (el && el.shadowRoot && el.shadowRoot.activeElement) el = el.shadowRoot.activeElement;
|
|
681
|
+
const tag = (el && el.tagName || "").toLowerCase();
|
|
682
|
+
return !el || tag === "body" || tag === "html" || isOwn(el) ? null : el;
|
|
683
|
+
};
|
|
663
684
|
const onKey = (e) => {
|
|
664
685
|
if (e.key === "Escape") {
|
|
665
686
|
stop(e);
|
|
666
687
|
reportSkipped();
|
|
667
688
|
return;
|
|
668
689
|
}
|
|
690
|
+
if (e.key === "Enter" && !e.isComposing) {
|
|
691
|
+
stop(e);
|
|
692
|
+
const el = current() || focused();
|
|
693
|
+
if (el) reportPicked(el);
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
669
696
|
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
|
670
697
|
stop(e);
|
|
698
|
+
if (!chain.length) return;
|
|
671
699
|
if (e.key === "ArrowUp") idx = Math.min(idx + 1, chain.length - 1);
|
|
672
700
|
else idx = Math.max(idx - 1, 0);
|
|
673
701
|
refresh();
|
|
@@ -741,12 +769,43 @@ function showAnchorPicker(arg) {
|
|
|
741
769
|
const al = n.getAttribute && n.getAttribute("aria-level");
|
|
742
770
|
return al && /^\d+$/.test(al) ? Number(al) : null;
|
|
743
771
|
};
|
|
772
|
+
const parentOf = (n) => {
|
|
773
|
+
if (n.parentElement) return n.parentElement;
|
|
774
|
+
const root = n.getRootNode ? n.getRootNode() : null;
|
|
775
|
+
return root && root !== doc && root.host ? root.host : null;
|
|
776
|
+
};
|
|
777
|
+
const shadowRoots = [];
|
|
778
|
+
const collectRoots = (root) => {
|
|
779
|
+
const all = root.querySelectorAll("*");
|
|
780
|
+
for (let i = 0; i < all.length; i++) {
|
|
781
|
+
const sr = all[i].shadowRoot;
|
|
782
|
+
if (sr) {
|
|
783
|
+
shadowRoots.push(sr);
|
|
784
|
+
collectRoots(sr);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
try {
|
|
789
|
+
collectRoots(doc);
|
|
790
|
+
} catch {
|
|
791
|
+
shadowRoots.length = 0;
|
|
792
|
+
}
|
|
793
|
+
const within = (node2, scope) => {
|
|
794
|
+
if (scope === doc) return true;
|
|
795
|
+
for (let n = node2; n; n = parentOf(n)) if (n === scope) return true;
|
|
796
|
+
return false;
|
|
797
|
+
};
|
|
798
|
+
const queryAll = (scope, sel) => {
|
|
799
|
+
const found = Array.from(scope.querySelectorAll(sel));
|
|
800
|
+
for (const sr of shadowRoots) if (within(sr.host, scope)) found.push(...Array.from(sr.querySelectorAll(sel)));
|
|
801
|
+
return found;
|
|
802
|
+
};
|
|
744
803
|
const leafCountable = !!leafTestId || roleOf(el) === leafRole;
|
|
745
804
|
const leafMatches = (scope) => {
|
|
746
805
|
try {
|
|
747
|
-
if (leafTestId) return scope
|
|
806
|
+
if (leafTestId) return queryAll(scope, `[${testIdAttr}=${JSON.stringify(leafTestId)}]`).length;
|
|
748
807
|
if (!leafCountable) return -1;
|
|
749
|
-
const nodes = scope
|
|
808
|
+
const nodes = queryAll(scope, roleSources);
|
|
750
809
|
if (nodes.length > 2e3) return -1;
|
|
751
810
|
let matched = 0;
|
|
752
811
|
for (let i = 0; i < nodes.length; i++) {
|
|
@@ -762,20 +821,20 @@ function showAnchorPicker(arg) {
|
|
|
762
821
|
};
|
|
763
822
|
let roleNodes = [];
|
|
764
823
|
try {
|
|
765
|
-
const all = doc
|
|
766
|
-
if (all.length <= 4e3) roleNodes =
|
|
824
|
+
const all = queryAll(doc, roleSources);
|
|
825
|
+
if (all.length <= 4e3) roleNodes = all;
|
|
767
826
|
} catch {
|
|
768
827
|
roleNodes = [];
|
|
769
828
|
}
|
|
770
829
|
const count = (sel) => {
|
|
771
830
|
try {
|
|
772
|
-
return doc
|
|
831
|
+
return queryAll(doc, sel).length;
|
|
773
832
|
} catch {
|
|
774
833
|
return void 0;
|
|
775
834
|
}
|
|
776
835
|
};
|
|
777
836
|
const rows = [];
|
|
778
|
-
let node = el
|
|
837
|
+
let node = parentOf(el);
|
|
779
838
|
let depth = 0;
|
|
780
839
|
while (node && depth < 12) {
|
|
781
840
|
depth++;
|
|
@@ -812,7 +871,7 @@ function showAnchorPicker(arg) {
|
|
|
812
871
|
hookLabel,
|
|
813
872
|
selectable: !!(testId || id || role && (ariaLabel || info.roleCount === 1))
|
|
814
873
|
});
|
|
815
|
-
node = node
|
|
874
|
+
node = parentOf(node);
|
|
816
875
|
}
|
|
817
876
|
if (rows.length === 0) {
|
|
818
877
|
g.__piwiAnchorState = "skipped";
|
|
@@ -841,9 +900,9 @@ function showAnchorPicker(arg) {
|
|
|
841
900
|
footer.style.cssText = "margin:10px 0;font-weight:600;";
|
|
842
901
|
const segMatches = (scope, info) => {
|
|
843
902
|
try {
|
|
844
|
-
if (info.testId) return
|
|
845
|
-
if (info.id) return
|
|
846
|
-
const nodes =
|
|
903
|
+
if (info.testId) return queryAll(scope, `[${testIdAttr}=${JSON.stringify(info.testId)}]`);
|
|
904
|
+
if (info.id) return queryAll(scope, `#${doc.defaultView.CSS.escape(info.id)}`);
|
|
905
|
+
const nodes = queryAll(scope, roleSources);
|
|
847
906
|
if (nodes.length > 2e3) return [];
|
|
848
907
|
return nodes.filter(
|
|
849
908
|
(n) => roleOf(n) === info.role && (!info.ariaLabel || n.getAttribute && n.getAttribute("aria-label") === info.ariaLabel)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piwitests/reporter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.59.0",
|
|
4
4
|
"description": "Playwright reporter that streams results, traces and HTML reports to a Piwi Dashboard instance",
|
|
5
5
|
"url": "https://github.com/PiwiTests/platform",
|
|
6
6
|
"homepage": "https://piwitests.dev",
|