From d4bc6246f16fddd6c79cd6761717e45efb75033a Mon Sep 17 00:00:00 2001 From: Dmitry S Date: Mon, 22 May 2023 15:55:20 -0400 Subject: [PATCH] (core) Fix breakage on Firefox iOS Summary: Grist recently stopped working on Firefox on iOS. The cause turns out an uncaught error, which is reported as an unhelpful "Script Error", but the act of reporting it causes additional errors, leading to an infinite loop and an unusable browser tab. Firefox-iOS is to blame, but a workaround is preventing a flood of "Script Error" messages. Specifically, we report only the first of these, and only to the server, suppressing the user-visible toast. Test Plan: Tested manually on Firefox on iOS. Added a test case, and improve other tests of uncaught errors. Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D3902 --- app/client/models/errors.ts | 26 +++++++++++++++++++++++--- test/nbrowser/gristUtils.ts | 13 +++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/app/client/models/errors.ts b/app/client/models/errors.ts index ee388556..c884b04b 100644 --- a/app/client/models/errors.ts +++ b/app/client/models/errors.ts @@ -70,6 +70,18 @@ export function reportSuccess(msg: MessageType, options?: Partial - doReportError(err || ev)); + G.window.addEventListener('error', (ev: ErrorEvent) => doReportError(ev.error || ev.message, ev)); G.window.addEventListener('unhandledrejection', (ev: any) => { const reason = ev.reason || (ev.detail && ev.detail.reason); diff --git a/test/nbrowser/gristUtils.ts b/test/nbrowser/gristUtils.ts index 63b3755e..e9b9250d 100644 --- a/test/nbrowser/gristUtils.ts +++ b/test/nbrowser/gristUtils.ts @@ -3068,6 +3068,19 @@ export async function assertIsRickRowing(expected: boolean) { assert.equal(await driver.find('iframe#youtube-player-dQw4w9WgXcQ').isPresent(), expected); } + +export function produceUncaughtError(message: string) { + // Simply throwing an error from driver.executeScript() may produce a sanitized "Script error", + // depending on browser/webdriver version. This is a trick to ensure the uncaught error is + // considered same-origin by the main window. + return driver.executeScript((msg: string) => { + const script = document.createElement("script"); + script.type = "text/javascript"; + script.innerText = 'setTimeout(() => { throw new Error(' + JSON.stringify(msg) + '); }, 0)'; + document.head.appendChild(script); + }, message); +} + } // end of namespace gristUtils stackWrapOwnMethods(gristUtils);