Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/viewer/sharing/summarize-with-chatgpt.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,15 @@ function registerPdfTransfer(requestId, filename) {
let awaitingAck;
const expire = setTimeout(() => port.disconnect(), 120000);
port.onDisconnect.addListener(() => {
// Chrome reports a missing receiver through lastError on disconnect.
// Reading it here also prevents an "Unchecked runtime.lastError" warning.
const disconnectError = chrome.runtime.lastError?.message;
stopped = true;
if (awaitingAck) awaitingAck.reject(new Error("PDF transfer disconnected"));
clearTimeout(expire);
if (awaitingAck) {
awaitingAck.reject(new Error(disconnectError || "PDF transfer disconnected"));
awaitingAck = null;
}
});
port.onMessage.addListener((message) => {
if (message?.type === "ack" && awaitingAck) {
Expand Down
41 changes: 36 additions & 5 deletions tests/chatgpt-summary-popup.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ function setup({ width = 1080, height = 1920, popupFails = false } = {}) {
let resolveUrl;
const listeners = new Map();
const calls = [];
let onDisconnect;
let lastErrorReads = 0;
const button = {
title: "Summarize with ChatGPT",
attributes: {},
Expand All @@ -25,10 +27,20 @@ function setup({ width = 1080, height = 1920, popupFails = false } = {}) {
window: { screen: { availWidth: width, availHeight: height } },
resolveDocumentReferenceUrl: () => new Promise((resolve) => { resolveUrl = resolve; }),
chrome: {
runtime: { connect(options) {
calls.push(["connect", options]);
return { onMessage: { addListener() {} }, onDisconnect: { addListener() {} }, disconnect() {} };
} },
runtime: {
get lastError() {
lastErrorReads += 1;
return { message: "Could not establish connection. Receiving end does not exist." };
},
connect(options) {
calls.push(["connect", options]);
return {
onMessage: { addListener() {} },
onDisconnect: { addListener(listener) { onDisconnect = listener; } },
disconnect() {},
};
},
},
windows: { async create(options) {
calls.push(["popup", options]);
if (popupFails) throw new Error("Popup unavailable");
Expand All @@ -46,7 +58,15 @@ function setup({ width = 1080, height = 1920, popupFails = false } = {}) {
},
};
vm.runInNewContext(source, context);
return { click: () => listeners.get("click")(), dispatch: (event) => listeners.get(event)(), resolveUrl, calls, button };
return {
click: () => listeners.get("click")(),
dispatch: (event) => listeners.get(event)(),
resolveUrl,
calls,
button,
disconnect: () => onDisconnect?.(),
get lastErrorReads() { return lastErrorReads; },
};
}

test("opens the portrait popup before PDF metadata resolves, then stores the prompt before navigation", async () => {
Expand Down Expand Up @@ -120,3 +140,14 @@ test("local file URLs are not substituted for PDF attachments", async () => {
assert.ok(!data.prompt.includes("file:///Users/"));
assert.equal(fixture.calls.find(([action]) => action === "connect")[1].name, "pdf-summary-source:request");
});

test("consumes Chrome's missing-receiver error on PDF summary disconnection", async () => {
const fixture = setup();
const pendingClick = fixture.click();
fixture.resolveUrl("https://www.sec.gov/files/rules/other/34-16900.pdf");
await pendingClick;

assert.equal(fixture.lastErrorReads, 0);
fixture.disconnect();
assert.equal(fixture.lastErrorReads, 1);
});
Loading