From e1ec945584e6b98de5e6cc81c43c7960c807bfee Mon Sep 17 00:00:00 2001 From: tianma-if Date: Wed, 16 Sep 2026 18:52:37 +0800 Subject: [PATCH] fix(desktop): keep Windows protocol e2e off stale DOM nodes The packaged Windows file-input check used a document nodeId that React replaced during bootstrap, so CDP could not attach the fixture. --- scripts/desktop-build-workflow.test.mjs | 3 ++ scripts/verify-desktop-protocol-e2e.mjs | 61 ++++++++++++++++++++----- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/scripts/desktop-build-workflow.test.mjs b/scripts/desktop-build-workflow.test.mjs index b3fd6f23..9872fa66 100644 --- a/scripts/desktop-build-workflow.test.mjs +++ b/scripts/desktop-build-workflow.test.mjs @@ -116,6 +116,9 @@ describe("desktop release workflow", () => { expect(protocolE2eVerifier).toContain('fetch("edgeever-staged://" + pending.id)'); expect(protocolE2eVerifier).toContain('const url = "edgeever-resource://resource/${cachedResourceId}"'); expect(protocolE2eVerifier).toContain('DOM.setFileInputFiles'); + expect(protocolE2eVerifier).toContain("renderer.bootstrap-ready"); + expect(protocolE2eVerifier).toContain("objectId"); + expect(protocolE2eVerifier).not.toContain("documentNode.root.nodeId"); expect(protocolE2eVerifier).toContain('Browser.setDownloadBehavior'); expect(packagedStartupVerifier).toContain('new Set(["renderer.origin-ready", "sidecar.ready", "renderer.bootstrap-ready"])'); expect(packagedStartupVerifier).toContain('"renderer.origin-ready"'); diff --git a/scripts/verify-desktop-protocol-e2e.mjs b/scripts/verify-desktop-protocol-e2e.mjs index aba2cc8b..660cf4b3 100644 --- a/scripts/verify-desktop-protocol-e2e.mjs +++ b/scripts/verify-desktop-protocol-e2e.mjs @@ -133,6 +133,53 @@ const waitForDownloadedFile = async () => { throw new Error(`Resource download did not create ${downloadedPath}`); }; +const waitForRendererBootstrap = async () => { + const diagnosticLogPath = join(userDataDirectory, "logs", "desktop.log"); + const deadline = Date.now() + (Number(process.env.EDGE_EVER_DESKTOP_E2E_TIMEOUT_MS) || 45_000); + while (Date.now() < deadline) { + if (existsSync(diagnosticLogPath)) { + const log = await readFile(diagnosticLogPath, "utf8"); + if (log.includes("renderer.bootstrap-ready")) return; + } + if (child?.exitCode !== null) break; + await wait(100); + } + throw new Error("Renderer bootstrap did not complete before protocol e2e"); +}; + +const attachFileToInput = async (filePath) => { + const deadline = Date.now() + 15_000; + let lastError = null; + while (Date.now() < deadline) { + try { + const created = await cdp.send("Runtime.evaluate", { + expression: `(() => { + let input = document.querySelector("#edgeever-protocol-file-input"); + if (!input) { + input = document.createElement("input"); + input.id = "edgeever-protocol-file-input"; + input.type = "file"; + document.body.append(input); + } + return input; + })()`, + }); + const objectId = created.result?.objectId; + if (!objectId) throw new Error("File input object is missing"); + await cdp.send("DOM.setFileInputFiles", { objectId, files: [filePath] }); + const hasFile = await evaluate( + `document.querySelector("#edgeever-protocol-file-input")?.files?.length === 1`, + ); + if (hasFile) return; + lastError = new Error("File input did not retain the attached file"); + } catch (error) { + lastError = error; + } + await wait(200); + } + throw lastError ?? new Error("Could not attach a file to the protocol e2e input"); +}; + try { await mkdir(resourceCacheDirectory, { recursive: true }); await mkdir(join(testDirectory, "downloads"), { recursive: true }); @@ -154,6 +201,7 @@ try { child.stdout?.on("data", (chunk) => processOutput.push(chunk.toString())); child.stderr?.on("data", (chunk) => processOutput.push(chunk.toString())); + await waitForRendererBootstrap(); const target = await findRendererTarget(port); cdp = await connectCdp(target.webSocketDebuggerUrl); await cdp.send("Runtime.enable"); @@ -179,18 +227,7 @@ try { throw new Error(`Bundled marketplace fetch failed: ${JSON.stringify(appProtocol)}`); } - await evaluate(`(() => { - const input = document.createElement("input"); - input.id = "edgeever-protocol-file-input"; - input.type = "file"; - document.body.append(input); - })()`); - const documentNode = await cdp.send("DOM.getDocument"); - const inputNode = await cdp.send("DOM.querySelector", { - nodeId: documentNode.root.nodeId, - selector: "#edgeever-protocol-file-input", - }); - await cdp.send("DOM.setFileInputFiles", { nodeId: inputNode.nodeId, files: [inputFixturePath] }); + await attachFileToInput(inputFixturePath); const staged = await evaluate(`(async () => { const input = document.querySelector("#edgeever-protocol-file-input");