mirror of
https://github.com/getpaseo/paseo.git
synced 2026-08-14 12:23:16 +00:00
Fix fresh browser screenshot prep race
This commit is contained in:
@@ -48,7 +48,8 @@
|
||||
const activeTokens = new Set();
|
||||
let nextTokenId = 0;
|
||||
|
||||
for (let index = 0; index < webviewCount; index += 1) {
|
||||
function appendHarnessWebview(sourceUrl) {
|
||||
const index = webviews.length;
|
||||
const webview = document.createElement("webview");
|
||||
webview.id = `target-webview-${index + 1}`;
|
||||
webview.className = "capture-harness-webview";
|
||||
@@ -57,9 +58,15 @@
|
||||
webview.setAttribute("allowpopups", "true");
|
||||
webview.setAttribute("spellcheck", "false");
|
||||
webview.setAttribute("autosize", "on");
|
||||
webview.src = params.get("targetUrl") || "bright.html";
|
||||
webview.src = sourceUrl;
|
||||
applyStackedWebviewStyle(webview);
|
||||
host.appendChild(webview);
|
||||
webviews.push(webview);
|
||||
return index;
|
||||
}
|
||||
|
||||
for (let index = 0; index < webviewCount; index += 1) {
|
||||
appendHarnessWebview(params.get("targetUrl") || "bright.html");
|
||||
}
|
||||
|
||||
function applyHostParking() {
|
||||
@@ -203,6 +210,9 @@
|
||||
typeof webview.getWebContentsId === "function" ? webview.getWebContentsId() : null,
|
||||
);
|
||||
},
|
||||
addWebview(sourceUrl) {
|
||||
return appendHarnessWebview(sourceUrl || params.get("targetUrl") || "bright.html");
|
||||
},
|
||||
async prepareForPixelCapture(targetIndex = 0) {
|
||||
const token = `capture-${++nextTokenId}`;
|
||||
activeTokens.add(token);
|
||||
|
||||
@@ -143,7 +143,7 @@ async function saveImage(image, outputPath) {
|
||||
await fsp.writeFile(outputPath, image.toPNG());
|
||||
}
|
||||
|
||||
async function waitForGuestLoad(contents) {
|
||||
async function waitForGuestLoad(contents, input = {}) {
|
||||
await new Promise((resolve) => {
|
||||
if (!contents.isLoading()) {
|
||||
resolve();
|
||||
@@ -152,7 +152,10 @@ async function waitForGuestLoad(contents) {
|
||||
contents.once("did-finish-load", resolve);
|
||||
contents.once("did-fail-load", resolve);
|
||||
});
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
const settleMs = input.settleMs ?? 500;
|
||||
if (settleMs > 0) {
|
||||
await new Promise((resolve) => setTimeout(resolve, settleMs));
|
||||
}
|
||||
}
|
||||
|
||||
async function renderer(win, expression) {
|
||||
@@ -228,14 +231,23 @@ async function captureFullPage(contents) {
|
||||
}
|
||||
}
|
||||
|
||||
async function captureWithPrep({ win, contents, mode, repeatIndex, targetIndex, guestMetrics }) {
|
||||
async function captureWithPrep({
|
||||
win,
|
||||
contents,
|
||||
mode,
|
||||
repeatIndex,
|
||||
targetIndex,
|
||||
guestMetrics,
|
||||
repeatTotal = REPEAT_COUNT,
|
||||
label = "prep",
|
||||
}) {
|
||||
const preparation = await renderer(
|
||||
win,
|
||||
`window.captureHarness.prepareForPixelCapture(${JSON.stringify(targetIndex)})`,
|
||||
);
|
||||
const outputPath = path.join(
|
||||
OUT_DIR,
|
||||
`${mode}-webview-${targetIndex + 1}-prep-${repeatIndex}.png`,
|
||||
`${mode}-webview-${targetIndex + 1}-${label}-${repeatIndex}.png`,
|
||||
);
|
||||
try {
|
||||
const image =
|
||||
@@ -251,11 +263,11 @@ async function captureWithPrep({ win, contents, mode, repeatIndex, targetIndex,
|
||||
const bright = analysis.brightRatio.toFixed(4);
|
||||
if (!analysis.pass) {
|
||||
fail(
|
||||
`${mode} webview ${targetIndex + 1} prep ${repeatIndex}/${REPEAT_COUNT} size=${size} logical=${logicalSize} bright=${bright} text=${analysis.textNonUniform} file=${outputPath}`,
|
||||
`${mode} webview ${targetIndex + 1} ${label} ${repeatIndex}/${repeatTotal} size=${size} logical=${logicalSize} bright=${bright} text=${analysis.textNonUniform} file=${outputPath}`,
|
||||
);
|
||||
}
|
||||
pass(
|
||||
`${mode} webview ${targetIndex + 1} prep ${repeatIndex}/${REPEAT_COUNT} size=${size} logical=${logicalSize} bright=${bright} text=${analysis.textNonUniform} file=${outputPath}`,
|
||||
`${mode} webview ${targetIndex + 1} ${label} ${repeatIndex}/${repeatTotal} size=${size} logical=${logicalSize} bright=${bright} text=${analysis.textNonUniform} file=${outputPath}`,
|
||||
);
|
||||
return analysis;
|
||||
} finally {
|
||||
@@ -308,14 +320,58 @@ async function expectLegacySecondWebviewFailure({ win, contents, mode, guestMetr
|
||||
}
|
||||
}
|
||||
|
||||
async function captureFreshWebviewImmediately({ win, waitForNextAttachedGuest }) {
|
||||
const freshGuestPromise = waitForNextAttachedGuest();
|
||||
const targetIndex = await renderer(
|
||||
win,
|
||||
`window.captureHarness.addWebview(${JSON.stringify(fileUrl(path.join(ROOT, "bright.html")))})`,
|
||||
);
|
||||
const guest = await withTimeout(freshGuestPromise, "fresh did-attach-webview");
|
||||
await waitForGuestLoad(guest, { settleMs: 0 });
|
||||
const guestMetrics = await readGuestMetrics(guest);
|
||||
if (guestMetrics.innerWidth !== VIEWPORT_WIDTH || guestMetrics.innerHeight !== VIEWPORT_HEIGHT) {
|
||||
fail(
|
||||
`fresh guest viewport sizing webview ${targetIndex + 1} inner=${guestMetrics.innerWidth}x${guestMetrics.innerHeight} expected=${VIEWPORT_WIDTH}x${VIEWPORT_HEIGHT}`,
|
||||
);
|
||||
}
|
||||
pass(
|
||||
`fresh guest viewport sizing webview ${targetIndex + 1} inner=${guestMetrics.innerWidth}x${guestMetrics.innerHeight} dpr=${guestMetrics.devicePixelRatio}`,
|
||||
);
|
||||
await captureWithPrep({
|
||||
win,
|
||||
contents: guest,
|
||||
mode: "viewport",
|
||||
repeatIndex: 1,
|
||||
targetIndex,
|
||||
guestMetrics,
|
||||
repeatTotal: 1,
|
||||
label: "fresh-immediate",
|
||||
});
|
||||
await captureWithPrep({
|
||||
win,
|
||||
contents: guest,
|
||||
mode: "full-page",
|
||||
repeatIndex: 1,
|
||||
targetIndex,
|
||||
guestMetrics,
|
||||
repeatTotal: 1,
|
||||
label: "fresh-immediate",
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
ensureDirSync(OUT_DIR);
|
||||
|
||||
const attachedGuests = [];
|
||||
const freshGuestWaiters = [];
|
||||
let resolveGuests;
|
||||
const guestsPromise = new Promise((resolve) => {
|
||||
resolveGuests = resolve;
|
||||
});
|
||||
const waitForNextAttachedGuest = () =>
|
||||
new Promise((resolve) => {
|
||||
freshGuestWaiters.push(resolve);
|
||||
});
|
||||
const win = new BrowserWindow({
|
||||
width: 1000,
|
||||
height: 700,
|
||||
@@ -335,6 +391,10 @@ async function main() {
|
||||
});
|
||||
win.webContents.on("did-attach-webview", (_event, contents) => {
|
||||
attachedGuests.push(contents);
|
||||
const waiter = freshGuestWaiters.shift();
|
||||
if (waiter) {
|
||||
waiter(contents);
|
||||
}
|
||||
if (attachedGuests.length >= 2) {
|
||||
resolveGuests(attachedGuests);
|
||||
}
|
||||
@@ -398,6 +458,9 @@ async function main() {
|
||||
|
||||
await renderer(win, "window.captureHarness.restoreParking()");
|
||||
|
||||
await captureFreshWebviewImmediately({ win, waitForNextAttachedGuest });
|
||||
await renderer(win, "window.captureHarness.restoreParking()");
|
||||
|
||||
const results = [];
|
||||
for (const targetIndex of [0, 1]) {
|
||||
for (let index = 1; index <= REPEAT_COUNT; index += 1) {
|
||||
|
||||
Reference in New Issue
Block a user