mirror of
https://github.com/electron/electron.git
synced 2026-10-28 11:44:46 +08:00
test: fix retry-reliant webview and debugger specs (#55227)
debugger.sendCommand "does not crash for invalid unicode characters in message" attached to a window that had never loaded anything and sent Network.enable without waiting for it. With no renderer yet, the command only reached the renderer during the first navigation, and Network.loadingFinished was sometimes never reported. Load about:blank first, attach, await Network.enable, then navigate. <webview>.reload() "should emit beforeunload handler": the guest has no user gesture, so Chromium skips the beforeunload confirmation and the reload goes ahead. The fixture's IPC, deferred with setTimeout(0) in the hidden window, could be dropped when the document unloaded. Send it synchronously from the handler. <webview> "follows the embedder window when it is hidden and shown again" took the guest's next visibility report as the state to check, but the guest can report 'hidden' before the embedder has shown it. Wait for each expected state instead, and run the suite serially like the BrowserWindow visibilityState specs, since on macOS a window from another spec worker can occlude the embedder. Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
1 parent
6408a0c6bb
commit
0187553fce
3 files changed
+38
-25
No files matched your search
+15
-14
@@ -235,27 +235,28 @@ describe('debugger module', () => {
|
||||
});
|
||||
|
||||
it('does not crash for invalid unicode characters in message', async () => {
|
||||
w.webContents.debugger.attach();
|
||||
|
||||
const loadingFinished = new Promise<void>((resolve) => {
|
||||
w.webContents.debugger.on('message', (event, method) => {
|
||||
// loadingFinished indicates that page has been loaded and it did not
|
||||
// crash because of invalid UTF-8 data
|
||||
if (method === 'Network.loadingFinished') {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
server = http.createServer((req, res) => {
|
||||
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
||||
res.end('\uFFFF');
|
||||
});
|
||||
|
||||
const { url } = await listen(server);
|
||||
w.webContents.debugger.sendCommand('Network.enable');
|
||||
w.loadURL(url);
|
||||
// Network.enable only reaches the renderer once it exists. On a fresh
|
||||
// window that is during the first navigation, which can then finish
|
||||
// before the renderer reports Network.loadingFinished. Load a page
|
||||
// first and wait for Network.enable before the real navigation.
|
||||
await w.loadURL('about:blank');
|
||||
w.webContents.debugger.attach();
|
||||
await w.webContents.debugger.sendCommand('Network.enable');
|
||||
|
||||
// loadingFinished indicates that page has been loaded and it did not
|
||||
// crash because of invalid UTF-8 data
|
||||
const loadingFinished = emittedUntil(
|
||||
w.webContents.debugger,
|
||||
'message',
|
||||
(_event: any, method: string) => method === 'Network.loadingFinished'
|
||||
);
|
||||
await w.loadURL(url);
|
||||
await loadingFinished;
|
||||
});
|
||||
|
||||
|
||||
+5
-4
@@ -2,10 +2,11 @@
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
window.onbeforeunload = function() {
|
||||
setTimeout(function() {
|
||||
var ipcRenderer = require('electron').ipcRenderer;
|
||||
ipcRenderer.sendToHost('onbeforeunload');
|
||||
}, 0);
|
||||
// Report synchronously. Without a user gesture Chromium skips the
|
||||
// confirmation and the navigation goes ahead, so a deferred message can
|
||||
// be dropped when this document unloads.
|
||||
var ipcRenderer = require('electron').ipcRenderer;
|
||||
ipcRenderer.sendToHost('onbeforeunload');
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
|
||||
+18
-7
@@ -230,37 +230,48 @@ describe('<webview> tag', () => {
|
||||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform !== 'win32')('document.visibilityState/hidden', () => {
|
||||
// The guest's visibility follows whether the embedder window is actually on
|
||||
// screen, so this needs the screen to itself (see the BrowserWindow
|
||||
// visibilityState specs): on macOS a window from another spec worker can
|
||||
// occlude this one and hide the guest.
|
||||
ifdescribe(process.platform !== 'win32')('document.visibilityState/hidden', { tags: ['serial'] }, () => {
|
||||
afterEach(() => {
|
||||
ipcMain.removeAllListeners('pong');
|
||||
});
|
||||
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
// The guest reports its state when its script runs and on every
|
||||
// visibilitychange. Wait for the expected state rather than taking the
|
||||
// next report: the guest can run its script while it is still being
|
||||
// attached, before the embedder has shown it, and report 'hidden' first.
|
||||
const guestVisibility = (state: 'visible' | 'hidden') =>
|
||||
emittedUntil(ipcMain, 'pong', (_event: unknown, visibilityState: string) => visibilityState === state);
|
||||
|
||||
it('follows the embedder window when it is hidden and shown again', async () => {
|
||||
const w = new BrowserWindow({
|
||||
width: 100,
|
||||
height: 100,
|
||||
webPreferences: { webviewTag: true, nodeIntegration: true, contextIsolation: false }
|
||||
});
|
||||
const initiallyVisible = guestVisibility('visible');
|
||||
w.loadFile(path.join(fixtures, 'pages', 'webview-visibilitychange.html'));
|
||||
{
|
||||
const [, visibilityState, hidden] = await once(ipcMain, 'pong');
|
||||
expect(visibilityState).toBe('visible');
|
||||
const [, , hidden] = await initiallyVisible;
|
||||
expect(hidden).toBe(false);
|
||||
}
|
||||
|
||||
const hiddenState = guestVisibility('hidden');
|
||||
w.hide();
|
||||
{
|
||||
const [, visibilityState, hidden] = await once(ipcMain, 'pong');
|
||||
expect(visibilityState).toBe('hidden');
|
||||
const [, , hidden] = await hiddenState;
|
||||
expect(hidden).toBe(true);
|
||||
}
|
||||
|
||||
const visibleState = guestVisibility('visible');
|
||||
w.show();
|
||||
{
|
||||
const [, visibilityState, hidden] = await once(ipcMain, 'pong');
|
||||
expect(visibilityState).toBe('visible');
|
||||
const [, , hidden] = await visibleState;
|
||||
expect(hidden).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user