test: move some BrowserWindow specs to the main runner (#18551)
This commit is contained in:
parent
cf628d9287
commit
901cdb22e3
6 changed files with 564 additions and 442 deletions
|
@ -70,10 +70,24 @@ Returns:
|
||||||
* `frameProcessId` Integer
|
* `frameProcessId` Integer
|
||||||
* `frameRoutingId` Integer
|
* `frameRoutingId` Integer
|
||||||
|
|
||||||
This event is like `did-finish-load` but emitted when the load failed or was
|
This event is like `did-finish-load` but emitted when the load failed.
|
||||||
cancelled, e.g. `window.stop()` is invoked.
|
|
||||||
The full list of error codes and their meaning is available [here](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h).
|
The full list of error codes and their meaning is available [here](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h).
|
||||||
|
|
||||||
|
#### Event: 'did-fail-provisional-load'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
* `event` Event
|
||||||
|
* `errorCode` Integer
|
||||||
|
* `errorDescription` String
|
||||||
|
* `validatedURL` String
|
||||||
|
* `isMainFrame` Boolean
|
||||||
|
* `frameProcessId` Integer
|
||||||
|
* `frameRoutingId` Integer
|
||||||
|
|
||||||
|
This event is like `did-fail-load` but emitted when the load was cancelled
|
||||||
|
(e.g. `window.stop()` was invoked).
|
||||||
|
|
||||||
#### Event: 'did-frame-finish-load'
|
#### Event: 'did-frame-finish-load'
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
|
@ -82,11 +82,11 @@ The `callback` has to be called with an `response` object.
|
||||||
* `resourceType` String
|
* `resourceType` String
|
||||||
* `referrer` String
|
* `referrer` String
|
||||||
* `timestamp` Double
|
* `timestamp` Double
|
||||||
* `requestHeaders` Object
|
* `requestHeaders` Record<string, string>
|
||||||
* `callback` Function
|
* `callback` Function
|
||||||
* `response` Object
|
* `response` Object
|
||||||
* `cancel` Boolean (optional)
|
* `cancel` Boolean (optional)
|
||||||
* `requestHeaders` Object (optional) - When provided, request will be made
|
* `requestHeaders` Record<string, string> (optional) - When provided, request will be made
|
||||||
with these headers.
|
with these headers.
|
||||||
|
|
||||||
The `listener` will be called with `listener(details, callback)` before sending
|
The `listener` will be called with `listener(details, callback)` before sending
|
||||||
|
@ -109,7 +109,7 @@ The `callback` has to be called with an `response` object.
|
||||||
* `resourceType` String
|
* `resourceType` String
|
||||||
* `referrer` String
|
* `referrer` String
|
||||||
* `timestamp` Double
|
* `timestamp` Double
|
||||||
* `requestHeaders` Object
|
* `requestHeaders` Record<string, string>
|
||||||
|
|
||||||
The `listener` will be called with `listener(details)` just before a request is
|
The `listener` will be called with `listener(details)` just before a request is
|
||||||
going to be sent to the server, modifications of previous `onBeforeSendHeaders`
|
going to be sent to the server, modifications of previous `onBeforeSendHeaders`
|
||||||
|
|
539
spec-main/api-browser-window-spec.ts
Normal file
539
spec-main/api-browser-window-spec.ts
Normal file
|
@ -0,0 +1,539 @@
|
||||||
|
import * as chai from 'chai'
|
||||||
|
import * as chaiAsPromised from 'chai-as-promised'
|
||||||
|
import * as path from 'path'
|
||||||
|
import * as fs from 'fs'
|
||||||
|
import * as qs from 'querystring'
|
||||||
|
import * as http from 'http'
|
||||||
|
import { AddressInfo } from 'net'
|
||||||
|
import { app, BrowserWindow, ipcMain, OnBeforeSendHeadersListenerDetails } from 'electron'
|
||||||
|
import { emittedOnce } from './events-helpers';
|
||||||
|
import { closeWindow } from './window-helpers';
|
||||||
|
|
||||||
|
const { expect } = chai
|
||||||
|
|
||||||
|
chai.use(chaiAsPromised)
|
||||||
|
|
||||||
|
const fixtures = path.resolve(__dirname, '..', 'spec', 'fixtures')
|
||||||
|
|
||||||
|
describe('BrowserWindow module', () => {
|
||||||
|
describe('BrowserWindow constructor', () => {
|
||||||
|
it('allows passing void 0 as the webContents', async () => {
|
||||||
|
expect(() => {
|
||||||
|
const w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
// apparently void 0 had different behaviour from undefined in the
|
||||||
|
// issue that this test is supposed to catch.
|
||||||
|
webContents: void 0
|
||||||
|
} as any)
|
||||||
|
w.destroy()
|
||||||
|
}).not.to.throw()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('BrowserWindow.close()', () => {
|
||||||
|
let w = null as unknown as BrowserWindow
|
||||||
|
beforeEach(() => {
|
||||||
|
w = new BrowserWindow({show: false, webPreferences: {nodeIntegration: true}})
|
||||||
|
})
|
||||||
|
afterEach(async () => {
|
||||||
|
await closeWindow(w)
|
||||||
|
w = null as unknown as BrowserWindow
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should emit unload handler', async () => {
|
||||||
|
await w.loadFile(path.join(fixtures, 'api', 'unload.html'))
|
||||||
|
const closed = emittedOnce(w, 'closed')
|
||||||
|
w.close()
|
||||||
|
await closed
|
||||||
|
const test = path.join(fixtures, 'api', 'unload')
|
||||||
|
const content = fs.readFileSync(test)
|
||||||
|
fs.unlinkSync(test)
|
||||||
|
expect(String(content)).to.equal('unload')
|
||||||
|
})
|
||||||
|
it('should emit beforeunload handler', async () => {
|
||||||
|
await w.loadFile(path.join(fixtures, 'api', 'beforeunload-false.html'))
|
||||||
|
const beforeunload = emittedOnce(w, 'onbeforeunload')
|
||||||
|
w.close()
|
||||||
|
await beforeunload
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when invoked synchronously inside navigation observer', () => {
|
||||||
|
let server: http.Server = null as unknown as http.Server
|
||||||
|
let url: string = null as unknown as string
|
||||||
|
|
||||||
|
before((done) => {
|
||||||
|
server = http.createServer((request, response) => {
|
||||||
|
switch (request.url) {
|
||||||
|
case '/net-error':
|
||||||
|
response.destroy()
|
||||||
|
break
|
||||||
|
case '/301':
|
||||||
|
response.statusCode = 301
|
||||||
|
response.setHeader('Location', '/200')
|
||||||
|
response.end()
|
||||||
|
break
|
||||||
|
case '/200':
|
||||||
|
response.statusCode = 200
|
||||||
|
response.end('hello')
|
||||||
|
break
|
||||||
|
case '/title':
|
||||||
|
response.statusCode = 200
|
||||||
|
response.end('<title>Hello</title>')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error(`unsupported endpoint: ${request.url}`)
|
||||||
|
}
|
||||||
|
}).listen(0, '127.0.0.1', () => {
|
||||||
|
url = 'http://127.0.0.1:' + (server.address() as AddressInfo).port
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
server.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
const events = [
|
||||||
|
{ name: 'did-start-loading', path: '/200' },
|
||||||
|
{ name: 'dom-ready', path: '/200' },
|
||||||
|
{ name: 'page-title-updated', path: '/title' },
|
||||||
|
{ name: 'did-stop-loading', path: '/200' },
|
||||||
|
{ name: 'did-finish-load', path: '/200' },
|
||||||
|
{ name: 'did-frame-finish-load', path: '/200' },
|
||||||
|
{ name: 'did-fail-load', path: '/net-error' }
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const {name, path} of events) {
|
||||||
|
it(`should not crash when closed during ${name}`, async () => {
|
||||||
|
const w = new BrowserWindow({ show: false })
|
||||||
|
w.webContents.once((name as any), () => {
|
||||||
|
w.close()
|
||||||
|
})
|
||||||
|
const destroyed = emittedOnce(w.webContents, 'destroyed')
|
||||||
|
w.webContents.loadURL(url + path)
|
||||||
|
await destroyed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('window.close()', () => {
|
||||||
|
let w = null as unknown as BrowserWindow
|
||||||
|
beforeEach(() => {
|
||||||
|
w = new BrowserWindow({show: false, webPreferences: {nodeIntegration: true}})
|
||||||
|
})
|
||||||
|
afterEach(async () => {
|
||||||
|
await closeWindow(w)
|
||||||
|
w = null as unknown as BrowserWindow
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should emit unload event', async () => {
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'close.html'))
|
||||||
|
await emittedOnce(w, 'closed')
|
||||||
|
const test = path.join(fixtures, 'api', 'close')
|
||||||
|
const content = fs.readFileSync(test).toString()
|
||||||
|
fs.unlinkSync(test)
|
||||||
|
expect(content).to.equal('close')
|
||||||
|
})
|
||||||
|
it('should emit beforeunload event', async () => {
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'close-beforeunload-false.html'))
|
||||||
|
await emittedOnce(w, 'onbeforeunload')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('BrowserWindow.destroy()', () => {
|
||||||
|
let w = null as unknown as BrowserWindow
|
||||||
|
beforeEach(() => {
|
||||||
|
w = new BrowserWindow({show: false, webPreferences: {nodeIntegration: true}})
|
||||||
|
})
|
||||||
|
afterEach(async () => {
|
||||||
|
await closeWindow(w)
|
||||||
|
w = null as unknown as BrowserWindow
|
||||||
|
})
|
||||||
|
|
||||||
|
it('prevents users to access methods of webContents', async () => {
|
||||||
|
const contents = w.webContents
|
||||||
|
w.destroy()
|
||||||
|
await new Promise(setImmediate)
|
||||||
|
expect(() => {
|
||||||
|
contents.getProcessId()
|
||||||
|
}).to.throw('Object has been destroyed')
|
||||||
|
})
|
||||||
|
it('should not crash when destroying windows with pending events', () => {
|
||||||
|
const focusListener = () => {}
|
||||||
|
app.on('browser-window-focus', focusListener)
|
||||||
|
const windowCount = 3
|
||||||
|
const windowOptions = {
|
||||||
|
show: false,
|
||||||
|
width: 400,
|
||||||
|
height: 400,
|
||||||
|
webPreferences: {
|
||||||
|
backgroundThrottling: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const windows = Array.from(Array(windowCount)).map(x => new BrowserWindow(windowOptions))
|
||||||
|
windows.forEach(win => win.show())
|
||||||
|
windows.forEach(win => win.focus())
|
||||||
|
windows.forEach(win => win.destroy())
|
||||||
|
app.removeListener('browser-window-focus', focusListener)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('BrowserWindow.loadURL(url)', () => {
|
||||||
|
let w = null as unknown as BrowserWindow
|
||||||
|
beforeEach(() => {
|
||||||
|
w = new BrowserWindow({show: false, webPreferences: {nodeIntegration: true}})
|
||||||
|
})
|
||||||
|
afterEach(async () => {
|
||||||
|
await closeWindow(w)
|
||||||
|
w = null as unknown as BrowserWindow
|
||||||
|
})
|
||||||
|
let server = null as unknown as http.Server
|
||||||
|
let url = null as unknown as string
|
||||||
|
let postData = null as any
|
||||||
|
before((done) => {
|
||||||
|
const filePath = path.join(fixtures, 'pages', 'a.html')
|
||||||
|
const fileStats = fs.statSync(filePath)
|
||||||
|
postData = [
|
||||||
|
{
|
||||||
|
type: 'rawData',
|
||||||
|
bytes: Buffer.from('username=test&file=')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'file',
|
||||||
|
filePath: filePath,
|
||||||
|
offset: 0,
|
||||||
|
length: fileStats.size,
|
||||||
|
modificationTime: fileStats.mtime.getTime() / 1000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
server = http.createServer((req, res) => {
|
||||||
|
function respond () {
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
let body = ''
|
||||||
|
req.on('data', (data) => {
|
||||||
|
if (data) body += data
|
||||||
|
})
|
||||||
|
req.on('end', () => {
|
||||||
|
const parsedData = qs.parse(body)
|
||||||
|
fs.readFile(filePath, (err, data) => {
|
||||||
|
if (err) return
|
||||||
|
if (parsedData.username === 'test' &&
|
||||||
|
parsedData.file === data.toString()) {
|
||||||
|
res.end()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else if (req.url === '/302') {
|
||||||
|
res.setHeader('Location', '/200')
|
||||||
|
res.statusCode = 302
|
||||||
|
res.end()
|
||||||
|
} else {
|
||||||
|
res.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(respond, req.url && req.url.includes('slow') ? 200 : 0)
|
||||||
|
})
|
||||||
|
server.listen(0, '127.0.0.1', () => {
|
||||||
|
url = `http://127.0.0.1:${(server.address() as AddressInfo).port}`
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
server.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should emit did-start-loading event', (done) => {
|
||||||
|
w.webContents.on('did-start-loading', () => { done() })
|
||||||
|
w.loadURL('about:blank')
|
||||||
|
})
|
||||||
|
it('should emit ready-to-show event', (done) => {
|
||||||
|
w.on('ready-to-show', () => { done() })
|
||||||
|
w.loadURL('about:blank')
|
||||||
|
})
|
||||||
|
it('should emit did-fail-load event for files that do not exist', (done) => {
|
||||||
|
w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => {
|
||||||
|
expect(code).to.equal(-6)
|
||||||
|
expect(desc).to.equal('ERR_FILE_NOT_FOUND')
|
||||||
|
expect(isMainFrame).to.equal(true)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL('file://a.txt')
|
||||||
|
})
|
||||||
|
it('should emit did-fail-load event for invalid URL', (done) => {
|
||||||
|
w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => {
|
||||||
|
expect(desc).to.equal('ERR_INVALID_URL')
|
||||||
|
expect(code).to.equal(-300)
|
||||||
|
expect(isMainFrame).to.equal(true)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL('http://example:port')
|
||||||
|
})
|
||||||
|
it('should set `mainFrame = false` on did-fail-load events in iframes', (done) => {
|
||||||
|
w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => {
|
||||||
|
expect(isMainFrame).to.equal(false)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'did-fail-load-iframe.html'))
|
||||||
|
})
|
||||||
|
it('does not crash in did-fail-provisional-load handler', (done) => {
|
||||||
|
w.webContents.once('did-fail-provisional-load', () => {
|
||||||
|
w.loadURL('http://127.0.0.1:11111')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL('http://127.0.0.1:11111')
|
||||||
|
})
|
||||||
|
it('should emit did-fail-load event for URL exceeding character limit', (done) => {
|
||||||
|
w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => {
|
||||||
|
expect(desc).to.equal('ERR_INVALID_URL')
|
||||||
|
expect(code).to.equal(-300)
|
||||||
|
expect(isMainFrame).to.equal(true)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
const data = Buffer.alloc(2 * 1024 * 1024).toString('base64')
|
||||||
|
w.loadURL(`data:image/png;base64,${data}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return a promise', () => {
|
||||||
|
const p = w.loadURL('about:blank')
|
||||||
|
expect(p).to.have.property('then')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return a promise that resolves', async () => {
|
||||||
|
expect(w.loadURL('about:blank')).to.eventually.be.fulfilled
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return a promise that rejects on a load failure', async () => {
|
||||||
|
const data = Buffer.alloc(2 * 1024 * 1024).toString('base64')
|
||||||
|
const p = w.loadURL(`data:image/png;base64,${data}`)
|
||||||
|
await expect(p).to.eventually.be.rejected
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return a promise that resolves even if pushState occurs during navigation', async () => {
|
||||||
|
const p = w.loadURL('data:text/html,<script>window.history.pushState({}, "/foo")</script>')
|
||||||
|
await expect(p).to.eventually.be.fulfilled
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('POST navigations', () => {
|
||||||
|
afterEach(() => { w.webContents.session.webRequest.onBeforeSendHeaders(null) })
|
||||||
|
|
||||||
|
it('supports specifying POST data', async () => {
|
||||||
|
await w.loadURL(url, { postData })
|
||||||
|
})
|
||||||
|
it('sets the content type header on URL encoded forms', async () => {
|
||||||
|
await w.loadURL(url)
|
||||||
|
const requestDetails: Promise<OnBeforeSendHeadersListenerDetails> = new Promise(resolve => {
|
||||||
|
w.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => {
|
||||||
|
resolve(details)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
w.webContents.executeJavaScript(`
|
||||||
|
form = document.createElement('form')
|
||||||
|
document.body.appendChild(form)
|
||||||
|
form.method = 'POST'
|
||||||
|
form.submit()
|
||||||
|
`)
|
||||||
|
const details = await requestDetails
|
||||||
|
expect(details.requestHeaders['Content-Type']).to.equal('application/x-www-form-urlencoded')
|
||||||
|
})
|
||||||
|
it('sets the content type header on multi part forms', async () => {
|
||||||
|
await w.loadURL(url)
|
||||||
|
const requestDetails: Promise<OnBeforeSendHeadersListenerDetails> = new Promise(resolve => {
|
||||||
|
w.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => {
|
||||||
|
resolve(details)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
w.webContents.executeJavaScript(`
|
||||||
|
form = document.createElement('form')
|
||||||
|
document.body.appendChild(form)
|
||||||
|
form.method = 'POST'
|
||||||
|
form.enctype = 'multipart/form-data'
|
||||||
|
file = document.createElement('input')
|
||||||
|
file.type = 'file'
|
||||||
|
file.name = 'file'
|
||||||
|
form.appendChild(file)
|
||||||
|
form.submit()
|
||||||
|
`)
|
||||||
|
const details = await requestDetails
|
||||||
|
expect(details.requestHeaders['Content-Type'].startsWith('multipart/form-data; boundary=----WebKitFormBoundary')).to.equal(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should support support base url for data urls', (done) => {
|
||||||
|
ipcMain.once('answer', (event, test) => {
|
||||||
|
expect(test).to.equal('test')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL('data:text/html,<script src="loaded-from-dataurl.js"></script>', { baseURLForDataURL: `file://${path.join(fixtures, 'api')}${path.sep}` })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('navigation events', () => {
|
||||||
|
let w = null as unknown as BrowserWindow
|
||||||
|
beforeEach(() => {
|
||||||
|
w = new BrowserWindow({show: false, webPreferences: {nodeIntegration: true}})
|
||||||
|
})
|
||||||
|
afterEach(async () => {
|
||||||
|
await closeWindow(w)
|
||||||
|
w = null as unknown as BrowserWindow
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('will-navigate event', () => {
|
||||||
|
it('allows the window to be closed from the event listener', (done) => {
|
||||||
|
w.webContents.once('will-navigate', () => {
|
||||||
|
w.close()
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadFile(path.join(fixtures, 'pages', 'will-navigate.html'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('will-redirect event', () => {
|
||||||
|
let server = null as unknown as http.Server
|
||||||
|
let url = null as unknown as string
|
||||||
|
before((done) => {
|
||||||
|
server = http.createServer((req, res) => {
|
||||||
|
if (req.url === '/302') {
|
||||||
|
res.setHeader('Location', '/200')
|
||||||
|
res.statusCode = 302
|
||||||
|
res.end()
|
||||||
|
} else if (req.url === '/navigate-302') {
|
||||||
|
res.end(`<html><body><script>window.location='${url}/302'</script></body></html>`)
|
||||||
|
} else {
|
||||||
|
res.end()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
server.listen(0, '127.0.0.1', () => {
|
||||||
|
url = `http://127.0.0.1:${(server.address() as AddressInfo).port}`
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
server.close()
|
||||||
|
})
|
||||||
|
it('is emitted on redirects', (done) => {
|
||||||
|
w.webContents.on('will-redirect', (event, url) => {
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL(`${url}/302`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('is emitted after will-navigate on redirects', (done) => {
|
||||||
|
let navigateCalled = false
|
||||||
|
w.webContents.on('will-navigate', () => {
|
||||||
|
navigateCalled = true
|
||||||
|
})
|
||||||
|
w.webContents.on('will-redirect', (event, url) => {
|
||||||
|
expect(navigateCalled).to.equal(true, 'should have called will-navigate first')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL(`${url}/navigate-302`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('is emitted before did-stop-loading on redirects', (done) => {
|
||||||
|
let stopCalled = false
|
||||||
|
w.webContents.on('did-stop-loading', () => {
|
||||||
|
stopCalled = true
|
||||||
|
})
|
||||||
|
w.webContents.on('will-redirect', (event, url) => {
|
||||||
|
expect(stopCalled).to.equal(false, 'should not have called did-stop-loading first')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL(`${url}/302`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows the window to be closed from the event listener', (done) => {
|
||||||
|
w.webContents.once('will-redirect', (event, input) => {
|
||||||
|
w.close()
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL(`${url}/302`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.skip('can be prevented', (done) => {
|
||||||
|
w.webContents.once('will-redirect', (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
})
|
||||||
|
w.webContents.on('will-navigate', (e, url) => {
|
||||||
|
expect(url).to.equal(`${url}/302`)
|
||||||
|
})
|
||||||
|
w.webContents.on('did-stop-loading', () => {
|
||||||
|
expect(w.webContents.getURL()).to.equal(
|
||||||
|
`${url}/navigate-302`,
|
||||||
|
'url should not have changed after navigation event'
|
||||||
|
)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.webContents.on('will-redirect', (e, url) => {
|
||||||
|
expect(url).to.equal(`${url}/200`)
|
||||||
|
})
|
||||||
|
w.loadURL(`${url}/navigate-302`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('BrowserWindow.show()', () => {
|
||||||
|
let w = null as unknown as BrowserWindow
|
||||||
|
beforeEach(() => {
|
||||||
|
w = new BrowserWindow({show: false, webPreferences: {nodeIntegration: true}})
|
||||||
|
})
|
||||||
|
afterEach(async () => {
|
||||||
|
await closeWindow(w)
|
||||||
|
w = null as unknown as BrowserWindow
|
||||||
|
})
|
||||||
|
it('should focus on window', () => {
|
||||||
|
w.show()
|
||||||
|
if (process.platform === 'darwin' && !isCI) {
|
||||||
|
// on CI, the Electron window will be the only one open, so it'll get
|
||||||
|
// focus. on not-CI, some other window will have focus, and we don't
|
||||||
|
// steal focus any more, so we expect isFocused to be false.
|
||||||
|
expect(w.isFocused()).to.equal(false)
|
||||||
|
} else {
|
||||||
|
expect(w.isFocused()).to.equal(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should make the window visible', () => {
|
||||||
|
w.show()
|
||||||
|
expect(w.isVisible()).to.equal(true)
|
||||||
|
})
|
||||||
|
it('emits when window is shown', (done) => {
|
||||||
|
w.once('show', () => {
|
||||||
|
expect(w.isVisible()).to.equal(true)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.show()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('BrowserWindow.hide()', () => {
|
||||||
|
let w = null as unknown as BrowserWindow
|
||||||
|
beforeEach(() => {
|
||||||
|
w = new BrowserWindow({show: false, webPreferences: {nodeIntegration: true}})
|
||||||
|
})
|
||||||
|
afterEach(async () => {
|
||||||
|
await closeWindow(w)
|
||||||
|
w = null as unknown as BrowserWindow
|
||||||
|
})
|
||||||
|
it('should defocus on window', () => {
|
||||||
|
w.hide()
|
||||||
|
expect(w.isFocused()).to.equal(false)
|
||||||
|
})
|
||||||
|
it('should make the window not visible', () => {
|
||||||
|
w.show()
|
||||||
|
w.hide()
|
||||||
|
expect(w.isVisible()).to.equal(false)
|
||||||
|
})
|
||||||
|
it('emits when window is hidden', async () => {
|
||||||
|
const shown = emittedOnce(w, 'show')
|
||||||
|
w.show()
|
||||||
|
await shown
|
||||||
|
const hidden = emittedOnce(w, 'hide')
|
||||||
|
w.hide()
|
||||||
|
await hidden
|
||||||
|
expect(w.isVisible()).to.equal(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
|
@ -30,9 +30,12 @@ export const closeWindow = async (
|
||||||
|
|
||||||
if (assertNotWindows) {
|
if (assertNotWindows) {
|
||||||
const windows = BrowserWindow.getAllWindows()
|
const windows = BrowserWindow.getAllWindows()
|
||||||
for (const win of windows) {
|
try {
|
||||||
await ensureWindowIsClosed(win)
|
expect(windows).to.have.lengthOf(0)
|
||||||
|
} finally {
|
||||||
|
for (const win of windows) {
|
||||||
|
await ensureWindowIsClosed(win)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
expect(windows).to.have.lengthOf(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,374 +113,6 @@ describe('BrowserWindow module', () => {
|
||||||
|
|
||||||
afterEach(closeTheWindow)
|
afterEach(closeTheWindow)
|
||||||
|
|
||||||
describe('BrowserWindow constructor', () => {
|
|
||||||
it('allows passing void 0 as the webContents', async () => {
|
|
||||||
await openTheWindow({
|
|
||||||
webContents: void 0
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('BrowserWindow.close()', () => {
|
|
||||||
let server
|
|
||||||
|
|
||||||
before((done) => {
|
|
||||||
server = http.createServer((request, response) => {
|
|
||||||
switch (request.url) {
|
|
||||||
case '/404':
|
|
||||||
response.statusCode = '404'
|
|
||||||
response.end()
|
|
||||||
break
|
|
||||||
case '/301':
|
|
||||||
response.statusCode = '301'
|
|
||||||
response.setHeader('Location', '/200')
|
|
||||||
response.end()
|
|
||||||
break
|
|
||||||
case '/200':
|
|
||||||
response.statusCode = '200'
|
|
||||||
response.end('hello')
|
|
||||||
break
|
|
||||||
case '/title':
|
|
||||||
response.statusCode = '200'
|
|
||||||
response.end('<title>Hello</title>')
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
done('unsupported endpoint')
|
|
||||||
}
|
|
||||||
}).listen(0, '127.0.0.1', () => {
|
|
||||||
server.url = 'http://127.0.0.1:' + server.address().port
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
server.close()
|
|
||||||
server = null
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should emit unload handler', (done) => {
|
|
||||||
w.webContents.once('did-finish-load', () => { w.close() })
|
|
||||||
w.once('closed', () => {
|
|
||||||
const test = path.join(fixtures, 'api', 'unload')
|
|
||||||
const content = fs.readFileSync(test)
|
|
||||||
fs.unlinkSync(test)
|
|
||||||
expect(String(content)).to.equal('unload')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'unload.html'))
|
|
||||||
})
|
|
||||||
it('should emit beforeunload handler', (done) => {
|
|
||||||
w.once('onbeforeunload', () => { done() })
|
|
||||||
w.webContents.once('did-finish-load', () => { w.close() })
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'beforeunload-false.html'))
|
|
||||||
})
|
|
||||||
it('should not crash when invoked synchronously inside navigation observer', (done) => {
|
|
||||||
const events = [
|
|
||||||
{ name: 'did-start-loading', url: `${server.url}/200` },
|
|
||||||
{ name: 'dom-ready', url: `${server.url}/200` },
|
|
||||||
{ name: 'page-title-updated', url: `${server.url}/title` },
|
|
||||||
{ name: 'did-stop-loading', url: `${server.url}/200` },
|
|
||||||
{ name: 'did-finish-load', url: `${server.url}/200` },
|
|
||||||
{ name: 'did-frame-finish-load', url: `${server.url}/200` },
|
|
||||||
{ name: 'did-fail-load', url: `${server.url}/404` }
|
|
||||||
]
|
|
||||||
const responseEvent = 'window-webContents-destroyed'
|
|
||||||
|
|
||||||
function * genNavigationEvent () {
|
|
||||||
let eventOptions = null
|
|
||||||
while ((eventOptions = events.shift()) && events.length) {
|
|
||||||
const w = new BrowserWindow({ show: false })
|
|
||||||
eventOptions.id = w.id
|
|
||||||
eventOptions.responseEvent = responseEvent
|
|
||||||
ipcRenderer.send('test-webcontents-navigation-observer', eventOptions)
|
|
||||||
yield 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const gen = genNavigationEvent()
|
|
||||||
ipcRenderer.on(responseEvent, () => {
|
|
||||||
if (!gen.next().value) done()
|
|
||||||
})
|
|
||||||
gen.next()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('window.close()', () => {
|
|
||||||
it('should emit unload handler', (done) => {
|
|
||||||
w.once('closed', () => {
|
|
||||||
const test = path.join(fixtures, 'api', 'close')
|
|
||||||
const content = fs.readFileSync(test)
|
|
||||||
fs.unlinkSync(test)
|
|
||||||
expect(String(content)).to.equal('close')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'close.html'))
|
|
||||||
})
|
|
||||||
it('should emit beforeunload handler', (done) => {
|
|
||||||
w.once('onbeforeunload', () => { done() })
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'close-beforeunload-false.html'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('BrowserWindow.destroy()', () => {
|
|
||||||
it('prevents users to access methods of webContents', () => {
|
|
||||||
const contents = w.webContents
|
|
||||||
w.destroy()
|
|
||||||
expect(() => {
|
|
||||||
contents.getProcessId()
|
|
||||||
}).to.throw('Object has been destroyed')
|
|
||||||
})
|
|
||||||
it('should not crash when destroying windows with pending events', (done) => {
|
|
||||||
const responseEvent = 'destroy-test-completed'
|
|
||||||
ipcRenderer.on(responseEvent, () => done())
|
|
||||||
ipcRenderer.send('test-browserwindow-destroy', { responseEvent })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('BrowserWindow.loadURL(url)', () => {
|
|
||||||
it('should emit did-start-loading event', (done) => {
|
|
||||||
w.webContents.on('did-start-loading', () => { done() })
|
|
||||||
w.loadURL('about:blank')
|
|
||||||
})
|
|
||||||
it('should emit ready-to-show event', (done) => {
|
|
||||||
w.on('ready-to-show', () => { done() })
|
|
||||||
w.loadURL('about:blank')
|
|
||||||
})
|
|
||||||
it('should emit did-fail-load event for files that do not exist', (done) => {
|
|
||||||
w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => {
|
|
||||||
expect(code).to.equal(-6)
|
|
||||||
expect(desc).to.equal('ERR_FILE_NOT_FOUND')
|
|
||||||
expect(isMainFrame).to.be.true()
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadURL('file://a.txt')
|
|
||||||
})
|
|
||||||
it('should emit did-fail-load event for invalid URL', (done) => {
|
|
||||||
w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => {
|
|
||||||
expect(desc).to.equal('ERR_INVALID_URL')
|
|
||||||
expect(code).to.equal(-300)
|
|
||||||
expect(isMainFrame).to.be.true()
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadURL('http://example:port')
|
|
||||||
})
|
|
||||||
it('should set `mainFrame = false` on did-fail-load events in iframes', (done) => {
|
|
||||||
w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => {
|
|
||||||
expect(isMainFrame).to.be.false()
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'did-fail-load-iframe.html'))
|
|
||||||
})
|
|
||||||
it('does not crash in did-fail-provisional-load handler', (done) => {
|
|
||||||
w.webContents.once('did-fail-provisional-load', () => {
|
|
||||||
w.loadURL('http://127.0.0.1:11111')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadURL('http://127.0.0.1:11111')
|
|
||||||
})
|
|
||||||
it('should emit did-fail-load event for URL exceeding character limit', (done) => {
|
|
||||||
w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => {
|
|
||||||
expect(desc).to.equal('ERR_INVALID_URL')
|
|
||||||
expect(code).to.equal(-300)
|
|
||||||
expect(isMainFrame).to.be.true()
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
const data = Buffer.alloc(2 * 1024 * 1024).toString('base64')
|
|
||||||
w.loadURL(`data:image/png;base64,${data}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return a promise', () => {
|
|
||||||
const p = w.loadURL('about:blank')
|
|
||||||
expect(p).to.have.property('then')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return a promise that resolves', async () => {
|
|
||||||
expect(w.loadURL('about:blank')).to.eventually.be.fulfilled()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return a promise that rejects on a load failure', async () => {
|
|
||||||
const data = Buffer.alloc(2 * 1024 * 1024).toString('base64')
|
|
||||||
const p = w.loadURL(`data:image/png;base64,${data}`)
|
|
||||||
await expect(p).to.eventually.be.rejected()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return a promise that resolves even if pushState occurs during navigation', async () => {
|
|
||||||
const data = Buffer.alloc(2 * 1024 * 1024).toString('base64')
|
|
||||||
const p = w.loadURL('data:text/html,<script>window.history.pushState({}, "/foo")</script>')
|
|
||||||
await expect(p).to.eventually.be.fulfilled()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('POST navigations', () => {
|
|
||||||
afterEach(() => { w.webContents.session.webRequest.onBeforeSendHeaders(null) })
|
|
||||||
|
|
||||||
it('supports specifying POST data', async () => {
|
|
||||||
await w.loadURL(server.url, { postData: postData })
|
|
||||||
})
|
|
||||||
it('sets the content type header on URL encoded forms', async () => {
|
|
||||||
await w.loadURL(server.url)
|
|
||||||
const requestDetails = new Promise(resolve => {
|
|
||||||
w.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => {
|
|
||||||
resolve(details)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
w.webContents.executeJavaScript(`
|
|
||||||
form = document.createElement('form')
|
|
||||||
document.body.appendChild(form)
|
|
||||||
form.method = 'POST'
|
|
||||||
form.target = '_blank'
|
|
||||||
form.submit()
|
|
||||||
`)
|
|
||||||
const details = await requestDetails
|
|
||||||
expect(details.requestHeaders['content-type']).to.equal('application/x-www-form-urlencoded')
|
|
||||||
})
|
|
||||||
it('sets the content type header on multi part forms', async () => {
|
|
||||||
await w.loadURL(server.url)
|
|
||||||
const requestDetails = new Promise(resolve => {
|
|
||||||
w.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => {
|
|
||||||
resolve(details)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
w.webContents.executeJavaScript(`
|
|
||||||
form = document.createElement('form')
|
|
||||||
document.body.appendChild(form)
|
|
||||||
form.method = 'POST'
|
|
||||||
form.target = '_blank'
|
|
||||||
form.enctype = 'multipart/form-data'
|
|
||||||
file = document.createElement('input')
|
|
||||||
file.type = 'file'
|
|
||||||
file.name = 'file'
|
|
||||||
form.appendChild(file)
|
|
||||||
form.submit()
|
|
||||||
`)
|
|
||||||
const details = await requestDetails
|
|
||||||
expect(details.requestHeaders['content-type'].startsWith('multipart/form-data; boundary=----WebKitFormBoundary')).to.be.true()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should support support base url for data urls', (done) => {
|
|
||||||
ipcMain.once('answer', (event, test) => {
|
|
||||||
expect(test).to.equal('test')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadURL('data:text/html,<script src="loaded-from-dataurl.js"></script>', { baseURLForDataURL: `file://${path.join(fixtures, 'api')}${path.sep}` })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('will-navigate event', () => {
|
|
||||||
it('allows the window to be closed from the event listener', (done) => {
|
|
||||||
ipcRenderer.send('close-on-will-navigate', w.id)
|
|
||||||
ipcRenderer.once('closed-on-will-navigate', () => { done() })
|
|
||||||
w.loadFile(path.join(fixtures, 'pages', 'will-navigate.html'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('will-redirect event', () => {
|
|
||||||
it('is emitted on redirects', (done) => {
|
|
||||||
w.webContents.on('will-redirect', (event, url) => {
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadURL(`${server.url}/302`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('is emitted after will-navigate on redirects', (done) => {
|
|
||||||
let navigateCalled = false
|
|
||||||
w.webContents.on('will-navigate', () => {
|
|
||||||
navigateCalled = true
|
|
||||||
})
|
|
||||||
w.webContents.on('will-redirect', (event, url) => {
|
|
||||||
expect(navigateCalled).to.equal(true, 'should have called will-navigate first')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadURL(`${server.url}/navigate-302`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('is emitted before did-stop-loading on redirects', (done) => {
|
|
||||||
let stopCalled = false
|
|
||||||
w.webContents.on('did-stop-loading', () => {
|
|
||||||
stopCalled = true
|
|
||||||
})
|
|
||||||
w.webContents.on('will-redirect', (event, url) => {
|
|
||||||
expect(stopCalled).to.equal(false, 'should not have called did-stop-loading first')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadURL(`${server.url}/302`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('allows the window to be closed from the event listener', (done) => {
|
|
||||||
ipcRenderer.send('close-on-will-redirect', w.id)
|
|
||||||
ipcRenderer.once('closed-on-will-redirect', () => { done() })
|
|
||||||
w.loadURL(`${server.url}/302`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it.skip('can be prevented', (done) => {
|
|
||||||
ipcRenderer.send('prevent-will-redirect', w.id)
|
|
||||||
w.webContents.on('will-navigate', (e, url) => {
|
|
||||||
expect(url).to.equal(`${server.url}/302`)
|
|
||||||
})
|
|
||||||
w.webContents.on('did-stop-loading', () => {
|
|
||||||
expect(w.webContents.getURL()).to.equal(
|
|
||||||
`${server.url}/navigate-302`,
|
|
||||||
'url should not have changed after navigation event'
|
|
||||||
)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.webContents.on('will-redirect', (e, url) => {
|
|
||||||
expect(url).to.equal(`${server.url}/200`)
|
|
||||||
})
|
|
||||||
w.loadURL(`${server.url}/navigate-302`)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('BrowserWindow.show()', () => {
|
|
||||||
before(function () {
|
|
||||||
if (isCI) {
|
|
||||||
this.skip()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should focus on window', () => {
|
|
||||||
w.show()
|
|
||||||
expect(w.isFocused()).to.be.true()
|
|
||||||
})
|
|
||||||
it('should make the window visible', () => {
|
|
||||||
w.show()
|
|
||||||
expect(w.isVisible()).to.be.true()
|
|
||||||
})
|
|
||||||
it('emits when window is shown', (done) => {
|
|
||||||
w.once('show', () => {
|
|
||||||
expect(w.isVisible()).to.be.true()
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.show()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('BrowserWindow.hide()', () => {
|
|
||||||
before(function () {
|
|
||||||
if (isCI) {
|
|
||||||
this.skip()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should defocus on window', () => {
|
|
||||||
w.hide()
|
|
||||||
expect(w.isFocused()).to.be.false()
|
|
||||||
})
|
|
||||||
it('should make the window not visible', () => {
|
|
||||||
w.show()
|
|
||||||
w.hide()
|
|
||||||
expect(w.isVisible()).to.be.false()
|
|
||||||
})
|
|
||||||
it('emits when window is hidden', (done) => {
|
|
||||||
w.show()
|
|
||||||
w.once('hide', () => {
|
|
||||||
expect(w.isVisible()).to.be.false()
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.hide()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('BrowserWindow.showInactive()', () => {
|
describe('BrowserWindow.showInactive()', () => {
|
||||||
it('should not focus on window', () => {
|
it('should not focus on window', () => {
|
||||||
w.showInactive()
|
w.showInactive()
|
||||||
|
|
|
@ -232,31 +232,6 @@ ipcMain.on('set-client-certificate-option', function (event, skip) {
|
||||||
event.returnValue = 'done'
|
event.returnValue = 'done'
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('close-on-will-navigate', (event, id) => {
|
|
||||||
const contents = event.sender
|
|
||||||
const window = BrowserWindow.fromId(id)
|
|
||||||
window.webContents.once('will-navigate', (event, input) => {
|
|
||||||
window.close()
|
|
||||||
contents.send('closed-on-will-navigate')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('close-on-will-redirect', (event, id) => {
|
|
||||||
const contents = event.sender
|
|
||||||
const window = BrowserWindow.fromId(id)
|
|
||||||
window.webContents.once('will-redirect', (event, input) => {
|
|
||||||
window.close()
|
|
||||||
contents.send('closed-on-will-redirect')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('prevent-will-redirect', (event, id) => {
|
|
||||||
const window = BrowserWindow.fromId(id)
|
|
||||||
window.webContents.once('will-redirect', (event) => {
|
|
||||||
event.preventDefault()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('create-window-with-options-cycle', (event) => {
|
ipcMain.on('create-window-with-options-cycle', (event) => {
|
||||||
// This can't be done over remote since cycles are already
|
// This can't be done over remote since cycles are already
|
||||||
// nulled out at the IPC layer
|
// nulled out at the IPC layer
|
||||||
|
@ -347,47 +322,6 @@ ipcMain.on('crash-service-pid', (event, pid) => {
|
||||||
event.returnValue = null
|
event.returnValue = null
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('test-webcontents-navigation-observer', (event, options) => {
|
|
||||||
let contents = null
|
|
||||||
let destroy = () => {}
|
|
||||||
if (options.id) {
|
|
||||||
const w = BrowserWindow.fromId(options.id)
|
|
||||||
contents = w.webContents
|
|
||||||
destroy = () => w.close()
|
|
||||||
} else {
|
|
||||||
contents = webContents.create()
|
|
||||||
destroy = () => contents.destroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
contents.once(options.name, () => destroy())
|
|
||||||
|
|
||||||
contents.once('destroyed', () => {
|
|
||||||
event.sender.send(options.responseEvent)
|
|
||||||
})
|
|
||||||
|
|
||||||
contents.loadURL(options.url)
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('test-browserwindow-destroy', (event, testOptions) => {
|
|
||||||
const focusListener = (event, win) => win.id
|
|
||||||
app.on('browser-window-focus', focusListener)
|
|
||||||
const windowCount = 3
|
|
||||||
const windowOptions = {
|
|
||||||
show: false,
|
|
||||||
width: 400,
|
|
||||||
height: 400,
|
|
||||||
webPreferences: {
|
|
||||||
backgroundThrottling: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const windows = Array.from(Array(windowCount)).map(x => new BrowserWindow(windowOptions))
|
|
||||||
windows.forEach(win => win.show())
|
|
||||||
windows.forEach(win => win.focus())
|
|
||||||
windows.forEach(win => win.destroy())
|
|
||||||
app.removeListener('browser-window-focus', focusListener)
|
|
||||||
event.sender.send(testOptions.responseEvent)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Suspend listeners until the next event and then restore them
|
// Suspend listeners until the next event and then restore them
|
||||||
const suspendListeners = (emitter, eventName, callback) => {
|
const suspendListeners = (emitter, eventName, callback) => {
|
||||||
const listeners = emitter.listeners(eventName)
|
const listeners = emitter.listeners(eventName)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue