Files
iptvnator/apps/electron-backend-e2e/src/renderer-reload.support.ts
T
4grayandClaude Fable 5.1 6f987d79d8 fix(shell): reload the packaged renderer back onto its in-app route (#1622)
The packaged renderer is index.html over file:// with path routing, so
after in-app navigation the document URL names a path with no file behind
it. A main-process reload (macOS View > Reload, DevTools) failed with
ERR_FILE_NOT_FOUND and stranded the window on Chromium's error page; a
renderer-initiated reload (the settings unsaved-changes guard's confirmed
location.reload()) was cancelled by the will-navigate trust check and
silently did nothing.

Both legs now re-load the packaged index with the route in a restoreRoute
query parameter, which main.ts restores with history.replaceState before
Angular bootstraps. The did-fail-load recovery is deferred to the error
page's dom-ready: a load issued from inside the failure event yields a
document that never receives animation frames and never paints.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 08:43:43 +02:00

70 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, Page } from '@playwright/test';
import { LaunchedElectronApp } from './electron-test-fixtures';
/**
* Helpers for E2E that reload the packaged renderer on an in-app route.
*
* The URL before and after a recovered reload is the same routed `file://`
* URL, so waiting on the URL alone passes before anything happened. The
* current document is marked instead, and the wait is for a document
* WITHOUT the mark that has reached the route.
*/
const DOCUMENT_MARK = 'data-e2e-pre-reload';
async function markCurrentDocument(page: Page): Promise<void> {
await page.evaluate((attribute) => {
document.documentElement.setAttribute(attribute, '');
}, DOCUMENT_MARK);
}
/** What the macOS View › Reload menu role does: `webContents.reload()`. */
export async function reloadFromMainProcess(
app: LaunchedElectronApp
): Promise<void> {
await markCurrentDocument(app.mainWindow);
await app.electronApp.evaluate(({ BrowserWindow }) => {
const [win] = BrowserWindow.getAllWindows();
win.webContents.reload();
});
}
/**
* What the settings unsaved-changes guard does after a confirmed reload:
* `window.location.reload()`. The evaluate may lose its execution context
* to the navigation it starts; that is not a failure.
*/
export async function reloadFromRenderer(
app: LaunchedElectronApp
): Promise<void> {
await markCurrentDocument(app.mainWindow);
await app.mainWindow
.evaluate(() => {
window.location.reload();
})
.catch(() => undefined);
}
/**
* Waits until a NEW document is rendered on `pathname` — the app re-booted
* on the route rather than the old document still being on screen — and
* checks that the restore parameter was consumed on the way.
*/
export async function expectRendererReloadedOnRoute(
page: Page,
pathname: RegExp
): Promise<void> {
await expect(page.locator(`html[${DOCUMENT_MARK}]`)).toHaveCount(0);
await expect(page).toHaveURL(pathname);
await expect
.poll(() =>
page.evaluate(
() =>
document.querySelector('app-root')?.innerHTML.trim()
.length ?? 0
)
)
.toBeGreaterThan(0);
expect(new URL(page.url()).searchParams.has('restoreRoute')).toBe(false);
}