refactor: move JS dialog handling to JS (#40598)
This commit is contained in:
parent
ee8d97d7fe
commit
85bc005cd6
8 changed files with 302 additions and 200 deletions
|
@ -1,5 +1,5 @@
|
|||
import { expect } from 'chai';
|
||||
import { BrowserWindow, WebContents, webFrameMain, session, ipcMain, app, protocol, webContents } from 'electron/main';
|
||||
import { BrowserWindow, WebContents, webFrameMain, session, ipcMain, app, protocol, webContents, dialog, MessageBoxOptions } from 'electron/main';
|
||||
import { closeAllWindows } from './lib/window-helpers';
|
||||
import * as https from 'node:https';
|
||||
import * as http from 'node:http';
|
||||
|
@ -2396,6 +2396,26 @@ describe('chromium features', () => {
|
|||
window.alert({ toString: null });
|
||||
}).to.throw('Cannot convert object to primitive value');
|
||||
});
|
||||
|
||||
it('shows a message box', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.loadURL('about:blank');
|
||||
const p = once(w.webContents, '-run-dialog');
|
||||
w.webContents.executeJavaScript('alert("hello")', true);
|
||||
const [info] = await p;
|
||||
expect(info.frame).to.equal(w.webContents.mainFrame);
|
||||
expect(info.messageText).to.equal('hello');
|
||||
expect(info.dialogType).to.equal('alert');
|
||||
});
|
||||
|
||||
it('does not crash if a webContents is destroyed while an alert is showing', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.loadURL('about:blank');
|
||||
const p = once(w.webContents, '-run-dialog');
|
||||
w.webContents.executeJavaScript('alert("hello")', true);
|
||||
await p;
|
||||
w.webContents.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('window.confirm(message, title)', () => {
|
||||
|
@ -2404,6 +2424,160 @@ describe('chromium features', () => {
|
|||
(window.confirm as any)({ toString: null }, 'title');
|
||||
}).to.throw('Cannot convert object to primitive value');
|
||||
});
|
||||
|
||||
it('shows a message box', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.loadURL('about:blank');
|
||||
const p = once(w.webContents, '-run-dialog');
|
||||
const resultPromise = w.webContents.executeJavaScript('confirm("hello")', true);
|
||||
const [info, cb] = await p;
|
||||
expect(info.frame).to.equal(w.webContents.mainFrame);
|
||||
expect(info.messageText).to.equal('hello');
|
||||
expect(info.dialogType).to.equal('confirm');
|
||||
cb(true, '');
|
||||
const result = await resultPromise;
|
||||
expect(result).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('safeDialogs web preference', () => {
|
||||
const originalShowMessageBox = dialog.showMessageBox;
|
||||
afterEach(() => {
|
||||
dialog.showMessageBox = originalShowMessageBox;
|
||||
if (protocol.isProtocolHandled('https')) protocol.unhandle('https');
|
||||
if (protocol.isProtocolHandled('file')) protocol.unhandle('file');
|
||||
});
|
||||
it('does not show the checkbox if not enabled', async () => {
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { safeDialogs: false } });
|
||||
w.loadURL('about:blank');
|
||||
// 1. The first alert() doesn't show the safeDialogs message.
|
||||
dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: false });
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
|
||||
let recordedOpts: MessageBoxOptions | undefined;
|
||||
dialog.showMessageBox = (bw, opts?: MessageBoxOptions) => {
|
||||
recordedOpts = opts;
|
||||
return Promise.resolve({ response: 0, checkboxChecked: false });
|
||||
};
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
expect(recordedOpts?.checkboxLabel).to.equal('');
|
||||
});
|
||||
|
||||
it('is respected', async () => {
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { safeDialogs: true } });
|
||||
w.loadURL('about:blank');
|
||||
// 1. The first alert() doesn't show the safeDialogs message.
|
||||
dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: false });
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
|
||||
// 2. The second alert() shows the message with a checkbox. Respond that we checked it.
|
||||
let recordedOpts: MessageBoxOptions | undefined;
|
||||
dialog.showMessageBox = (bw, opts?: MessageBoxOptions) => {
|
||||
recordedOpts = opts;
|
||||
return Promise.resolve({ response: 0, checkboxChecked: true });
|
||||
};
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
expect(recordedOpts?.checkboxLabel).to.be.a('string').with.length.above(0);
|
||||
|
||||
// 3. The third alert() shouldn't show a dialog.
|
||||
dialog.showMessageBox = () => Promise.reject(new Error('unexpected showMessageBox'));
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
});
|
||||
|
||||
it('shows the safeDialogMessage', async () => {
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { safeDialogs: true, safeDialogsMessage: 'foo bar' } });
|
||||
w.loadURL('about:blank');
|
||||
dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: false });
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
let recordedOpts: MessageBoxOptions | undefined;
|
||||
dialog.showMessageBox = (bw, opts?: MessageBoxOptions) => {
|
||||
recordedOpts = opts;
|
||||
return Promise.resolve({ response: 0, checkboxChecked: true });
|
||||
};
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
expect(recordedOpts?.checkboxLabel).to.equal('foo bar');
|
||||
});
|
||||
|
||||
it('has persistent state across navigations', async () => {
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { safeDialogs: true } });
|
||||
w.loadURL('about:blank');
|
||||
// 1. The first alert() doesn't show the safeDialogs message.
|
||||
dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: false });
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
|
||||
// 2. The second alert() shows the message with a checkbox. Respond that we checked it.
|
||||
dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: true });
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
|
||||
// 3. The third alert() shouldn't show a dialog.
|
||||
dialog.showMessageBox = () => Promise.reject(new Error('unexpected showMessageBox'));
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
|
||||
// 4. After navigating to the same origin, message boxes should still be hidden.
|
||||
w.loadURL('about:blank');
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
});
|
||||
|
||||
it('is separated by origin', async () => {
|
||||
protocol.handle('https', () => new Response(''));
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { safeDialogs: true } });
|
||||
w.loadURL('https://example1');
|
||||
dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: false });
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: true });
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
dialog.showMessageBox = () => Promise.reject(new Error('unexpected showMessageBox'));
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
|
||||
// A different origin is allowed to show message boxes after navigation.
|
||||
w.loadURL('https://example2');
|
||||
let dialogWasShown = false;
|
||||
dialog.showMessageBox = () => {
|
||||
dialogWasShown = true;
|
||||
return Promise.resolve({ response: 0, checkboxChecked: false });
|
||||
};
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
expect(dialogWasShown).to.be.true();
|
||||
|
||||
// Navigating back to the first origin means alerts are blocked again.
|
||||
w.loadURL('https://example1');
|
||||
dialog.showMessageBox = () => Promise.reject(new Error('unexpected showMessageBox'));
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
});
|
||||
|
||||
it('treats different file: paths as different origins', async () => {
|
||||
protocol.handle('file', () => new Response(''));
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { safeDialogs: true } });
|
||||
w.loadURL('file:///path/1');
|
||||
dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: false });
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: true });
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
dialog.showMessageBox = () => Promise.reject(new Error('unexpected showMessageBox'));
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
|
||||
w.loadURL('file:///path/2');
|
||||
let dialogWasShown = false;
|
||||
dialog.showMessageBox = () => {
|
||||
dialogWasShown = true;
|
||||
return Promise.resolve({ response: 0, checkboxChecked: false });
|
||||
};
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
expect(dialogWasShown).to.be.true();
|
||||
});
|
||||
});
|
||||
describe('disableDialogs web preference', () => {
|
||||
const originalShowMessageBox = dialog.showMessageBox;
|
||||
afterEach(() => {
|
||||
dialog.showMessageBox = originalShowMessageBox;
|
||||
if (protocol.isProtocolHandled('https')) protocol.unhandle('https');
|
||||
});
|
||||
it('is respected', async () => {
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { disableDialogs: true } });
|
||||
w.loadURL('about:blank');
|
||||
dialog.showMessageBox = () => Promise.reject(new Error('unexpected message box'));
|
||||
await w.webContents.executeJavaScript('alert("hi")');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue