chore: remove deprecated 'new-window' event (#34526)
This commit is contained in:
parent
32fefb1f50
commit
8646bf8d30
14 changed files with 36 additions and 681 deletions
|
@ -1,3 +0,0 @@
|
||||||
# NewWindowWebContentsEvent Object extends `Event`
|
|
||||||
|
|
||||||
* `newGuest` BrowserWindow (optional)
|
|
|
@ -156,64 +156,6 @@ Returns:
|
||||||
|
|
||||||
Emitted when page receives favicon urls.
|
Emitted when page receives favicon urls.
|
||||||
|
|
||||||
#### Event: 'new-window' _Deprecated_
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
* `event` NewWindowWebContentsEvent
|
|
||||||
* `url` string
|
|
||||||
* `frameName` string
|
|
||||||
* `disposition` string - Can be `default`, `foreground-tab`, `background-tab`,
|
|
||||||
`new-window`, `save-to-disk` and `other`.
|
|
||||||
* `options` BrowserWindowConstructorOptions - The options which will be used for creating the new
|
|
||||||
[`BrowserWindow`](browser-window.md).
|
|
||||||
* `additionalFeatures` string[] - The non-standard features (features not handled
|
|
||||||
by Chromium or Electron) given to `window.open()`. Deprecated, and will now
|
|
||||||
always be the empty array `[]`.
|
|
||||||
* `referrer` [Referrer](structures/referrer.md) - The referrer that will be
|
|
||||||
passed to the new window. May or may not result in the `Referer` header being
|
|
||||||
sent, depending on the referrer policy.
|
|
||||||
* `postBody` [PostBody](structures/post-body.md) (optional) - The post data that
|
|
||||||
will be sent to the new window, along with the appropriate headers that will
|
|
||||||
be set. If no post data is to be sent, the value will be `null`. Only defined
|
|
||||||
when the window is being created by a form that set `target=_blank`.
|
|
||||||
|
|
||||||
Deprecated in favor of [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler).
|
|
||||||
|
|
||||||
Emitted when the page requests to open a new window for a `url`. It could be
|
|
||||||
requested by `window.open` or an external link like `<a target='_blank'>`.
|
|
||||||
|
|
||||||
By default a new `BrowserWindow` will be created for the `url`.
|
|
||||||
|
|
||||||
Calling `event.preventDefault()` will prevent Electron from automatically creating a
|
|
||||||
new [`BrowserWindow`](browser-window.md). If you call `event.preventDefault()` and manually create a new
|
|
||||||
[`BrowserWindow`](browser-window.md) then you must set `event.newGuest` to reference the new [`BrowserWindow`](browser-window.md)
|
|
||||||
instance, failing to do so may result in unexpected behavior. For example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
myBrowserWindow.webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures, referrer, postBody) => {
|
|
||||||
event.preventDefault()
|
|
||||||
const win = new BrowserWindow({
|
|
||||||
webContents: options.webContents, // use existing webContents if provided
|
|
||||||
show: false
|
|
||||||
})
|
|
||||||
win.once('ready-to-show', () => win.show())
|
|
||||||
if (!options.webContents) {
|
|
||||||
const loadOptions = {
|
|
||||||
httpReferrer: referrer
|
|
||||||
}
|
|
||||||
if (postBody != null) {
|
|
||||||
const { data, contentType, boundary } = postBody
|
|
||||||
loadOptions.postData = postBody.data
|
|
||||||
loadOptions.extraHeaders = `content-type: ${contentType}; boundary=${boundary}`
|
|
||||||
}
|
|
||||||
|
|
||||||
win.loadURL(url, loadOptions) // existing webContents will be navigated automatically
|
|
||||||
}
|
|
||||||
event.newGuest = win
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Event: 'did-create-window'
|
#### Event: 'did-create-window'
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
|
@ -805,33 +805,6 @@ const requestId = webview.findInPage('test')
|
||||||
console.log(requestId)
|
console.log(requestId)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Event: 'new-window'
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
* `url` string
|
|
||||||
* `frameName` string
|
|
||||||
* `disposition` string - Can be `default`, `foreground-tab`, `background-tab`,
|
|
||||||
`new-window`, `save-to-disk` and `other`.
|
|
||||||
* `options` BrowserWindowConstructorOptions - The options which should be used for creating the new
|
|
||||||
[`BrowserWindow`](browser-window.md).
|
|
||||||
|
|
||||||
Fired when the guest page attempts to open a new browser window.
|
|
||||||
|
|
||||||
The following example code opens the new url in system's default browser.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const { shell } = require('electron')
|
|
||||||
const webview = document.querySelector('webview')
|
|
||||||
|
|
||||||
webview.addEventListener('new-window', async (e) => {
|
|
||||||
const protocol = (new URL(e.url)).protocol
|
|
||||||
if (protocol === 'http:' || protocol === 'https:') {
|
|
||||||
await shell.openExternal(e.url)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### Event: 'will-navigate'
|
### Event: 'will-navigate'
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
|
@ -12,6 +12,24 @@ This document uses the following convention to categorize breaking changes:
|
||||||
* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release.
|
* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release.
|
||||||
* **Removed:** An API or feature was removed, and is no longer supported by Electron.
|
* **Removed:** An API or feature was removed, and is no longer supported by Electron.
|
||||||
|
|
||||||
|
## Planned Breaking API Changes (22.0)
|
||||||
|
|
||||||
|
### Removed: WebContents `new-window` event
|
||||||
|
|
||||||
|
The `new-window` event of WebContents has been removed. It is replaced by [`webContents.setWindowOpenHandler()`](api/web-contents.md#contentssetwindowopenhandlerhandler).
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Removed in Electron 21
|
||||||
|
webContents.on('new-window', (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Replace with
|
||||||
|
webContents.setWindowOpenHandler((details) => {
|
||||||
|
return { action: 'deny' }
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
## Planned Breaking API Changes (20.0)
|
## Planned Breaking API Changes (20.0)
|
||||||
|
|
||||||
### Behavior Changed: V8 Memory Cage enabled
|
### Behavior Changed: V8 Memory Cage enabled
|
||||||
|
|
|
@ -98,7 +98,6 @@ auto_filenames = {
|
||||||
"docs/api/structures/mime-typed-buffer.md",
|
"docs/api/structures/mime-typed-buffer.md",
|
||||||
"docs/api/structures/mouse-input-event.md",
|
"docs/api/structures/mouse-input-event.md",
|
||||||
"docs/api/structures/mouse-wheel-input-event.md",
|
"docs/api/structures/mouse-wheel-input-event.md",
|
||||||
"docs/api/structures/new-window-web-contents-event.md",
|
|
||||||
"docs/api/structures/notification-action.md",
|
"docs/api/structures/notification-action.md",
|
||||||
"docs/api/structures/notification-response.md",
|
"docs/api/structures/notification-response.md",
|
||||||
"docs/api/structures/payment-discount.md",
|
"docs/api/structures/payment-discount.md",
|
||||||
|
|
|
@ -670,7 +670,6 @@ WebContents.prototype._init = function () {
|
||||||
const options = result.browserWindowConstructorOptions;
|
const options = result.browserWindowConstructorOptions;
|
||||||
if (!event.defaultPrevented) {
|
if (!event.defaultPrevented) {
|
||||||
openGuestWindow({
|
openGuestWindow({
|
||||||
event,
|
|
||||||
embedder: event.sender,
|
embedder: event.sender,
|
||||||
disposition,
|
disposition,
|
||||||
referrer,
|
referrer,
|
||||||
|
@ -717,18 +716,16 @@ WebContents.prototype._init = function () {
|
||||||
transparent: windowOpenOverriddenOptions.transparent,
|
transparent: windowOpenOverriddenOptions.transparent,
|
||||||
...windowOpenOverriddenOptions.webPreferences
|
...windowOpenOverriddenOptions.webPreferences
|
||||||
} : undefined;
|
} : undefined;
|
||||||
// TODO(zcbenz): The features string is parsed twice: here where it is
|
|
||||||
// passed to C++, and in |makeBrowserWindowOptions| later where it is
|
|
||||||
// not actually used since the WebContents is created here.
|
|
||||||
// We should be able to remove the latter once the |new-window| event
|
|
||||||
// is removed.
|
|
||||||
const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures);
|
const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures);
|
||||||
// Parameters should keep same with |makeBrowserWindowOptions|.
|
|
||||||
const webPreferences = makeWebPreferences({
|
const webPreferences = makeWebPreferences({
|
||||||
embedder: event.sender,
|
embedder: event.sender,
|
||||||
insecureParsedWebPreferences: parsedWebPreferences,
|
insecureParsedWebPreferences: parsedWebPreferences,
|
||||||
secureOverrideWebPreferences
|
secureOverrideWebPreferences
|
||||||
});
|
});
|
||||||
|
windowOpenOverriddenOptions = {
|
||||||
|
...windowOpenOverriddenOptions,
|
||||||
|
webPreferences
|
||||||
|
};
|
||||||
this._setNextChildWebPreferences(webPreferences);
|
this._setNextChildWebPreferences(webPreferences);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -750,7 +747,6 @@ WebContents.prototype._init = function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
openGuestWindow({
|
openGuestWindow({
|
||||||
event,
|
|
||||||
embedder: event.sender,
|
embedder: event.sender,
|
||||||
guest: webContents,
|
guest: webContents,
|
||||||
overrideBrowserWindowOptions: overriddenOptions,
|
overrideBrowserWindowOptions: overriddenOptions,
|
||||||
|
|
|
@ -22,13 +22,6 @@ const supportedWebViewEvents = Object.keys(webViewEvents);
|
||||||
const guestInstances = new Map<number, GuestInstance>();
|
const guestInstances = new Map<number, GuestInstance>();
|
||||||
const embedderElementsMap = new Map<string, number>();
|
const embedderElementsMap = new Map<string, number>();
|
||||||
|
|
||||||
function sanitizeOptionsForGuest (options: Record<string, any>) {
|
|
||||||
const ret = { ...options };
|
|
||||||
// WebContents values can't be sent over IPC.
|
|
||||||
delete ret.webContents;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeWebPreferences (embedder: Electron.WebContents, params: Record<string, any>) {
|
function makeWebPreferences (embedder: Electron.WebContents, params: Record<string, any>) {
|
||||||
// parse the 'webpreferences' attribute string, if set
|
// parse the 'webpreferences' attribute string, if set
|
||||||
// this uses the same parsing rules as window.open uses for its features
|
// this uses the same parsing rules as window.open uses for its features
|
||||||
|
@ -156,15 +149,6 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
guest.on('new-window', function (event, url, frameName, disposition, options) {
|
|
||||||
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'new-window', {
|
|
||||||
url,
|
|
||||||
frameName,
|
|
||||||
disposition,
|
|
||||||
options: sanitizeOptionsForGuest(options)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Dispatch guest's IPC messages to embedder.
|
// Dispatch guest's IPC messages to embedder.
|
||||||
guest.on('ipc-message-host' as any, function (event: Electron.IpcMainEvent, channel: string, args: any[]) {
|
guest.on('ipc-message-host' as any, function (event: Electron.IpcMainEvent, channel: string, args: any[]) {
|
||||||
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'ipc-message', {
|
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'ipc-message', {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* out-of-process (cross-origin) are created here. "Embedder" roughly means
|
* out-of-process (cross-origin) are created here. "Embedder" roughly means
|
||||||
* "parent."
|
* "parent."
|
||||||
*/
|
*/
|
||||||
import { BrowserWindow, deprecate } from 'electron/main';
|
import { BrowserWindow } from 'electron/main';
|
||||||
import type { BrowserWindowConstructorOptions, Referrer, WebContents, LoadURLOptions } from 'electron/main';
|
import type { BrowserWindowConstructorOptions, Referrer, WebContents, LoadURLOptions } from 'electron/main';
|
||||||
import { parseFeatures } from '@electron/internal/browser/parse-features-string';
|
import { parseFeatures } from '@electron/internal/browser/parse-features-string';
|
||||||
|
|
||||||
|
@ -24,13 +24,8 @@ const getGuestWindowByFrameName = (name: string) => frameNamesToWindow.get(name)
|
||||||
/**
|
/**
|
||||||
* `openGuestWindow` is called to create and setup event handling for the new
|
* `openGuestWindow` is called to create and setup event handling for the new
|
||||||
* window.
|
* window.
|
||||||
*
|
|
||||||
* Until its removal in 12.0.0, the `new-window` event is fired, allowing the
|
|
||||||
* user to preventDefault() on the passed event (which ends up calling
|
|
||||||
* DestroyWebContents).
|
|
||||||
*/
|
*/
|
||||||
export function openGuestWindow ({ event, embedder, guest, referrer, disposition, postData, overrideBrowserWindowOptions, windowOpenArgs, outlivesOpener }: {
|
export function openGuestWindow ({ embedder, guest, referrer, disposition, postData, overrideBrowserWindowOptions, windowOpenArgs, outlivesOpener }: {
|
||||||
event: { sender: WebContents, defaultPrevented: boolean },
|
|
||||||
embedder: WebContents,
|
embedder: WebContents,
|
||||||
guest?: WebContents,
|
guest?: WebContents,
|
||||||
referrer: Referrer,
|
referrer: Referrer,
|
||||||
|
@ -41,23 +36,14 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition
|
||||||
outlivesOpener: boolean,
|
outlivesOpener: boolean,
|
||||||
}): BrowserWindow | undefined {
|
}): BrowserWindow | undefined {
|
||||||
const { url, frameName, features } = windowOpenArgs;
|
const { url, frameName, features } = windowOpenArgs;
|
||||||
const browserWindowOptions = makeBrowserWindowOptions({
|
const { options: parsedOptions } = parseFeatures(features);
|
||||||
embedder,
|
const browserWindowOptions = {
|
||||||
features,
|
show: true,
|
||||||
overrideOptions: overrideBrowserWindowOptions
|
width: 800,
|
||||||
});
|
height: 600,
|
||||||
|
...parsedOptions,
|
||||||
const didCancelEvent = emitDeprecatedNewWindowEvent({
|
...overrideBrowserWindowOptions
|
||||||
event,
|
};
|
||||||
embedder,
|
|
||||||
guest,
|
|
||||||
browserWindowOptions,
|
|
||||||
windowOpenArgs,
|
|
||||||
disposition,
|
|
||||||
postData,
|
|
||||||
referrer
|
|
||||||
});
|
|
||||||
if (didCancelEvent) return;
|
|
||||||
|
|
||||||
// To spec, subsequent window.open calls with the same frame name (`target` in
|
// To spec, subsequent window.open calls with the same frame name (`target` in
|
||||||
// spec parlance) will reuse the previous window.
|
// spec parlance) will reuse the previous window.
|
||||||
|
@ -134,68 +120,6 @@ const handleWindowLifecycleEvents = function ({ embedder, guest, frameName, outl
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated in favor of `webContents.setWindowOpenHandler` and
|
|
||||||
* `did-create-window` in 11.0.0. Will be removed in 12.0.0.
|
|
||||||
*/
|
|
||||||
function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs, browserWindowOptions, disposition, referrer, postData }: {
|
|
||||||
event: { sender: WebContents, defaultPrevented: boolean, newGuest?: BrowserWindow },
|
|
||||||
embedder: WebContents,
|
|
||||||
guest?: WebContents,
|
|
||||||
windowOpenArgs: WindowOpenArgs,
|
|
||||||
browserWindowOptions: BrowserWindowConstructorOptions,
|
|
||||||
disposition: string,
|
|
||||||
referrer: Referrer,
|
|
||||||
postData?: PostData,
|
|
||||||
}): boolean {
|
|
||||||
const { url, frameName } = windowOpenArgs;
|
|
||||||
const isWebViewWithPopupsDisabled = embedder.getType() === 'webview' && embedder.getLastWebPreferences()!.disablePopups;
|
|
||||||
const postBody = postData ? {
|
|
||||||
data: postData,
|
|
||||||
...parseContentTypeFormat(postData)
|
|
||||||
} : null;
|
|
||||||
|
|
||||||
if (embedder.listenerCount('new-window') > 0) {
|
|
||||||
deprecate.log('The new-window event is deprecated and will be removed. Please use contents.setWindowOpenHandler() instead.');
|
|
||||||
}
|
|
||||||
|
|
||||||
embedder.emit(
|
|
||||||
'new-window',
|
|
||||||
event,
|
|
||||||
url,
|
|
||||||
frameName,
|
|
||||||
disposition,
|
|
||||||
{
|
|
||||||
...browserWindowOptions,
|
|
||||||
webContents: guest
|
|
||||||
},
|
|
||||||
[], // additionalFeatures
|
|
||||||
referrer,
|
|
||||||
postBody
|
|
||||||
);
|
|
||||||
|
|
||||||
const { newGuest } = event;
|
|
||||||
if (isWebViewWithPopupsDisabled) return true;
|
|
||||||
if (event.defaultPrevented) {
|
|
||||||
if (newGuest) {
|
|
||||||
if (guest === newGuest.webContents) {
|
|
||||||
// The webContents is not changed, so set defaultPrevented to false to
|
|
||||||
// stop the callers of this event from destroying the webContents.
|
|
||||||
event.defaultPrevented = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleWindowLifecycleEvents({
|
|
||||||
embedder: event.sender,
|
|
||||||
guest: newGuest,
|
|
||||||
frameName,
|
|
||||||
outlivesOpener: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Security options that child windows will always inherit from parent windows
|
// Security options that child windows will always inherit from parent windows
|
||||||
const securityWebPreferences: { [key: string]: boolean } = {
|
const securityWebPreferences: { [key: string]: boolean } = {
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
|
@ -207,31 +131,6 @@ const securityWebPreferences: { [key: string]: boolean } = {
|
||||||
enableWebSQL: false
|
enableWebSQL: false
|
||||||
};
|
};
|
||||||
|
|
||||||
function makeBrowserWindowOptions ({ embedder, features, overrideOptions }: {
|
|
||||||
embedder: WebContents,
|
|
||||||
features: string,
|
|
||||||
overrideOptions?: BrowserWindowConstructorOptions,
|
|
||||||
}) {
|
|
||||||
const { options: parsedOptions, webPreferences: parsedWebPreferences } = parseFeatures(features);
|
|
||||||
|
|
||||||
return {
|
|
||||||
show: true,
|
|
||||||
width: 800,
|
|
||||||
height: 600,
|
|
||||||
...parsedOptions,
|
|
||||||
...overrideOptions,
|
|
||||||
// Note that for normal code path an existing WebContents created by
|
|
||||||
// Chromium will be used, with web preferences parsed in the
|
|
||||||
// |-will-add-new-contents| event.
|
|
||||||
// The |webPreferences| here is only used by the |new-window| event.
|
|
||||||
webPreferences: makeWebPreferences({
|
|
||||||
embedder,
|
|
||||||
insecureParsedWebPreferences: parsedWebPreferences,
|
|
||||||
secureOverrideWebPreferences: overrideOptions && overrideOptions.webPreferences
|
|
||||||
})
|
|
||||||
} as Electron.BrowserViewConstructorOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function makeWebPreferences ({ embedder, secureOverrideWebPreferences = {}, insecureParsedWebPreferences: parsedWebPreferences = {} }: {
|
export function makeWebPreferences ({ embedder, secureOverrideWebPreferences = {}, insecureParsedWebPreferences: parsedWebPreferences = {} }: {
|
||||||
embedder: WebContents,
|
embedder: WebContents,
|
||||||
insecureParsedWebPreferences?: ReturnType<typeof parseFeatures>['webPreferences'],
|
insecureParsedWebPreferences?: ReturnType<typeof parseFeatures>['webPreferences'],
|
||||||
|
|
|
@ -5,7 +5,7 @@ import * as fs from 'fs';
|
||||||
import * as qs from 'querystring';
|
import * as qs from 'querystring';
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
import { AddressInfo } from 'net';
|
import { AddressInfo } from 'net';
|
||||||
import { app, BrowserWindow, BrowserView, dialog, ipcMain, OnBeforeSendHeadersListenerDetails, protocol, screen, webContents, session, WebContents, BrowserWindowConstructorOptions } from 'electron/main';
|
import { app, BrowserWindow, BrowserView, dialog, ipcMain, OnBeforeSendHeadersListenerDetails, protocol, screen, webContents, session, WebContents } from 'electron/main';
|
||||||
|
|
||||||
import { emittedOnce, emittedUntil, emittedNTimes } from './events-helpers';
|
import { emittedOnce, emittedUntil, emittedNTimes } from './events-helpers';
|
||||||
import { ifit, ifdescribe, defer, delay } from './spec-helpers';
|
import { ifit, ifdescribe, defer, delay } from './spec-helpers';
|
||||||
|
@ -3080,7 +3080,7 @@ describe('BrowserWindow module', () => {
|
||||||
expect(argv).to.include('--enable-sandbox');
|
expect(argv).to.include('--enable-sandbox');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should open windows with the options configured via new-window event listeners', async () => {
|
it('should open windows with the options configured via setWindowOpenHandler handlers', async () => {
|
||||||
const w = new BrowserWindow({
|
const w = new BrowserWindow({
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
|
@ -3171,30 +3171,6 @@ describe('BrowserWindow module', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('supports calling preventDefault on new-window events', (done) => {
|
|
||||||
const w = new BrowserWindow({
|
|
||||||
show: false,
|
|
||||||
webPreferences: {
|
|
||||||
sandbox: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const initialWebContents = webContents.getAllWebContents().map((i) => i.id);
|
|
||||||
w.webContents.once('new-window', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
// We need to give it some time so the windows get properly disposed (at least on OSX).
|
|
||||||
setTimeout(() => {
|
|
||||||
const currentWebContents = webContents.getAllWebContents().map((i) => i.id);
|
|
||||||
try {
|
|
||||||
expect(currentWebContents).to.deep.equal(initialWebContents);
|
|
||||||
done();
|
|
||||||
} catch (error) {
|
|
||||||
done(e);
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
w.loadFile(path.join(fixtures, 'pages', 'window-open.html'));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates process APIs access in sandboxed renderer', async () => {
|
it('validates process APIs access in sandboxed renderer', async () => {
|
||||||
const w = new BrowserWindow({
|
const w = new BrowserWindow({
|
||||||
show: false,
|
show: false,
|
||||||
|
@ -3350,7 +3326,7 @@ describe('BrowserWindow module', () => {
|
||||||
w.loadFile(path.join(fixtures, 'api', 'new-window-webview.html'));
|
w.loadFile(path.join(fixtures, 'api', 'new-window-webview.html'));
|
||||||
await webviewLoaded;
|
await webviewLoaded;
|
||||||
});
|
});
|
||||||
it('should open windows with the options configured via new-window event listeners', async () => {
|
it('should open windows with the options configured via setWindowOpenHandler handlers', async () => {
|
||||||
const preloadPath = path.join(mainFixtures, 'api', 'new-window-preload.js');
|
const preloadPath = path.join(mainFixtures, 'api', 'new-window-preload.js');
|
||||||
w.webContents.setWindowOpenHandler(() => ({
|
w.webContents.setWindowOpenHandler(() => ({
|
||||||
action: 'allow',
|
action: 'allow',
|
||||||
|
@ -3720,94 +3696,6 @@ describe('BrowserWindow module', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('new-window event', () => {
|
|
||||||
afterEach(closeAllWindows);
|
|
||||||
|
|
||||||
it('emits when window.open is called', (done) => {
|
|
||||||
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
|
|
||||||
w.webContents.once('new-window', (e, url, frameName, disposition, options) => {
|
|
||||||
e.preventDefault();
|
|
||||||
try {
|
|
||||||
expect(url).to.equal('http://host/');
|
|
||||||
expect(frameName).to.equal('host');
|
|
||||||
expect((options as any)['this-is-not-a-standard-feature']).to.equal(true);
|
|
||||||
done();
|
|
||||||
} catch (e) {
|
|
||||||
done(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
w.loadFile(path.join(fixtures, 'pages', 'window-open.html'));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('emits when window.open is called with no webPreferences', (done) => {
|
|
||||||
const w = new BrowserWindow({ show: false });
|
|
||||||
w.webContents.once('new-window', function (e, url, frameName, disposition, options) {
|
|
||||||
e.preventDefault();
|
|
||||||
try {
|
|
||||||
expect(url).to.equal('http://host/');
|
|
||||||
expect(frameName).to.equal('host');
|
|
||||||
expect((options as any)['this-is-not-a-standard-feature']).to.equal(true);
|
|
||||||
done();
|
|
||||||
} catch (e) {
|
|
||||||
done(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
w.loadFile(path.join(fixtures, 'pages', 'window-open.html'));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('emits when link with target is called', (done) => {
|
|
||||||
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
|
|
||||||
w.webContents.once('new-window', (e, url, frameName) => {
|
|
||||||
e.preventDefault();
|
|
||||||
try {
|
|
||||||
expect(url).to.equal('http://host/');
|
|
||||||
expect(frameName).to.equal('target');
|
|
||||||
done();
|
|
||||||
} catch (e) {
|
|
||||||
done(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
w.loadFile(path.join(fixtures, 'pages', 'target-name.html'));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('includes all properties', async () => {
|
|
||||||
const w = new BrowserWindow({ show: false });
|
|
||||||
|
|
||||||
const p = new Promise<{
|
|
||||||
url: string,
|
|
||||||
frameName: string,
|
|
||||||
disposition: string,
|
|
||||||
options: BrowserWindowConstructorOptions,
|
|
||||||
additionalFeatures: string[],
|
|
||||||
referrer: Electron.Referrer,
|
|
||||||
postBody: Electron.PostBody
|
|
||||||
}>((resolve) => {
|
|
||||||
w.webContents.once('new-window', (e, url, frameName, disposition, options, additionalFeatures, referrer, postBody) => {
|
|
||||||
e.preventDefault();
|
|
||||||
resolve({ url, frameName, disposition, options, additionalFeatures, referrer, postBody });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
w.loadURL(`data:text/html,${encodeURIComponent(`
|
|
||||||
<form target="_blank" method="POST" id="form" action="http://example.com/test">
|
|
||||||
<input type="text" name="post-test-key" value="post-test-value"></input>
|
|
||||||
</form>
|
|
||||||
<script>form.submit()</script>
|
|
||||||
`)}`);
|
|
||||||
const { url, frameName, disposition, options, additionalFeatures, referrer, postBody } = await p;
|
|
||||||
expect(url).to.equal('http://example.com/test');
|
|
||||||
expect(frameName).to.equal('');
|
|
||||||
expect(disposition).to.equal('foreground-tab');
|
|
||||||
expect(options).to.be.an('object').not.null();
|
|
||||||
expect(referrer.policy).to.equal('strict-origin-when-cross-origin');
|
|
||||||
expect(referrer.url).to.equal('');
|
|
||||||
expect(additionalFeatures).to.deep.equal([]);
|
|
||||||
expect(postBody.data).to.have.length(1);
|
|
||||||
expect(postBody.data[0].type).to.equal('rawData');
|
|
||||||
expect((postBody.data[0] as any).bytes).to.deep.equal(Buffer.from('post-test-key=post-test-value'));
|
|
||||||
expect(postBody.contentType).to.equal('application/x-www-form-urlencoded');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ifdescribe(process.platform !== 'linux')('max/minimize events', () => {
|
ifdescribe(process.platform !== 'linux')('max/minimize events', () => {
|
||||||
afterEach(closeAllWindows);
|
afterEach(closeAllWindows);
|
||||||
it('emits an event when window is maximized', async () => {
|
it('emits an event when window is maximized', async () => {
|
||||||
|
|
|
@ -2102,26 +2102,4 @@ describe('webContents module', () => {
|
||||||
expect(params.y).to.be.a('number');
|
expect(params.y).to.be.a('number');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('emits a cancelable event before creating a child webcontents', async () => {
|
|
||||||
const w = new BrowserWindow({
|
|
||||||
show: false,
|
|
||||||
webPreferences: {
|
|
||||||
sandbox: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
w.webContents.on('-will-add-new-contents' as any, (event: any, url: any) => {
|
|
||||||
expect(url).to.equal('about:blank');
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
let wasCalled = false;
|
|
||||||
w.webContents.on('new-window' as any, () => {
|
|
||||||
wasCalled = true;
|
|
||||||
});
|
|
||||||
await w.loadURL('about:blank');
|
|
||||||
await w.webContents.executeJavaScript('window.open(\'about:blank\')');
|
|
||||||
await new Promise((resolve) => { process.nextTick(resolve); });
|
|
||||||
expect(wasCalled).to.equal(false);
|
|
||||||
await closeAllWindows();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,161 +0,0 @@
|
||||||
[
|
|
||||||
[
|
|
||||||
"top=5,left=10,resizable=no",
|
|
||||||
{
|
|
||||||
"sender": "[WebContents]"
|
|
||||||
},
|
|
||||||
"about:blank",
|
|
||||||
"frame-name",
|
|
||||||
"new-window",
|
|
||||||
{
|
|
||||||
"show": true,
|
|
||||||
"width": 800,
|
|
||||||
"height": 600,
|
|
||||||
"top": 5,
|
|
||||||
"left": 10,
|
|
||||||
"resizable": false,
|
|
||||||
"x": 10,
|
|
||||||
"y": 5,
|
|
||||||
"webPreferences": {
|
|
||||||
"contextIsolation": true,
|
|
||||||
"nodeIntegration": false,
|
|
||||||
"sandbox": true,
|
|
||||||
"webviewTag": false,
|
|
||||||
"nodeIntegrationInSubFrames": false
|
|
||||||
},
|
|
||||||
"webContents": "[WebContents]"
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
{
|
|
||||||
"url": "",
|
|
||||||
"policy": "strict-origin-when-cross-origin"
|
|
||||||
},
|
|
||||||
null
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"zoomFactor=2,resizable=0,x=0,y=10",
|
|
||||||
{
|
|
||||||
"sender": "[WebContents]"
|
|
||||||
},
|
|
||||||
"about:blank",
|
|
||||||
"frame-name",
|
|
||||||
"new-window",
|
|
||||||
{
|
|
||||||
"show": true,
|
|
||||||
"width": 800,
|
|
||||||
"height": 600,
|
|
||||||
"resizable": false,
|
|
||||||
"x": 0,
|
|
||||||
"y": 10,
|
|
||||||
"webPreferences": {
|
|
||||||
"zoomFactor": "2",
|
|
||||||
"contextIsolation": true,
|
|
||||||
"nodeIntegration": false,
|
|
||||||
"sandbox": true,
|
|
||||||
"webviewTag": false,
|
|
||||||
"nodeIntegrationInSubFrames": false
|
|
||||||
},
|
|
||||||
"webContents": "[WebContents]"
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
{
|
|
||||||
"url": "",
|
|
||||||
"policy": "strict-origin-when-cross-origin"
|
|
||||||
},
|
|
||||||
null
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"backgroundColor=gray,webPreferences=0,x=100,y=100",
|
|
||||||
{
|
|
||||||
"sender": "[WebContents]"
|
|
||||||
},
|
|
||||||
"about:blank",
|
|
||||||
"frame-name",
|
|
||||||
"new-window",
|
|
||||||
{
|
|
||||||
"show": true,
|
|
||||||
"width": 800,
|
|
||||||
"height": 600,
|
|
||||||
"backgroundColor": "gray",
|
|
||||||
"webPreferences": {
|
|
||||||
"contextIsolation": true,
|
|
||||||
"nodeIntegration": false,
|
|
||||||
"sandbox": true,
|
|
||||||
"webviewTag": false,
|
|
||||||
"nodeIntegrationInSubFrames": false
|
|
||||||
},
|
|
||||||
"x": 100,
|
|
||||||
"y": 100,
|
|
||||||
"webContents": "[WebContents]"
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
{
|
|
||||||
"url": "",
|
|
||||||
"policy": "strict-origin-when-cross-origin"
|
|
||||||
},
|
|
||||||
null
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"x=50,y=20,title=sup",
|
|
||||||
{
|
|
||||||
"sender": "[WebContents]"
|
|
||||||
},
|
|
||||||
"about:blank",
|
|
||||||
"frame-name",
|
|
||||||
"new-window",
|
|
||||||
{
|
|
||||||
"show": true,
|
|
||||||
"width": 800,
|
|
||||||
"height": 600,
|
|
||||||
"x": 50,
|
|
||||||
"y": 20,
|
|
||||||
"title": "sup",
|
|
||||||
"webPreferences": {
|
|
||||||
"contextIsolation": true,
|
|
||||||
"nodeIntegration": false,
|
|
||||||
"sandbox": true,
|
|
||||||
"webviewTag": false,
|
|
||||||
"nodeIntegrationInSubFrames": false
|
|
||||||
},
|
|
||||||
"webContents": "[WebContents]"
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
{
|
|
||||||
"url": "",
|
|
||||||
"policy": "strict-origin-when-cross-origin"
|
|
||||||
},
|
|
||||||
null
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"show=false,top=1,left=1",
|
|
||||||
{
|
|
||||||
"sender": "[WebContents]"
|
|
||||||
},
|
|
||||||
"about:blank",
|
|
||||||
"frame-name",
|
|
||||||
"new-window",
|
|
||||||
{
|
|
||||||
"show": false,
|
|
||||||
"width": 800,
|
|
||||||
"height": 600,
|
|
||||||
"top": 1,
|
|
||||||
"left": 1,
|
|
||||||
"x": 1,
|
|
||||||
"y": 1,
|
|
||||||
"webPreferences": {
|
|
||||||
"contextIsolation": true,
|
|
||||||
"nodeIntegration": false,
|
|
||||||
"sandbox": true,
|
|
||||||
"webviewTag": false,
|
|
||||||
"nodeIntegrationInSubFrames": false
|
|
||||||
},
|
|
||||||
"webContents": "[WebContents]"
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
{
|
|
||||||
"url": "",
|
|
||||||
"policy": "strict-origin-when-cross-origin"
|
|
||||||
},
|
|
||||||
null
|
|
||||||
]
|
|
||||||
]
|
|
|
@ -1,75 +1,8 @@
|
||||||
import { BrowserWindow } from 'electron';
|
import { BrowserWindow } from 'electron';
|
||||||
import { writeFileSync, readFileSync } from 'fs';
|
|
||||||
import { resolve } from 'path';
|
|
||||||
import { expect, assert } from 'chai';
|
import { expect, assert } from 'chai';
|
||||||
import { closeAllWindows } from './window-helpers';
|
import { closeAllWindows } from './window-helpers';
|
||||||
const { emittedOnce } = require('./events-helpers');
|
const { emittedOnce } = require('./events-helpers');
|
||||||
|
|
||||||
function genSnapshot (browserWindow: BrowserWindow, features: string) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
browserWindow.webContents.on('new-window', (...args: any[]) => {
|
|
||||||
resolve([features, ...args]);
|
|
||||||
});
|
|
||||||
browserWindow.webContents.executeJavaScript(`window.open('about:blank', 'frame-name', '${features}') && true`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('new-window event', () => {
|
|
||||||
const snapshotFileName = 'native-window-open.snapshot.txt';
|
|
||||||
const browserWindowOptions = {
|
|
||||||
show: false,
|
|
||||||
width: 200,
|
|
||||||
title: 'cool',
|
|
||||||
backgroundColor: 'blue',
|
|
||||||
focusable: false,
|
|
||||||
webPreferences: {
|
|
||||||
sandbox: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const snapshotFile = resolve(__dirname, 'fixtures', 'snapshots', snapshotFileName);
|
|
||||||
let browserWindow: BrowserWindow;
|
|
||||||
let existingSnapshots: any[];
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
existingSnapshots = parseSnapshots(readFileSync(snapshotFile, { encoding: 'utf8' }));
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach((done) => {
|
|
||||||
browserWindow = new BrowserWindow(browserWindowOptions);
|
|
||||||
browserWindow.loadURL('about:blank');
|
|
||||||
browserWindow.on('ready-to-show', () => { done(); });
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(closeAllWindows);
|
|
||||||
|
|
||||||
const newSnapshots: any[] = [];
|
|
||||||
[
|
|
||||||
'top=5,left=10,resizable=no',
|
|
||||||
'zoomFactor=2,resizable=0,x=0,y=10',
|
|
||||||
'backgroundColor=gray,webPreferences=0,x=100,y=100',
|
|
||||||
'x=50,y=20,title=sup',
|
|
||||||
'show=false,top=1,left=1'
|
|
||||||
].forEach((features, index) => {
|
|
||||||
/**
|
|
||||||
* ATTN: If this test is failing, you likely just need to change
|
|
||||||
* `shouldOverwriteSnapshot` to true and then evaluate the snapshot diff
|
|
||||||
* to see if the change is harmless.
|
|
||||||
*/
|
|
||||||
it(`matches snapshot for ${features}`, async () => {
|
|
||||||
const newSnapshot = await genSnapshot(browserWindow, features);
|
|
||||||
newSnapshots.push(newSnapshot);
|
|
||||||
// TODO: The output when these fail could be friendlier.
|
|
||||||
expect(stringifySnapshots(newSnapshot)).to.equal(stringifySnapshots(existingSnapshots[index]));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
const shouldOverwriteSnapshot = false;
|
|
||||||
if (shouldOverwriteSnapshot) writeFileSync(snapshotFile, stringifySnapshots(newSnapshots, true));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('webContents.setWindowOpenHandler', () => {
|
describe('webContents.setWindowOpenHandler', () => {
|
||||||
let browserWindow: BrowserWindow;
|
let browserWindow: BrowserWindow;
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
@ -95,10 +28,6 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
browserWindow.webContents.on('new-window', () => {
|
|
||||||
assert.fail('new-window should not be called with an overridden window.open');
|
|
||||||
});
|
|
||||||
|
|
||||||
browserWindow.webContents.on('did-create-window', () => {
|
browserWindow.webContents.on('did-create-window', () => {
|
||||||
assert.fail('did-create-window should not be called with an overridden window.open');
|
assert.fail('did-create-window should not be called with an overridden window.open');
|
||||||
});
|
});
|
||||||
|
@ -118,10 +47,6 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
browserWindow.webContents.on('new-window', () => {
|
|
||||||
assert.fail('new-window should not be called with an overridden window.open');
|
|
||||||
});
|
|
||||||
|
|
||||||
browserWindow.webContents.on('did-create-window', () => {
|
browserWindow.webContents.on('did-create-window', () => {
|
||||||
assert.fail('did-create-window should not be called with an overridden window.open');
|
assert.fail('did-create-window should not be called with an overridden window.open');
|
||||||
});
|
});
|
||||||
|
@ -138,9 +63,6 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||||
return { action: 'deny' };
|
return { action: 'deny' };
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
browserWindow.webContents.on('new-window', () => {
|
|
||||||
assert.fail('new-window should not be called with an overridden window.open');
|
|
||||||
});
|
|
||||||
|
|
||||||
browserWindow.webContents.on('did-create-window', () => {
|
browserWindow.webContents.on('did-create-window', () => {
|
||||||
assert.fail('did-create-window should not be called with an overridden window.open');
|
assert.fail('did-create-window should not be called with an overridden window.open');
|
||||||
|
@ -158,9 +80,6 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||||
return { action: 'deny' };
|
return { action: 'deny' };
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
browserWindow.webContents.on('new-window', () => {
|
|
||||||
assert.fail('new-window should not be called with an overridden window.open');
|
|
||||||
});
|
|
||||||
|
|
||||||
browserWindow.webContents.on('did-create-window', () => {
|
browserWindow.webContents.on('did-create-window', () => {
|
||||||
assert.fail('did-create-window should not be called with an overridden window.open');
|
assert.fail('did-create-window should not be called with an overridden window.open');
|
||||||
|
@ -180,9 +99,6 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||||
return { action: 'deny' };
|
return { action: 'deny' };
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
browserWindow.webContents.on('new-window', () => {
|
|
||||||
assert.fail('new-window should not be called with an overridden window.open');
|
|
||||||
});
|
|
||||||
|
|
||||||
browserWindow.webContents.on('did-create-window', () => {
|
browserWindow.webContents.on('did-create-window', () => {
|
||||||
assert.fail('did-create-window should not be called with an overridden window.open');
|
assert.fail('did-create-window should not be called with an overridden window.open');
|
||||||
|
@ -257,10 +173,7 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||||
browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");
|
browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all([
|
await emittedOnce(browserWindow.webContents, 'did-create-window');
|
||||||
emittedOnce(browserWindow.webContents, 'did-create-window'),
|
|
||||||
emittedOnce(browserWindow.webContents, 'new-window')
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can change webPreferences of child windows', (done) => {
|
it('can change webPreferences of child windows', (done) => {
|
||||||
|
@ -282,22 +195,3 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||||
expect(await browserWindow.webContents.executeJavaScript('42')).to.equal(42);
|
expect(await browserWindow.webContents.executeJavaScript('42')).to.equal(42);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function stringifySnapshots (snapshots: any, pretty = false) {
|
|
||||||
return JSON.stringify(snapshots, (key, value) => {
|
|
||||||
if (['sender', 'webContents'].includes(key)) {
|
|
||||||
return '[WebContents]';
|
|
||||||
}
|
|
||||||
if (key === 'processId' && typeof value === 'number') {
|
|
||||||
return 'placeholder-process-id';
|
|
||||||
}
|
|
||||||
if (key === 'returnValue') {
|
|
||||||
return 'placeholder-guest-contents-id';
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}, pretty ? 2 : undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseSnapshots (snapshotsJson: string) {
|
|
||||||
return JSON.parse(snapshotsJson);
|
|
||||||
}
|
|
||||||
|
|
|
@ -668,31 +668,6 @@ describe('<webview> tag', function () {
|
||||||
expect(content).to.equal(expectedContent);
|
expect(content).to.equal(expectedContent);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('emits a new-window event', async () => {
|
|
||||||
// Don't wait for loading to finish.
|
|
||||||
const attributes = {
|
|
||||||
allowpopups: 'on',
|
|
||||||
nodeintegration: 'on',
|
|
||||||
webpreferences: 'contextIsolation=no',
|
|
||||||
src: `file://${fixtures}/pages/window-open.html`
|
|
||||||
};
|
|
||||||
const { url, frameName } = await w.webContents.executeJavaScript(`
|
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
const webview = document.createElement('webview')
|
|
||||||
for (const [k, v] of Object.entries(${JSON.stringify(attributes)})) {
|
|
||||||
webview.setAttribute(k, v)
|
|
||||||
}
|
|
||||||
document.body.appendChild(webview)
|
|
||||||
webview.addEventListener('new-window', (e) => {
|
|
||||||
resolve({url: e.url, frameName: e.frameName})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
`);
|
|
||||||
|
|
||||||
expect(url).to.equal('http://host/');
|
|
||||||
expect(frameName).to.equal('host');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('emits a browser-window-created event', async () => {
|
it('emits a browser-window-created event', async () => {
|
||||||
// Don't wait for loading to finish.
|
// Don't wait for loading to finish.
|
||||||
loadWebView(w.webContents, {
|
loadWebView(w.webContents, {
|
||||||
|
@ -1435,28 +1410,6 @@ describe('<webview> tag', function () {
|
||||||
});
|
});
|
||||||
after(closeAllWindows);
|
after(closeAllWindows);
|
||||||
|
|
||||||
describe('new-window event', () => {
|
|
||||||
it('emits when window.open is called', async () => {
|
|
||||||
const { url, frameName } = await loadWebViewAndWaitForEvent(w, {
|
|
||||||
src: `file://${fixtures}/pages/window-open.html`,
|
|
||||||
allowpopups: 'true'
|
|
||||||
}, 'new-window');
|
|
||||||
|
|
||||||
expect(url).to.equal('http://host/');
|
|
||||||
expect(frameName).to.equal('host');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('emits when link with target is called', async () => {
|
|
||||||
const { url, frameName } = await loadWebViewAndWaitForEvent(w, {
|
|
||||||
src: `file://${fixtures}/pages/target-name.html`,
|
|
||||||
allowpopups: 'true'
|
|
||||||
}, 'new-window');
|
|
||||||
|
|
||||||
expect(url).to.equal('http://host/');
|
|
||||||
expect(frameName).to.equal('target');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('ipc-message event', () => {
|
describe('ipc-message event', () => {
|
||||||
it('emits when guest sends an ipc message to browser', async () => {
|
it('emits when guest sends an ipc message to browser', async () => {
|
||||||
const { frameId, channel, args } = await loadWebViewAndWaitForEvent(w, {
|
const { frameId, channel, args } = await loadWebViewAndWaitForEvent(w, {
|
||||||
|
|
|
@ -174,11 +174,6 @@ webview.addEventListener('found-in-page', function (e) {
|
||||||
|
|
||||||
const requestId = webview.findInPage('test')
|
const requestId = webview.findInPage('test')
|
||||||
|
|
||||||
webview.addEventListener('new-window', async e => {
|
|
||||||
const { shell } = require('electron')
|
|
||||||
await shell.openExternal(e.url)
|
|
||||||
})
|
|
||||||
|
|
||||||
webview.addEventListener('close', function () {
|
webview.addEventListener('close', function () {
|
||||||
webview.src = 'about:blank'
|
webview.src = 'about:blank'
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue