mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
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>
70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
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);
|
||
}
|