@olomonhelpdesk2/helpdesk 0.1.13 → 0.1.14
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/helpdesk-capture.mjs +47 -14
- package/package.json +1 -1
package/helpdesk-capture.mjs
CHANGED
|
@@ -106,7 +106,12 @@ function readExampleRoutes(raw) {
|
|
|
106
106
|
}
|
|
107
107
|
paths.set(route, path5);
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
const again = /* @__PURE__ */ new Set();
|
|
110
|
+
for (const route of Array.isArray(body["again"]) ? body["again"] : []) {
|
|
111
|
+
if (typeof route === "string" && paths.has(route)) again.add(route);
|
|
112
|
+
else refused.push({ route: String(route), because: "it is named as safe to open again, but not as a route with a record" });
|
|
113
|
+
}
|
|
114
|
+
return { ok: true, examples: { paths, refused, again } };
|
|
110
115
|
}
|
|
111
116
|
function resolveVisit(route, examples) {
|
|
112
117
|
const needs = dynamicSegments(route);
|
|
@@ -1298,7 +1303,9 @@ async function phoneFit(page, width) {
|
|
|
1298
1303
|
if (content > laid + 1) return { fits: false, because: `it runs ${Math.round(content - laid)}px off the side` };
|
|
1299
1304
|
const main2 = document.querySelector("main, [role=main]");
|
|
1300
1305
|
const column = main2 ? main2.getBoundingClientRect().width : laid;
|
|
1301
|
-
|
|
1306
|
+
if (column < laid * 0.75) return { fits: false, because: `its main column is ${Math.round(column)}px of ${laid}px, beside the rest of the layout` };
|
|
1307
|
+
const overflow = main2 ? main2.scrollWidth - main2.clientWidth : 0;
|
|
1308
|
+
return overflow > 1 ? { fits: false, because: `its content runs ${Math.round(overflow)}px past its main column` } : { fits: true };
|
|
1302
1309
|
},
|
|
1303
1310
|
{ width }
|
|
1304
1311
|
)
|
|
@@ -1336,6 +1343,10 @@ import { createHash } from "node:crypto";
|
|
|
1336
1343
|
var LAYOUT_MANIFEST_SCHEMA = "helpdesk.layout-manifest/1";
|
|
1337
1344
|
var PHONE_SUFFIX = "--phone";
|
|
1338
1345
|
var PHONE_VIEWPORT = { width: 390, height: 844 };
|
|
1346
|
+
var PHONE_VIEWPORTS = [PHONE_VIEWPORT, { width: 430, height: 932 }];
|
|
1347
|
+
function phoneViewport(width) {
|
|
1348
|
+
return PHONE_VIEWPORTS.find((viewport) => viewport.width === width) ?? PHONE_VIEWPORT;
|
|
1349
|
+
}
|
|
1339
1350
|
var CONTROL_ROLES = [
|
|
1340
1351
|
"button",
|
|
1341
1352
|
"link",
|
|
@@ -2584,7 +2595,7 @@ async function runCapture(options) {
|
|
|
2584
2595
|
const evidence = [];
|
|
2585
2596
|
const build = await options.browser.build?.().catch(() => void 0);
|
|
2586
2597
|
for (const [index, shot] of options.shots.entries()) {
|
|
2587
|
-
const taken = await captureOne(options, shot, build);
|
|
2598
|
+
const taken = shot.variant === "phone" ? await captureAtPhoneWidths(options, shot, build) : await captureOne(options, shot, build);
|
|
2588
2599
|
const outcome = shot.variant ? { ...taken.outcome, variant: shot.variant } : taken.outcome;
|
|
2589
2600
|
outcomes.push(outcome);
|
|
2590
2601
|
if (taken.observed && !shot.variant) survey.push(taken.observed);
|
|
@@ -2632,6 +2643,19 @@ async function layoutOf(page, shot, options, cover, size, landed) {
|
|
|
2632
2643
|
return void 0;
|
|
2633
2644
|
}
|
|
2634
2645
|
}
|
|
2646
|
+
async function captureAtPhoneWidths(options, shot, build) {
|
|
2647
|
+
const tried = [];
|
|
2648
|
+
let taken;
|
|
2649
|
+
for (const { width } of PHONE_VIEWPORTS) {
|
|
2650
|
+
taken = await captureOne(options, { ...shot, phoneWidth: width }, build);
|
|
2651
|
+
if (taken.unfit === void 0) return taken;
|
|
2652
|
+
tried.push(`at ${width}px ${taken.unfit}`);
|
|
2653
|
+
}
|
|
2654
|
+
return {
|
|
2655
|
+
...taken,
|
|
2656
|
+
outcome: { ...taken.outcome, reason: `not laid out for a phone (${tried.join("; ")}), so there is no phone-width frame` }
|
|
2657
|
+
};
|
|
2658
|
+
}
|
|
2635
2659
|
async function captureOne(options, shot, build) {
|
|
2636
2660
|
if (shot.unvisitable) {
|
|
2637
2661
|
return { outcome: { shotId: shot.id, route: shot.route, status: "skipped", reason: shot.unvisitable } };
|
|
@@ -2639,7 +2663,7 @@ async function captureOne(options, shot, build) {
|
|
|
2639
2663
|
const visit = shot.visit ?? shot.route;
|
|
2640
2664
|
let page;
|
|
2641
2665
|
try {
|
|
2642
|
-
page = await options.browser.page(shot.variant ? { variant: shot.variant } : void 0);
|
|
2666
|
+
page = await options.browser.page(shot.variant ? { variant: shot.variant, ...shot.phoneWidth ? { width: shot.phoneWidth } : {} } : void 0);
|
|
2643
2667
|
await page.goto(new URL(visit, options.baseUrl).toString());
|
|
2644
2668
|
if (await page.isSignIn()) {
|
|
2645
2669
|
return {
|
|
@@ -2700,9 +2724,10 @@ async function captureOne(options, shot, build) {
|
|
|
2700
2724
|
route: shot.route,
|
|
2701
2725
|
status: "skipped",
|
|
2702
2726
|
result: observed.result,
|
|
2703
|
-
reason: `not laid out for a phone at ${
|
|
2727
|
+
reason: `not laid out for a phone at ${phoneViewport(shot.phoneWidth).width}px (${fit.because}), so there is no phone-width frame`
|
|
2704
2728
|
},
|
|
2705
|
-
observed
|
|
2729
|
+
observed,
|
|
2730
|
+
unfit: fit.because
|
|
2706
2731
|
};
|
|
2707
2732
|
}
|
|
2708
2733
|
const evidence = shot.variant ? void 0 : await readEvidence(settledPage, shot.route, options, build, visit);
|
|
@@ -2769,7 +2794,7 @@ async function captureOne(options, shot, build) {
|
|
|
2769
2794
|
});
|
|
2770
2795
|
const image = frame.value;
|
|
2771
2796
|
const size = pngSize(image);
|
|
2772
|
-
const minimum = shot.variant === "phone" ?
|
|
2797
|
+
const minimum = shot.variant === "phone" ? phoneViewport(shot.phoneWidth).width * CAPTURE_CONTRACT.stillScale : CAPTURE_CONTRACT.minStillWidth;
|
|
2773
2798
|
if (size && size.width < minimum) {
|
|
2774
2799
|
return {
|
|
2775
2800
|
outcome: {
|
|
@@ -2988,8 +3013,9 @@ async function playwrightBrowser(options = {}) {
|
|
|
2988
3013
|
};
|
|
2989
3014
|
return {
|
|
2990
3015
|
async page(wanted) {
|
|
3016
|
+
const phone = phoneViewport(wanted?.width);
|
|
2991
3017
|
const context = await browser.newContext(
|
|
2992
|
-
wanted?.variant === "phone" ? { ...contextOptions, viewport: { ...
|
|
3018
|
+
wanted?.variant === "phone" ? { ...contextOptions, viewport: { ...phone }, isMobile: true, hasTouch: true } : wanted?.variant === "clip" ? { ...contextOptions, viewport: { ...CLIP_VIEWPORT }, deviceScaleFactor: CAPTURE_CONTRACT.clipScale } : contextOptions
|
|
2993
3019
|
);
|
|
2994
3020
|
if (!options.liveClock) {
|
|
2995
3021
|
await context.addInitScript(freezeScript(CAPTURE_CONTRACT.pinnedClock));
|
|
@@ -3068,7 +3094,7 @@ async function playwrightBrowser(options = {}) {
|
|
|
3068
3094
|
return readPageLayout(page, cover ?? []);
|
|
3069
3095
|
},
|
|
3070
3096
|
async phoneFit() {
|
|
3071
|
-
return phoneFit(page,
|
|
3097
|
+
return phoneFit(page, phone.width).catch(() => ({ fits: false, because: "the page could not be measured at that width" }));
|
|
3072
3098
|
},
|
|
3073
3099
|
async location() {
|
|
3074
3100
|
const url = new URL(page.url());
|
|
@@ -4669,11 +4695,18 @@ function shotsFromRepo(repo, previous) {
|
|
|
4669
4695
|
}))
|
|
4670
4696
|
);
|
|
4671
4697
|
}
|
|
4672
|
-
function withPhoneShots(shots, previous) {
|
|
4698
|
+
function withPhoneShots(shots, previous, again = /* @__PURE__ */ new Set()) {
|
|
4673
4699
|
const planned = new Set(shots.map((shot) => shot.id));
|
|
4674
|
-
const phones = shots.filter((shot) => !shot.visit && !shot.unvisitable && !shot.variant && !planned.has(`${shot.id}${PHONE_SUFFIX}`)).map((shot) => {
|
|
4700
|
+
const phones = shots.filter((shot) => (!shot.visit || again.has(shot.route)) && !shot.unvisitable && !shot.variant && !planned.has(`${shot.id}${PHONE_SUFFIX}`)).map((shot) => {
|
|
4675
4701
|
const id = `${shot.id}${PHONE_SUFFIX}`;
|
|
4676
|
-
return {
|
|
4702
|
+
return {
|
|
4703
|
+
id,
|
|
4704
|
+
route: shot.route,
|
|
4705
|
+
...shot.visit ? { visit: shot.visit } : {},
|
|
4706
|
+
depicts: `${shot.depicts}, at phone width`,
|
|
4707
|
+
variant: "phone",
|
|
4708
|
+
...seenBefore(previous.get(id))
|
|
4709
|
+
};
|
|
4677
4710
|
});
|
|
4678
4711
|
return [...shots, ...phones];
|
|
4679
4712
|
}
|
|
@@ -4943,7 +4976,7 @@ Approve one on the plan page, then run this again.`
|
|
|
4943
4976
|
}
|
|
4944
4977
|
}
|
|
4945
4978
|
const withRecords = seeded?.examples ? withExamples(shots, seeded.examples) : shots;
|
|
4946
|
-
const planned = seededLast(parsed.phone ? withPhoneShots(withRecords, previous) : withRecords);
|
|
4979
|
+
const planned = seededLast(parsed.phone ? withPhoneShots(withRecords, previous, seeded?.examples?.again) : withRecords);
|
|
4947
4980
|
if (parsed.cassette) {
|
|
4948
4981
|
try {
|
|
4949
4982
|
stage = await stageAgainstRecording({
|
|
@@ -4993,7 +5026,7 @@ Approve one on the plan page, then run this again.`
|
|
|
4993
5026
|
console.log(`${coverageReport(found, shots.length).join("\n")}
|
|
4994
5027
|
`);
|
|
4995
5028
|
}
|
|
4996
|
-
const phones = parsed.phone ? `, each opened at its own address again at ${
|
|
5029
|
+
const phones = parsed.phone ? `, each opened at its own address again at phone width (${PHONE_VIEWPORTS.map((viewport) => `${viewport.width}px`).join(", then ")}) if it is laid out for a phone` : "";
|
|
4997
5030
|
console.log(
|
|
4998
5031
|
stage ? `Photographing ${shots.length} screen(s) of ${baseUrl}${phones}, served from ${parsed.cassette}.
|
|
4999
5032
|
` : `Photographing ${shots.length} screen(s) of ${baseUrl}${phones}.
|