test: move the last of the browser window specs (#19295)
* move devtools extensions tests * move executeJavaScript tests * move previewFile test * move contextIsolation tests * move OSR tests * RIP api-browser-window-spec.js .--. .-, .-..-.__ .'(`.-` \_.-'-./` |\_( "\__ __.>\ '; _;---,._| / __/`'--) /.--. : |/' _.--.<| / | | _..-' `\ /' /` /_/ _/_/ >_.-``-. `Y /' _;---.`|/)))) '` .-''. \|: .' __, .-'"` .'--._ `-: \/: /' '.\ _|_ /.'`\ :; /' `- `-|-` -` | | | :.; : | .-'~^~`-. |: | .' _ _ `. |:. | | |_) | |_) | :. : | | | \ | | | : ; | | | : ; | | Here lies | : ; | | 1000 | : ; | | flaky | : ; | | tests | .jgs. : ; | | -."-/\\\/:::. `\."-._'."-"_\\-| |///."- " -."-.\\"-."//.-".`-."_\\-.".-\\`=.........=`//-". * remove unused ipcMain listeners * remove debugging logs * close windows in offscreen test * more closeAllWindows * remove extra logs * refactor webContents main spec using closeAllWindows
This commit is contained in:
parent
16011cacef
commit
2a5d40617a
4 changed files with 600 additions and 755 deletions
|
@ -2448,15 +2448,12 @@ describe('BrowserWindow module', () => {
|
||||||
throw new Error(`Unexpected visibility change event. visibilityState: ${visibilityState} hidden: ${hidden}`)
|
throw new Error(`Unexpected visibility change event. visibilityState: ${visibilityState} hidden: ${hidden}`)
|
||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
console.log("c 1")
|
|
||||||
const shown1 = emittedOnce(w, 'show')
|
const shown1 = emittedOnce(w, 'show')
|
||||||
w.show()
|
w.show()
|
||||||
await shown1
|
await shown1
|
||||||
console.log("c 2")
|
|
||||||
const hidden = emittedOnce(w, 'hide')
|
const hidden = emittedOnce(w, 'hide')
|
||||||
w.hide()
|
w.hide()
|
||||||
await hidden
|
await hidden
|
||||||
console.log("c 3")
|
|
||||||
const shown2 = emittedOnce(w, 'show')
|
const shown2 = emittedOnce(w, 'show')
|
||||||
w.show()
|
w.show()
|
||||||
await shown2
|
await shown2
|
||||||
|
@ -2682,31 +2679,24 @@ describe('BrowserWindow module', () => {
|
||||||
ifdescribe(process.platform === 'win32')('on windows', () => {
|
ifdescribe(process.platform === 'win32')('on windows', () => {
|
||||||
it('should restore a normal visible window from a fullscreen startup state', async () => {
|
it('should restore a normal visible window from a fullscreen startup state', async () => {
|
||||||
const w = new BrowserWindow({show: false})
|
const w = new BrowserWindow({show: false})
|
||||||
console.log("a 1")
|
|
||||||
await w.loadURL('about:blank')
|
await w.loadURL('about:blank')
|
||||||
console.log("a 2")
|
|
||||||
const shown = emittedOnce(w, 'show')
|
const shown = emittedOnce(w, 'show')
|
||||||
// start fullscreen and hidden
|
// start fullscreen and hidden
|
||||||
w.setFullScreen(true)
|
w.setFullScreen(true)
|
||||||
w.show()
|
w.show()
|
||||||
await shown
|
await shown
|
||||||
console.log("a 3")
|
|
||||||
const leftFullScreen = emittedOnce(w, 'leave-full-screen')
|
const leftFullScreen = emittedOnce(w, 'leave-full-screen')
|
||||||
w.setFullScreen(false)
|
w.setFullScreen(false)
|
||||||
await leftFullScreen
|
await leftFullScreen
|
||||||
console.log("a 4")
|
|
||||||
expect(w.isVisible()).to.be.true('visible')
|
expect(w.isVisible()).to.be.true('visible')
|
||||||
expect(w.isFullScreen()).to.be.false('fullscreen')
|
expect(w.isFullScreen()).to.be.false('fullscreen')
|
||||||
})
|
})
|
||||||
it('should keep window hidden if already in hidden state', async () => {
|
it('should keep window hidden if already in hidden state', async () => {
|
||||||
const w = new BrowserWindow({show: false})
|
const w = new BrowserWindow({show: false})
|
||||||
console.log("b 1")
|
|
||||||
await w.loadURL('about:blank')
|
await w.loadURL('about:blank')
|
||||||
console.log("b 2")
|
|
||||||
const leftFullScreen = emittedOnce(w, 'leave-full-screen')
|
const leftFullScreen = emittedOnce(w, 'leave-full-screen')
|
||||||
w.setFullScreen(false)
|
w.setFullScreen(false)
|
||||||
await leftFullScreen
|
await leftFullScreen
|
||||||
console.log("b 3")
|
|
||||||
expect(w.isVisible()).to.be.false('visible')
|
expect(w.isVisible()).to.be.false('visible')
|
||||||
expect(w.isFullScreen()).to.be.false('fullscreen')
|
expect(w.isFullScreen()).to.be.false('fullscreen')
|
||||||
})
|
})
|
||||||
|
@ -3328,4 +3318,477 @@ describe('BrowserWindow module', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ifdescribe(!process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS)('window.getNativeWindowHandle()', () => {
|
||||||
|
afterEach(closeAllWindows)
|
||||||
|
it('returns valid handle', () => {
|
||||||
|
const w = new BrowserWindow({show: false})
|
||||||
|
// The module's source code is hosted at
|
||||||
|
// https://github.com/electron/node-is-valid-window
|
||||||
|
const isValidWindow = require('is-valid-window')
|
||||||
|
expect(isValidWindow(w.getNativeWindowHandle())).to.be.true('is valid window')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('extensions and dev tools extensions', () => {
|
||||||
|
let showPanelTimeoutId: NodeJS.Timeout | null = null
|
||||||
|
|
||||||
|
const showLastDevToolsPanel = (w: BrowserWindow) => {
|
||||||
|
w.webContents.once('devtools-opened', () => {
|
||||||
|
const show = () => {
|
||||||
|
if (w == null || w.isDestroyed()) return
|
||||||
|
const { devToolsWebContents } = w as unknown as { devToolsWebContents: WebContents | undefined }
|
||||||
|
if (devToolsWebContents == null || devToolsWebContents.isDestroyed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const showLastPanel = () => {
|
||||||
|
// this is executed in the devtools context, where UI is a global
|
||||||
|
const {UI} = (window as any)
|
||||||
|
const lastPanelId = UI.inspectorView._tabbedPane._tabs.peekLast().id
|
||||||
|
UI.inspectorView.showPanel(lastPanelId)
|
||||||
|
}
|
||||||
|
devToolsWebContents.executeJavaScript(`(${showLastPanel})()`, false).then(() => {
|
||||||
|
showPanelTimeoutId = setTimeout(show, 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
showPanelTimeoutId = setTimeout(show, 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
if (showPanelTimeoutId != null) {
|
||||||
|
clearTimeout(showPanelTimeoutId)
|
||||||
|
showPanelTimeoutId = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('BrowserWindow.addDevToolsExtension', () => {
|
||||||
|
describe('for invalid extensions', () => {
|
||||||
|
it('throws errors for missing manifest.json files', () => {
|
||||||
|
const nonexistentExtensionPath = path.join(__dirname, 'does-not-exist')
|
||||||
|
expect(() => {
|
||||||
|
BrowserWindow.addDevToolsExtension(nonexistentExtensionPath)
|
||||||
|
}).to.throw(/ENOENT: no such file or directory/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws errors for invalid manifest.json files', () => {
|
||||||
|
const badManifestExtensionPath = path.join(fixtures, 'devtools-extensions', 'bad-manifest')
|
||||||
|
expect(() => {
|
||||||
|
BrowserWindow.addDevToolsExtension(badManifestExtensionPath)
|
||||||
|
}).to.throw(/Unexpected token }/)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('for a valid extension', () => {
|
||||||
|
const extensionName = 'foo'
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
const extensionPath = path.join(fixtures, 'devtools-extensions', 'foo')
|
||||||
|
BrowserWindow.addDevToolsExtension(extensionPath)
|
||||||
|
expect(BrowserWindow.getDevToolsExtensions()).to.have.property(extensionName)
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
BrowserWindow.removeDevToolsExtension('foo')
|
||||||
|
expect(BrowserWindow.getDevToolsExtensions()).to.not.have.property(extensionName)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when the devtools is docked', () => {
|
||||||
|
let message: any
|
||||||
|
let w: BrowserWindow
|
||||||
|
before(async () => {
|
||||||
|
w = new BrowserWindow({show: false, webPreferences: {nodeIntegration: true}})
|
||||||
|
const p = new Promise(resolve => ipcMain.once('answer', (event, message) => {
|
||||||
|
resolve(message)
|
||||||
|
}))
|
||||||
|
showLastDevToolsPanel(w)
|
||||||
|
w.loadURL('about:blank')
|
||||||
|
w.webContents.openDevTools({ mode: 'bottom' })
|
||||||
|
message = await p
|
||||||
|
})
|
||||||
|
after(closeAllWindows)
|
||||||
|
|
||||||
|
describe('created extension info', function () {
|
||||||
|
it('has proper "runtimeId"', async function () {
|
||||||
|
expect(message).to.have.ownProperty('runtimeId')
|
||||||
|
expect(message.runtimeId).to.equal(extensionName)
|
||||||
|
})
|
||||||
|
it('has "tabId" matching webContents id', function () {
|
||||||
|
expect(message).to.have.ownProperty('tabId')
|
||||||
|
expect(message.tabId).to.equal(w.webContents.id)
|
||||||
|
})
|
||||||
|
it('has "i18nString" with proper contents', function () {
|
||||||
|
expect(message).to.have.ownProperty('i18nString')
|
||||||
|
expect(message.i18nString).to.equal('foo - bar (baz)')
|
||||||
|
})
|
||||||
|
it('has "storageItems" with proper contents', function () {
|
||||||
|
expect(message).to.have.ownProperty('storageItems')
|
||||||
|
expect(message.storageItems).to.deep.equal({
|
||||||
|
local: {
|
||||||
|
set: { hello: 'world', world: 'hello' },
|
||||||
|
remove: { world: 'hello' },
|
||||||
|
clear: {}
|
||||||
|
},
|
||||||
|
sync: {
|
||||||
|
set: { foo: 'bar', bar: 'foo' },
|
||||||
|
remove: { foo: 'bar' },
|
||||||
|
clear: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when the devtools is undocked', () => {
|
||||||
|
let message: any
|
||||||
|
let w: BrowserWindow
|
||||||
|
before(async () => {
|
||||||
|
w = new BrowserWindow({show: false, webPreferences: {nodeIntegration: true}})
|
||||||
|
showLastDevToolsPanel(w)
|
||||||
|
w.loadURL('about:blank')
|
||||||
|
w.webContents.openDevTools({ mode: 'undocked' })
|
||||||
|
message = await new Promise(resolve => ipcMain.once('answer', (event, message) => {
|
||||||
|
resolve(message)
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
after(closeAllWindows)
|
||||||
|
|
||||||
|
describe('created extension info', function () {
|
||||||
|
it('has proper "runtimeId"', function () {
|
||||||
|
expect(message).to.have.ownProperty('runtimeId')
|
||||||
|
expect(message.runtimeId).to.equal(extensionName)
|
||||||
|
})
|
||||||
|
it('has "tabId" matching webContents id', function () {
|
||||||
|
expect(message).to.have.ownProperty('tabId')
|
||||||
|
expect(message.tabId).to.equal(w.webContents.id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('works when used with partitions', async () => {
|
||||||
|
const w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
partition: 'temp'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const extensionPath = path.join(fixtures, 'devtools-extensions', 'foo')
|
||||||
|
BrowserWindow.addDevToolsExtension(extensionPath)
|
||||||
|
try {
|
||||||
|
showLastDevToolsPanel(w)
|
||||||
|
|
||||||
|
const p: Promise<any> = new Promise(resolve => ipcMain.once('answer', function (event, message) {
|
||||||
|
resolve(message)
|
||||||
|
}))
|
||||||
|
|
||||||
|
w.loadURL('about:blank')
|
||||||
|
w.webContents.openDevTools({ mode: 'bottom' })
|
||||||
|
const message = await p
|
||||||
|
expect(message.runtimeId).to.equal('foo')
|
||||||
|
} finally {
|
||||||
|
BrowserWindow.removeDevToolsExtension('foo')
|
||||||
|
await closeAllWindows()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('serializes the registered extensions on quit', () => {
|
||||||
|
const extensionName = 'foo'
|
||||||
|
const extensionPath = path.join(fixtures, 'devtools-extensions', extensionName)
|
||||||
|
const serializedPath = path.join(app.getPath('userData'), 'DevTools Extensions')
|
||||||
|
|
||||||
|
BrowserWindow.addDevToolsExtension(extensionPath)
|
||||||
|
app.emit('will-quit')
|
||||||
|
expect(JSON.parse(fs.readFileSync(serializedPath, 'utf8'))).to.deep.equal([extensionPath])
|
||||||
|
|
||||||
|
BrowserWindow.removeDevToolsExtension(extensionName)
|
||||||
|
app.emit('will-quit')
|
||||||
|
expect(fs.existsSync(serializedPath)).to.be.false('file exists')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('BrowserWindow.addExtension', () => {
|
||||||
|
it('throws errors for missing manifest.json files', () => {
|
||||||
|
expect(() => {
|
||||||
|
BrowserWindow.addExtension(path.join(__dirname, 'does-not-exist'))
|
||||||
|
}).to.throw('ENOENT: no such file or directory')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws errors for invalid manifest.json files', () => {
|
||||||
|
expect(() => {
|
||||||
|
BrowserWindow.addExtension(path.join(fixtures, 'devtools-extensions', 'bad-manifest'))
|
||||||
|
}).to.throw('Unexpected token }')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
ifdescribe(process.platform === 'darwin')('previewFile', () => {
|
||||||
|
afterEach(closeAllWindows)
|
||||||
|
it('opens the path in Quick Look on macOS', () => {
|
||||||
|
const w = new BrowserWindow({show: false})
|
||||||
|
expect(() => {
|
||||||
|
w.previewFile(__filename)
|
||||||
|
w.closeFilePreview()
|
||||||
|
}).to.not.throw()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('contextIsolation option with and without sandbox option', () => {
|
||||||
|
const expectedContextData = {
|
||||||
|
preloadContext: {
|
||||||
|
preloadProperty: 'number',
|
||||||
|
pageProperty: 'undefined',
|
||||||
|
typeofRequire: 'function',
|
||||||
|
typeofProcess: 'object',
|
||||||
|
typeofArrayPush: 'function',
|
||||||
|
typeofFunctionApply: 'function',
|
||||||
|
typeofPreloadExecuteJavaScriptProperty: 'undefined'
|
||||||
|
},
|
||||||
|
pageContext: {
|
||||||
|
preloadProperty: 'undefined',
|
||||||
|
pageProperty: 'string',
|
||||||
|
typeofRequire: 'undefined',
|
||||||
|
typeofProcess: 'undefined',
|
||||||
|
typeofArrayPush: 'number',
|
||||||
|
typeofFunctionApply: 'boolean',
|
||||||
|
typeofPreloadExecuteJavaScriptProperty: 'number',
|
||||||
|
typeofOpenedWindow: 'object'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(closeAllWindows)
|
||||||
|
|
||||||
|
it('separates the page context from the Electron/preload context', async () => {
|
||||||
|
const iw = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
contextIsolation: true,
|
||||||
|
preload: path.join(fixtures, 'api', 'isolated-preload.js')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const p = emittedOnce(ipcMain, 'isolated-world')
|
||||||
|
iw.loadFile(path.join(fixtures, 'api', 'isolated.html'))
|
||||||
|
const [, data] = await p
|
||||||
|
expect(data).to.deep.equal(expectedContextData)
|
||||||
|
})
|
||||||
|
it('recreates the contexts on reload', async () => {
|
||||||
|
const iw = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
contextIsolation: true,
|
||||||
|
preload: path.join(fixtures, 'api', 'isolated-preload.js')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await iw.loadFile(path.join(fixtures, 'api', 'isolated.html'))
|
||||||
|
const isolatedWorld = emittedOnce(ipcMain, 'isolated-world')
|
||||||
|
iw.webContents.reload()
|
||||||
|
const [, data] = await isolatedWorld
|
||||||
|
expect(data).to.deep.equal(expectedContextData)
|
||||||
|
})
|
||||||
|
it('enables context isolation on child windows', async () => {
|
||||||
|
const iw = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
contextIsolation: true,
|
||||||
|
preload: path.join(fixtures, 'api', 'isolated-preload.js')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const browserWindowCreated = emittedOnce(app, 'browser-window-created')
|
||||||
|
iw.loadFile(path.join(fixtures, 'pages', 'window-open.html'))
|
||||||
|
const [, window] = await browserWindowCreated
|
||||||
|
expect(window.webContents.getLastWebPreferences().contextIsolation).to.be.true('contextIsolation')
|
||||||
|
})
|
||||||
|
it('separates the page context from the Electron/preload context with sandbox on', async () => {
|
||||||
|
const ws = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
sandbox: true,
|
||||||
|
contextIsolation: true,
|
||||||
|
preload: path.join(fixtures, 'api', 'isolated-preload.js')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const p = emittedOnce(ipcMain, 'isolated-world')
|
||||||
|
ws.loadFile(path.join(fixtures, 'api', 'isolated.html'))
|
||||||
|
const [, data] = await p
|
||||||
|
expect(data).to.deep.equal(expectedContextData)
|
||||||
|
})
|
||||||
|
it('recreates the contexts on reload with sandbox on', async () => {
|
||||||
|
const ws = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
sandbox: true,
|
||||||
|
contextIsolation: true,
|
||||||
|
preload: path.join(fixtures, 'api', 'isolated-preload.js')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await ws.loadFile(path.join(fixtures, 'api', 'isolated.html'))
|
||||||
|
const isolatedWorld = emittedOnce(ipcMain, 'isolated-world')
|
||||||
|
ws.webContents.reload()
|
||||||
|
const [, data] = await isolatedWorld
|
||||||
|
expect(data).to.deep.equal(expectedContextData)
|
||||||
|
})
|
||||||
|
it('supports fetch api', async () => {
|
||||||
|
const fetchWindow = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
contextIsolation: true,
|
||||||
|
preload: path.join(fixtures, 'api', 'isolated-fetch-preload.js')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const p = emittedOnce(ipcMain, 'isolated-fetch-error')
|
||||||
|
fetchWindow.loadURL('about:blank')
|
||||||
|
const [, error] = await p
|
||||||
|
expect(error).to.equal('Failed to fetch')
|
||||||
|
})
|
||||||
|
it('doesn\'t break ipc serialization', async () => {
|
||||||
|
const iw = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
contextIsolation: true,
|
||||||
|
preload: path.join(fixtures, 'api', 'isolated-preload.js')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const p = emittedOnce(ipcMain, 'isolated-world')
|
||||||
|
iw.loadURL('about:blank')
|
||||||
|
iw.webContents.executeJavaScript(`
|
||||||
|
const opened = window.open()
|
||||||
|
openedLocation = opened.location.href
|
||||||
|
opened.close()
|
||||||
|
window.postMessage({openedLocation}, '*')
|
||||||
|
`)
|
||||||
|
const [, data] = await p
|
||||||
|
expect(data.pageContext.openedLocation).to.equal('')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const features = process.electronBinding('features')
|
||||||
|
ifdescribe(features.isOffscreenRenderingEnabled())('offscreen rendering', () => {
|
||||||
|
let w: BrowserWindow
|
||||||
|
beforeEach(function () {
|
||||||
|
w = new BrowserWindow({
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
backgroundThrottling: false,
|
||||||
|
offscreen: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
afterEach(closeAllWindows)
|
||||||
|
|
||||||
|
it('creates offscreen window with correct size', (done) => {
|
||||||
|
w.webContents.once('paint', function (event, rect, data) {
|
||||||
|
expect(data.constructor.name).to.equal('NativeImage')
|
||||||
|
expect(data.isEmpty()).to.be.false('data is empty')
|
||||||
|
const size = data.getSize()
|
||||||
|
const { scaleFactor } = screen.getPrimaryDisplay()
|
||||||
|
expect(size.width).to.be.closeTo(100 * scaleFactor, 2)
|
||||||
|
expect(size.height).to.be.closeTo(100 * scaleFactor, 2)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not crash after navigation', () => {
|
||||||
|
w.webContents.loadURL('about:blank')
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('window.webContents.isOffscreen()', () => {
|
||||||
|
it('is true for offscreen type', () => {
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
||||||
|
expect(w.webContents.isOffscreen()).to.be.true('isOffscreen')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('is false for regular window', () => {
|
||||||
|
const c = new BrowserWindow({ show: false })
|
||||||
|
expect(c.webContents.isOffscreen()).to.be.false('isOffscreen')
|
||||||
|
c.destroy()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('window.webContents.isPainting()', () => {
|
||||||
|
it('returns whether is currently painting', (done) => {
|
||||||
|
w.webContents.once('paint', function (event, rect, data) {
|
||||||
|
expect(w.webContents.isPainting()).to.be.true('isPainting')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('window.webContents.stopPainting()', () => {
|
||||||
|
it('stops painting', (done) => {
|
||||||
|
w.webContents.on('dom-ready', () => {
|
||||||
|
w.webContents.stopPainting()
|
||||||
|
expect(w.webContents.isPainting()).to.be.false('isPainting')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('window.webContents.startPainting()', () => {
|
||||||
|
it('starts painting', (done) => {
|
||||||
|
w.webContents.on('dom-ready', () => {
|
||||||
|
w.webContents.stopPainting()
|
||||||
|
w.webContents.startPainting()
|
||||||
|
w.webContents.once('paint', function (event, rect, data) {
|
||||||
|
expect(w.webContents.isPainting()).to.be.true('isPainting')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO(codebytere): remove in Electron v8.0.0
|
||||||
|
describe('window.webContents.getFrameRate()', () => {
|
||||||
|
it('has default frame rate', (done) => {
|
||||||
|
w.webContents.once('paint', function (event, rect, data) {
|
||||||
|
expect(w.webContents.getFrameRate()).to.equal(60)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO(codebytere): remove in Electron v8.0.0
|
||||||
|
describe('window.webContents.setFrameRate(frameRate)', () => {
|
||||||
|
it('sets custom frame rate', (done) => {
|
||||||
|
w.webContents.on('dom-ready', () => {
|
||||||
|
w.webContents.setFrameRate(30)
|
||||||
|
w.webContents.once('paint', function (event, rect, data) {
|
||||||
|
expect(w.webContents.getFrameRate()).to.equal(30)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('window.webContents.FrameRate', () => {
|
||||||
|
it('has default frame rate', (done) => {
|
||||||
|
w.webContents.once('paint', function (event, rect, data) {
|
||||||
|
expect(w.webContents.frameRate).to.equal(60)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets custom frame rate', (done) => {
|
||||||
|
w.webContents.on('dom-ready', () => {
|
||||||
|
w.webContents.frameRate = 30
|
||||||
|
w.webContents.once('paint', function (event, rect, data) {
|
||||||
|
expect(w.webContents.frameRate).to.equal(30)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
|
import { AddressInfo } from 'net'
|
||||||
import * as chaiAsPromised from 'chai-as-promised'
|
import * as chaiAsPromised from 'chai-as-promised'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
import * as http from 'http'
|
||||||
import { BrowserWindow, webContents } from 'electron'
|
import { BrowserWindow, webContents } from 'electron'
|
||||||
import { emittedOnce } from './events-helpers';
|
import { emittedOnce } from './events-helpers';
|
||||||
import { closeWindow } from './window-helpers';
|
import { closeAllWindows } from './window-helpers';
|
||||||
|
|
||||||
const { expect } = chai
|
const { expect } = chai
|
||||||
|
|
||||||
|
@ -12,28 +14,13 @@ chai.use(chaiAsPromised)
|
||||||
const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures')
|
const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures')
|
||||||
|
|
||||||
describe('webContents module', () => {
|
describe('webContents module', () => {
|
||||||
let w: BrowserWindow = (null as unknown as BrowserWindow)
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
w = new BrowserWindow({
|
|
||||||
show: false,
|
|
||||||
width: 400,
|
|
||||||
height: 400,
|
|
||||||
webPreferences: {
|
|
||||||
backgroundThrottling: false,
|
|
||||||
nodeIntegration: true,
|
|
||||||
webviewTag: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await closeWindow(w)
|
|
||||||
w = (null as unknown as BrowserWindow)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('getAllWebContents() API', () => {
|
describe('getAllWebContents() API', () => {
|
||||||
|
afterEach(closeAllWindows)
|
||||||
it('returns an array of web contents', async () => {
|
it('returns an array of web contents', async () => {
|
||||||
|
const w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: { webviewTag: true }
|
||||||
|
})
|
||||||
w.loadFile(path.join(fixturesPath, 'pages', 'webview-zoom-factor.html'))
|
w.loadFile(path.join(fixturesPath, 'pages', 'webview-zoom-factor.html'))
|
||||||
|
|
||||||
await emittedOnce(w.webContents, 'did-attach-webview')
|
await emittedOnce(w.webContents, 'did-attach-webview')
|
||||||
|
@ -54,7 +41,9 @@ describe('webContents module', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('will-prevent-unload event', () => {
|
describe('will-prevent-unload event', () => {
|
||||||
|
afterEach(closeAllWindows)
|
||||||
it('does not emit if beforeunload returns undefined', (done) => {
|
it('does not emit if beforeunload returns undefined', (done) => {
|
||||||
|
const w = new BrowserWindow({show: false})
|
||||||
w.once('closed', () => done())
|
w.once('closed', () => done())
|
||||||
w.webContents.once('will-prevent-unload', (e) => {
|
w.webContents.once('will-prevent-unload', (e) => {
|
||||||
expect.fail('should not have fired')
|
expect.fail('should not have fired')
|
||||||
|
@ -63,14 +52,131 @@ describe('webContents module', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('emits if beforeunload returns false', (done) => {
|
it('emits if beforeunload returns false', (done) => {
|
||||||
|
const w = new BrowserWindow({show: false})
|
||||||
w.webContents.once('will-prevent-unload', () => done())
|
w.webContents.once('will-prevent-unload', () => done())
|
||||||
w.loadFile(path.join(fixturesPath, 'api', 'close-beforeunload-false.html'))
|
w.loadFile(path.join(fixturesPath, 'api', 'close-beforeunload-false.html'))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('supports calling preventDefault on will-prevent-unload events', (done) => {
|
it('supports calling preventDefault on will-prevent-unload events', (done) => {
|
||||||
|
const w = new BrowserWindow({show: false})
|
||||||
w.webContents.once('will-prevent-unload', event => event.preventDefault())
|
w.webContents.once('will-prevent-unload', event => event.preventDefault())
|
||||||
w.once('closed', () => done())
|
w.once('closed', () => done())
|
||||||
w.loadFile(path.join(fixturesPath, 'api', 'close-beforeunload-false.html'))
|
w.loadFile(path.join(fixturesPath, 'api', 'close-beforeunload-false.html'))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('webContents.send(channel, args...)', () => {
|
||||||
|
afterEach(closeAllWindows)
|
||||||
|
it('throws an error when the channel is missing', () => {
|
||||||
|
const w = new BrowserWindow({show: false})
|
||||||
|
expect(() => {
|
||||||
|
(w.webContents.send as any)()
|
||||||
|
}).to.throw('Missing required channel argument')
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
w.webContents.send(null as any)
|
||||||
|
}).to.throw('Missing required channel argument')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('webContents.executeJavaScript', () => {
|
||||||
|
describe('in about:blank', () => {
|
||||||
|
const expected = 'hello, world!'
|
||||||
|
const expectedErrorMsg = 'woops!'
|
||||||
|
const code = `(() => "${expected}")()`
|
||||||
|
const asyncCode = `(() => new Promise(r => setTimeout(() => r("${expected}"), 500)))()`
|
||||||
|
const badAsyncCode = `(() => new Promise((r, e) => setTimeout(() => e("${expectedErrorMsg}"), 500)))()`
|
||||||
|
const errorTypes = new Set([
|
||||||
|
Error,
|
||||||
|
ReferenceError,
|
||||||
|
EvalError,
|
||||||
|
RangeError,
|
||||||
|
SyntaxError,
|
||||||
|
TypeError,
|
||||||
|
URIError
|
||||||
|
])
|
||||||
|
let w: BrowserWindow
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
w = new BrowserWindow({show: false})
|
||||||
|
await w.loadURL('about:blank')
|
||||||
|
})
|
||||||
|
after(closeAllWindows)
|
||||||
|
|
||||||
|
it('resolves the returned promise with the result', async () => {
|
||||||
|
const result = await w.webContents.executeJavaScript(code)
|
||||||
|
expect(result).to.equal(expected)
|
||||||
|
})
|
||||||
|
it('resolves the returned promise with the result if the code returns an asyncronous promise', async () => {
|
||||||
|
const result = await w.webContents.executeJavaScript(asyncCode)
|
||||||
|
expect(result).to.equal(expected)
|
||||||
|
})
|
||||||
|
it('rejects the returned promise if an async error is thrown', async () => {
|
||||||
|
await expect(w.webContents.executeJavaScript(badAsyncCode)).to.eventually.be.rejectedWith(expectedErrorMsg)
|
||||||
|
})
|
||||||
|
it('rejects the returned promise with an error if an Error.prototype is thrown', async () => {
|
||||||
|
for (const error of errorTypes) {
|
||||||
|
await expect(w.webContents.executeJavaScript(`Promise.reject(new ${error.name}("Wamp-wamp"))`))
|
||||||
|
.to.eventually.be.rejectedWith(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("on a real page", () => {
|
||||||
|
let w: BrowserWindow
|
||||||
|
beforeEach(() => {
|
||||||
|
w = new BrowserWindow({show: false})
|
||||||
|
})
|
||||||
|
afterEach(closeAllWindows)
|
||||||
|
|
||||||
|
let server: http.Server = null as unknown as http.Server
|
||||||
|
let serverUrl: string = null as unknown as string
|
||||||
|
|
||||||
|
before((done) => {
|
||||||
|
server = http.createServer((request, response) => {
|
||||||
|
response.end()
|
||||||
|
}).listen(0, '127.0.0.1', () => {
|
||||||
|
serverUrl = 'http://127.0.0.1:' + (server.address() as AddressInfo).port
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
server.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('works after page load and during subframe load', (done) => {
|
||||||
|
w.webContents.once('did-finish-load', () => {
|
||||||
|
// initiate a sub-frame load, then try and execute script during it
|
||||||
|
w.webContents.executeJavaScript(`
|
||||||
|
var iframe = document.createElement('iframe')
|
||||||
|
iframe.src = '${serverUrl}/slow'
|
||||||
|
document.body.appendChild(iframe)
|
||||||
|
`).then(() => {
|
||||||
|
w.webContents.executeJavaScript('console.log(\'hello\')').then(() => {
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
w.loadURL(serverUrl)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('executes after page load', (done) => {
|
||||||
|
w.webContents.executeJavaScript(`(() => "test")()`).then(result => {
|
||||||
|
expect(result).to.equal("test")
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL(serverUrl)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('works with result objects that have DOM class prototypes', (done) => {
|
||||||
|
w.webContents.executeJavaScript('document.location').then(result => {
|
||||||
|
expect(result.origin).to.equal(serverUrl)
|
||||||
|
expect(result.protocol).to.equal('http:')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL(serverUrl)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,704 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const chai = require('chai')
|
|
||||||
const dirtyChai = require('dirty-chai')
|
|
||||||
const fs = require('fs')
|
|
||||||
const path = require('path')
|
|
||||||
const os = require('os')
|
|
||||||
const qs = require('querystring')
|
|
||||||
const http = require('http')
|
|
||||||
const { closeWindow } = require('./window-helpers')
|
|
||||||
const { emittedOnce } = require('./events-helpers')
|
|
||||||
const { ipcRenderer, remote } = require('electron')
|
|
||||||
const { app, ipcMain, BrowserWindow, BrowserView, protocol, session, screen, webContents } = remote
|
|
||||||
|
|
||||||
const features = process.electronBinding('features')
|
|
||||||
const { expect } = chai
|
|
||||||
const isCI = remote.getGlobal('isCi')
|
|
||||||
const nativeModulesEnabled = remote.getGlobal('nativeModulesEnabled')
|
|
||||||
|
|
||||||
chai.use(dirtyChai)
|
|
||||||
|
|
||||||
describe('BrowserWindow module', () => {
|
|
||||||
const fixtures = path.resolve(__dirname, 'fixtures')
|
|
||||||
let w = null
|
|
||||||
let iw = null
|
|
||||||
let ws = null
|
|
||||||
let server
|
|
||||||
let postData
|
|
||||||
|
|
||||||
const defaultOptions = {
|
|
||||||
show: false,
|
|
||||||
width: 400,
|
|
||||||
height: 400,
|
|
||||||
webPreferences: {
|
|
||||||
backgroundThrottling: false,
|
|
||||||
nodeIntegration: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const openTheWindow = async (options = defaultOptions) => {
|
|
||||||
// The `afterEach` hook isn't called if a test fails,
|
|
||||||
// we should make sure that the window is closed ourselves.
|
|
||||||
await closeTheWindow()
|
|
||||||
|
|
||||||
w = new BrowserWindow(options)
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeTheWindow = function () {
|
|
||||||
return closeWindow(w).then(() => { w = null })
|
|
||||||
}
|
|
||||||
|
|
||||||
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 if (req.url === '/navigate-302') {
|
|
||||||
res.end(`<html><body><script>window.location='${server.url}/302'</script></body></html>`)
|
|
||||||
} else if (req.url === '/cross-site') {
|
|
||||||
res.end(`<html><body><h1>${req.url}</h1></body></html>`)
|
|
||||||
} else {
|
|
||||||
res.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setTimeout(respond, req.url.includes('slow') ? 200 : 0)
|
|
||||||
})
|
|
||||||
server.listen(0, '127.0.0.1', () => {
|
|
||||||
server.url = `http://127.0.0.1:${server.address().port}`
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
server.close()
|
|
||||||
server = null
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(openTheWindow)
|
|
||||||
|
|
||||||
afterEach(closeTheWindow)
|
|
||||||
|
|
||||||
describe('window.webContents.send(channel, args...)', () => {
|
|
||||||
it('throws an error when the channel is missing', () => {
|
|
||||||
expect(() => {
|
|
||||||
w.webContents.send()
|
|
||||||
}).to.throw('Missing required channel argument')
|
|
||||||
|
|
||||||
expect(() => {
|
|
||||||
w.webContents.send(null)
|
|
||||||
}).to.throw('Missing required channel argument')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('window.getNativeWindowHandle()', () => {
|
|
||||||
before(function () {
|
|
||||||
if (!nativeModulesEnabled) {
|
|
||||||
this.skip()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('returns valid handle', () => {
|
|
||||||
// The module's source code is hosted at
|
|
||||||
// https://github.com/electron/node-is-valid-window
|
|
||||||
const isValidWindow = remote.require('is-valid-window')
|
|
||||||
expect(isValidWindow(w.getNativeWindowHandle())).to.be.true()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('extensions and dev tools extensions', () => {
|
|
||||||
let showPanelTimeoutId
|
|
||||||
|
|
||||||
const showLastDevToolsPanel = () => {
|
|
||||||
w.webContents.once('devtools-opened', () => {
|
|
||||||
const show = () => {
|
|
||||||
if (w == null || w.isDestroyed()) return
|
|
||||||
const { devToolsWebContents } = w
|
|
||||||
if (devToolsWebContents == null || devToolsWebContents.isDestroyed()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const showLastPanel = () => {
|
|
||||||
const lastPanelId = UI.inspectorView._tabbedPane._tabs.peekLast().id
|
|
||||||
UI.inspectorView.showPanel(lastPanelId)
|
|
||||||
}
|
|
||||||
devToolsWebContents.executeJavaScript(`(${showLastPanel})()`, false).then(() => {
|
|
||||||
showPanelTimeoutId = setTimeout(show, 100)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
showPanelTimeoutId = setTimeout(show, 100)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
clearTimeout(showPanelTimeoutId)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('BrowserWindow.addDevToolsExtension', () => {
|
|
||||||
describe('for invalid extensions', () => {
|
|
||||||
it('throws errors for missing manifest.json files', () => {
|
|
||||||
const nonexistentExtensionPath = path.join(__dirname, 'does-not-exist')
|
|
||||||
expect(() => {
|
|
||||||
BrowserWindow.addDevToolsExtension(nonexistentExtensionPath)
|
|
||||||
}).to.throw(/ENOENT: no such file or directory/)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('throws errors for invalid manifest.json files', () => {
|
|
||||||
const badManifestExtensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', 'bad-manifest')
|
|
||||||
expect(() => {
|
|
||||||
BrowserWindow.addDevToolsExtension(badManifestExtensionPath)
|
|
||||||
}).to.throw(/Unexpected token }/)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('for a valid extension', () => {
|
|
||||||
const extensionName = 'foo'
|
|
||||||
|
|
||||||
const removeExtension = () => {
|
|
||||||
BrowserWindow.removeDevToolsExtension('foo')
|
|
||||||
expect(BrowserWindow.getDevToolsExtensions()).to.not.have.a.property(extensionName)
|
|
||||||
}
|
|
||||||
|
|
||||||
const addExtension = () => {
|
|
||||||
const extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', 'foo')
|
|
||||||
BrowserWindow.addDevToolsExtension(extensionPath)
|
|
||||||
expect(BrowserWindow.getDevToolsExtensions()).to.have.a.property(extensionName)
|
|
||||||
|
|
||||||
showLastDevToolsPanel()
|
|
||||||
|
|
||||||
w.loadURL('about:blank')
|
|
||||||
}
|
|
||||||
|
|
||||||
// After* hooks won't be called if a test fail.
|
|
||||||
// So let's make a clean-up in the before hook.
|
|
||||||
beforeEach(removeExtension)
|
|
||||||
|
|
||||||
describe('when the devtools is docked', () => {
|
|
||||||
beforeEach(function (done) {
|
|
||||||
addExtension()
|
|
||||||
w.webContents.openDevTools({ mode: 'bottom' })
|
|
||||||
ipcMain.once('answer', (event, message) => {
|
|
||||||
this.message = message
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('created extension info', function () {
|
|
||||||
it('has proper "runtimeId"', function () {
|
|
||||||
expect(this.message).to.have.own.property('runtimeId')
|
|
||||||
expect(this.message.runtimeId).to.equal(extensionName)
|
|
||||||
})
|
|
||||||
it('has "tabId" matching webContents id', function () {
|
|
||||||
expect(this.message).to.have.own.property('tabId')
|
|
||||||
expect(this.message.tabId).to.equal(w.webContents.id)
|
|
||||||
})
|
|
||||||
it('has "i18nString" with proper contents', function () {
|
|
||||||
expect(this.message).to.have.own.property('i18nString')
|
|
||||||
expect(this.message.i18nString).to.equal('foo - bar (baz)')
|
|
||||||
})
|
|
||||||
it('has "storageItems" with proper contents', function () {
|
|
||||||
expect(this.message).to.have.own.property('storageItems')
|
|
||||||
expect(this.message.storageItems).to.deep.equal({
|
|
||||||
local: {
|
|
||||||
set: { hello: 'world', world: 'hello' },
|
|
||||||
remove: { world: 'hello' },
|
|
||||||
clear: {}
|
|
||||||
},
|
|
||||||
sync: {
|
|
||||||
set: { foo: 'bar', bar: 'foo' },
|
|
||||||
remove: { foo: 'bar' },
|
|
||||||
clear: {}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('when the devtools is undocked', () => {
|
|
||||||
beforeEach(function (done) {
|
|
||||||
addExtension()
|
|
||||||
w.webContents.openDevTools({ mode: 'undocked' })
|
|
||||||
ipcMain.once('answer', (event, message, extensionId) => {
|
|
||||||
this.message = message
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('created extension info', function () {
|
|
||||||
it('has proper "runtimeId"', function () {
|
|
||||||
expect(this.message).to.have.own.property('runtimeId')
|
|
||||||
expect(this.message.runtimeId).to.equal(extensionName)
|
|
||||||
})
|
|
||||||
it('has "tabId" matching webContents id', function () {
|
|
||||||
expect(this.message).to.have.own.property('tabId')
|
|
||||||
expect(this.message.tabId).to.equal(w.webContents.id)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('works when used with partitions', (done) => {
|
|
||||||
if (w != null) {
|
|
||||||
w.destroy()
|
|
||||||
}
|
|
||||||
w = new BrowserWindow({
|
|
||||||
show: false,
|
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: true,
|
|
||||||
partition: 'temp'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', 'foo')
|
|
||||||
BrowserWindow.removeDevToolsExtension('foo')
|
|
||||||
BrowserWindow.addDevToolsExtension(extensionPath)
|
|
||||||
|
|
||||||
showLastDevToolsPanel()
|
|
||||||
|
|
||||||
ipcMain.once('answer', function (event, message) {
|
|
||||||
expect(message.runtimeId).to.equal('foo')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
|
|
||||||
w.loadURL('about:blank')
|
|
||||||
w.webContents.openDevTools({ mode: 'bottom' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('serializes the registered extensions on quit', () => {
|
|
||||||
const extensionName = 'foo'
|
|
||||||
const extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', extensionName)
|
|
||||||
const serializedPath = path.join(app.getPath('userData'), 'DevTools Extensions')
|
|
||||||
|
|
||||||
BrowserWindow.addDevToolsExtension(extensionPath)
|
|
||||||
app.emit('will-quit')
|
|
||||||
expect(JSON.parse(fs.readFileSync(serializedPath))).to.deep.equal([extensionPath])
|
|
||||||
|
|
||||||
BrowserWindow.removeDevToolsExtension(extensionName)
|
|
||||||
app.emit('will-quit')
|
|
||||||
expect(fs.existsSync(serializedPath)).to.be.false()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('BrowserWindow.addExtension', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
BrowserWindow.removeExtension('foo')
|
|
||||||
expect(BrowserWindow.getExtensions()).to.not.have.property('foo')
|
|
||||||
|
|
||||||
const extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', 'foo')
|
|
||||||
BrowserWindow.addExtension(extensionPath)
|
|
||||||
expect(BrowserWindow.getExtensions()).to.have.property('foo')
|
|
||||||
|
|
||||||
showLastDevToolsPanel()
|
|
||||||
|
|
||||||
w.loadURL('about:blank')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('throws errors for missing manifest.json files', () => {
|
|
||||||
expect(() => {
|
|
||||||
BrowserWindow.addExtension(path.join(__dirname, 'does-not-exist'))
|
|
||||||
}).to.throw('ENOENT: no such file or directory')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('throws errors for invalid manifest.json files', () => {
|
|
||||||
expect(() => {
|
|
||||||
BrowserWindow.addExtension(path.join(__dirname, 'fixtures', 'devtools-extensions', 'bad-manifest'))
|
|
||||||
}).to.throw('Unexpected token }')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('window.webContents.executeJavaScript', () => {
|
|
||||||
const expected = 'hello, world!'
|
|
||||||
const expectedErrorMsg = 'woops!'
|
|
||||||
const code = `(() => "${expected}")()`
|
|
||||||
const asyncCode = `(() => new Promise(r => setTimeout(() => r("${expected}"), 500)))()`
|
|
||||||
const badAsyncCode = `(() => new Promise((r, e) => setTimeout(() => e("${expectedErrorMsg}"), 500)))()`
|
|
||||||
const errorTypes = new Set([
|
|
||||||
Error,
|
|
||||||
ReferenceError,
|
|
||||||
EvalError,
|
|
||||||
RangeError,
|
|
||||||
SyntaxError,
|
|
||||||
TypeError,
|
|
||||||
URIError
|
|
||||||
])
|
|
||||||
|
|
||||||
it('resolves the returned promise with the result', (done) => {
|
|
||||||
ipcRenderer.send('executeJavaScript', code)
|
|
||||||
ipcRenderer.once('executeJavaScript-promise-response', (event, result) => {
|
|
||||||
expect(result).to.equal(expected)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
it('resolves the returned promise with the result if the code returns an asyncronous promise', (done) => {
|
|
||||||
ipcRenderer.send('executeJavaScript', asyncCode)
|
|
||||||
ipcRenderer.once('executeJavaScript-promise-response', (event, result) => {
|
|
||||||
expect(result).to.equal(expected)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
it('rejects the returned promise if an async error is thrown', (done) => {
|
|
||||||
ipcRenderer.send('executeJavaScript', badAsyncCode)
|
|
||||||
ipcRenderer.once('executeJavaScript-promise-error', (event, error) => {
|
|
||||||
expect(error).to.equal(expectedErrorMsg)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
it('rejects the returned promise with an error if an Error.prototype is thrown', async () => {
|
|
||||||
for (const error in errorTypes) {
|
|
||||||
await new Promise((resolve) => {
|
|
||||||
ipcRenderer.send('executeJavaScript', `Promise.reject(new ${error.name}("Wamp-wamp")`)
|
|
||||||
ipcRenderer.once('executeJavaScript-promise-error-name', (event, name) => {
|
|
||||||
expect(name).to.equal(error.name)
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('works after page load and during subframe load', (done) => {
|
|
||||||
w.webContents.once('did-finish-load', () => {
|
|
||||||
// initiate a sub-frame load, then try and execute script during it
|
|
||||||
w.webContents.executeJavaScript(`
|
|
||||||
var iframe = document.createElement('iframe')
|
|
||||||
iframe.src = '${server.url}/slow'
|
|
||||||
document.body.appendChild(iframe)
|
|
||||||
`).then(() => {
|
|
||||||
w.webContents.executeJavaScript('console.log(\'hello\')').then(() => {
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
w.loadURL(server.url)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('executes after page load', (done) => {
|
|
||||||
w.webContents.executeJavaScript(code).then(result => {
|
|
||||||
expect(result).to.equal(expected)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadURL(server.url)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('works with result objects that have DOM class prototypes', (done) => {
|
|
||||||
w.webContents.executeJavaScript('document.location').then(result => {
|
|
||||||
expect(result.origin).to.equal(server.url)
|
|
||||||
expect(result.protocol).to.equal('http:')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadURL(server.url)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('previewFile', () => {
|
|
||||||
before(function () {
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
this.skip()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('opens the path in Quick Look on macOS', () => {
|
|
||||||
expect(() => {
|
|
||||||
w.previewFile(__filename)
|
|
||||||
w.closeFilePreview()
|
|
||||||
}).to.not.throw()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('contextIsolation option with and without sandbox option', () => {
|
|
||||||
const expectedContextData = {
|
|
||||||
preloadContext: {
|
|
||||||
preloadProperty: 'number',
|
|
||||||
pageProperty: 'undefined',
|
|
||||||
typeofRequire: 'function',
|
|
||||||
typeofProcess: 'object',
|
|
||||||
typeofArrayPush: 'function',
|
|
||||||
typeofFunctionApply: 'function',
|
|
||||||
typeofPreloadExecuteJavaScriptProperty: 'undefined'
|
|
||||||
},
|
|
||||||
pageContext: {
|
|
||||||
preloadProperty: 'undefined',
|
|
||||||
pageProperty: 'string',
|
|
||||||
typeofRequire: 'undefined',
|
|
||||||
typeofProcess: 'undefined',
|
|
||||||
typeofArrayPush: 'number',
|
|
||||||
typeofFunctionApply: 'boolean',
|
|
||||||
typeofPreloadExecuteJavaScriptProperty: 'number',
|
|
||||||
typeofOpenedWindow: 'object'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
if (iw != null) iw.destroy()
|
|
||||||
iw = new BrowserWindow({
|
|
||||||
show: false,
|
|
||||||
webPreferences: {
|
|
||||||
contextIsolation: true,
|
|
||||||
preload: path.join(fixtures, 'api', 'isolated-preload.js')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (ws != null) ws.destroy()
|
|
||||||
ws = new BrowserWindow({
|
|
||||||
show: false,
|
|
||||||
webPreferences: {
|
|
||||||
sandbox: true,
|
|
||||||
contextIsolation: true,
|
|
||||||
preload: path.join(fixtures, 'api', 'isolated-preload.js')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
if (iw != null) iw.destroy()
|
|
||||||
if (ws != null) ws.destroy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('separates the page context from the Electron/preload context', async () => {
|
|
||||||
const p = emittedOnce(ipcMain, 'isolated-world')
|
|
||||||
iw.loadFile(path.join(fixtures, 'api', 'isolated.html'))
|
|
||||||
const [, data] = await p
|
|
||||||
expect(data).to.deep.equal(expectedContextData)
|
|
||||||
})
|
|
||||||
it('recreates the contexts on reload', async () => {
|
|
||||||
await iw.loadFile(path.join(fixtures, 'api', 'isolated.html'))
|
|
||||||
const isolatedWorld = emittedOnce(ipcMain, 'isolated-world')
|
|
||||||
iw.webContents.reload()
|
|
||||||
const [, data] = await isolatedWorld
|
|
||||||
expect(data).to.deep.equal(expectedContextData)
|
|
||||||
})
|
|
||||||
it('enables context isolation on child windows', async () => {
|
|
||||||
const browserWindowCreated = emittedOnce(app, 'browser-window-created')
|
|
||||||
iw.loadFile(path.join(fixtures, 'pages', 'window-open.html'))
|
|
||||||
const [, window] = await browserWindowCreated
|
|
||||||
expect(window.webContents.getLastWebPreferences().contextIsolation).to.be.true()
|
|
||||||
})
|
|
||||||
it('separates the page context from the Electron/preload context with sandbox on', async () => {
|
|
||||||
const p = emittedOnce(ipcMain, 'isolated-world')
|
|
||||||
ws.loadFile(path.join(fixtures, 'api', 'isolated.html'))
|
|
||||||
const [, data] = await p
|
|
||||||
expect(data).to.deep.equal(expectedContextData)
|
|
||||||
})
|
|
||||||
it('recreates the contexts on reload with sandbox on', async () => {
|
|
||||||
await ws.loadFile(path.join(fixtures, 'api', 'isolated.html'))
|
|
||||||
const isolatedWorld = emittedOnce(ipcMain, 'isolated-world')
|
|
||||||
ws.webContents.reload()
|
|
||||||
const [, data] = await isolatedWorld
|
|
||||||
expect(data).to.deep.equal(expectedContextData)
|
|
||||||
})
|
|
||||||
it('supports fetch api', async () => {
|
|
||||||
const fetchWindow = new BrowserWindow({
|
|
||||||
show: false,
|
|
||||||
webPreferences: {
|
|
||||||
contextIsolation: true,
|
|
||||||
preload: path.join(fixtures, 'api', 'isolated-fetch-preload.js')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const p = emittedOnce(ipcMain, 'isolated-fetch-error')
|
|
||||||
fetchWindow.loadURL('about:blank')
|
|
||||||
const [, error] = await p
|
|
||||||
fetchWindow.destroy()
|
|
||||||
expect(error).to.equal('Failed to fetch')
|
|
||||||
})
|
|
||||||
it('doesn\'t break ipc serialization', async () => {
|
|
||||||
const p = emittedOnce(ipcMain, 'isolated-world')
|
|
||||||
iw.loadURL('about:blank')
|
|
||||||
iw.webContents.executeJavaScript(`
|
|
||||||
const opened = window.open()
|
|
||||||
openedLocation = opened.location.href
|
|
||||||
opened.close()
|
|
||||||
window.postMessage({openedLocation}, '*')
|
|
||||||
`)
|
|
||||||
const [, data] = await p
|
|
||||||
expect(data.pageContext.openedLocation).to.equal('')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('offscreen rendering', () => {
|
|
||||||
beforeEach(function () {
|
|
||||||
if (!features.isOffscreenRenderingEnabled()) {
|
|
||||||
// XXX(alexeykuzmin): "afterEach" hook is not called
|
|
||||||
// for skipped tests, we have to close the window manually.
|
|
||||||
return closeTheWindow().then(() => { this.skip() })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w != null) w.destroy()
|
|
||||||
w = new BrowserWindow({
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
show: false,
|
|
||||||
webPreferences: {
|
|
||||||
backgroundThrottling: false,
|
|
||||||
offscreen: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('creates offscreen window with correct size', (done) => {
|
|
||||||
w.webContents.once('paint', function (event, rect, data) {
|
|
||||||
expect(data.constructor.name).to.equal('NativeImage')
|
|
||||||
expect(data.isEmpty()).to.be.false()
|
|
||||||
const size = data.getSize()
|
|
||||||
expect(size.width).to.be.closeTo(100 * devicePixelRatio, 2)
|
|
||||||
expect(size.height).to.be.closeTo(100 * devicePixelRatio, 2)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('does not crash after navigation', () => {
|
|
||||||
w.webContents.loadURL('about:blank')
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('window.webContents.isOffscreen()', () => {
|
|
||||||
it('is true for offscreen type', () => {
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
|
||||||
expect(w.webContents.isOffscreen()).to.be.true()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('is false for regular window', () => {
|
|
||||||
const c = new BrowserWindow({ show: false })
|
|
||||||
expect(c.webContents.isOffscreen()).to.be.false()
|
|
||||||
c.destroy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('window.webContents.isPainting()', () => {
|
|
||||||
it('returns whether is currently painting', (done) => {
|
|
||||||
w.webContents.once('paint', function (event, rect, data) {
|
|
||||||
expect(w.webContents.isPainting()).to.be.true()
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('window.webContents.stopPainting()', () => {
|
|
||||||
it('stops painting', (done) => {
|
|
||||||
w.webContents.on('dom-ready', () => {
|
|
||||||
w.webContents.stopPainting()
|
|
||||||
expect(w.webContents.isPainting()).to.be.false()
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('window.webContents.startPainting()', () => {
|
|
||||||
it('starts painting', (done) => {
|
|
||||||
w.webContents.on('dom-ready', () => {
|
|
||||||
w.webContents.stopPainting()
|
|
||||||
w.webContents.startPainting()
|
|
||||||
w.webContents.once('paint', function (event, rect, data) {
|
|
||||||
expect(w.webContents.isPainting()).to.be.true()
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// TODO(codebytere): remove in Electron v8.0.0
|
|
||||||
describe('window.webContents.getFrameRate()', () => {
|
|
||||||
it('has default frame rate', (done) => {
|
|
||||||
w.webContents.once('paint', function (event, rect, data) {
|
|
||||||
expect(w.webContents.getFrameRate()).to.equal(60)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// TODO(codebytere): remove in Electron v8.0.0
|
|
||||||
describe('window.webContents.setFrameRate(frameRate)', () => {
|
|
||||||
it('sets custom frame rate', (done) => {
|
|
||||||
w.webContents.on('dom-ready', () => {
|
|
||||||
w.webContents.setFrameRate(30)
|
|
||||||
w.webContents.once('paint', function (event, rect, data) {
|
|
||||||
expect(w.webContents.getFrameRate()).to.equal(30)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('window.webContents.FrameRate', () => {
|
|
||||||
it('has default frame rate', (done) => {
|
|
||||||
w.webContents.once('paint', function (event, rect, data) {
|
|
||||||
expect(w.webContents.frameRate).to.equal(60)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('sets custom frame rate', (done) => {
|
|
||||||
w.webContents.on('dom-ready', () => {
|
|
||||||
w.webContents.frameRate = 30
|
|
||||||
w.webContents.once('paint', function (event, rect, data) {
|
|
||||||
expect(w.webContents.frameRate).to.equal(30)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const expectBoundsEqual = (actual, expected) => {
|
|
||||||
if (!isScaleFactorRounding()) {
|
|
||||||
expect(expected).to.deep.equal(actual)
|
|
||||||
} else if (Array.isArray(actual)) {
|
|
||||||
expect(actual[0]).to.be.closeTo(expected[0], 1)
|
|
||||||
expect(actual[1]).to.be.closeTo(expected[1], 1)
|
|
||||||
} else {
|
|
||||||
expect(actual.x).to.be.closeTo(expected.x, 1)
|
|
||||||
expect(actual.y).to.be.closeTo(expected.y, 1)
|
|
||||||
expect(actual.width).to.be.closeTo(expected.width, 1)
|
|
||||||
expect(actual.height).to.be.closeTo(expected.height, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is the display's scale factor possibly causing rounding of pixel coordinate
|
|
||||||
// values?
|
|
||||||
const isScaleFactorRounding = () => {
|
|
||||||
const { scaleFactor } = screen.getPrimaryDisplay()
|
|
||||||
// Return true if scale factor is non-integer value
|
|
||||||
if (Math.round(scaleFactor) !== scaleFactor) return true
|
|
||||||
// Return true if scale factor is odd number above 2
|
|
||||||
return scaleFactor > 2 && scaleFactor % 2 === 1
|
|
||||||
}
|
|
|
@ -159,18 +159,6 @@ app.on('ready', function () {
|
||||||
})
|
})
|
||||||
event.returnValue = null
|
event.returnValue = null
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('executeJavaScript', function (event, code) {
|
|
||||||
window.webContents.executeJavaScript(code).then((result) => {
|
|
||||||
window.webContents.send('executeJavaScript-promise-response', result)
|
|
||||||
}).catch((error) => {
|
|
||||||
window.webContents.send('executeJavaScript-promise-error', error)
|
|
||||||
|
|
||||||
if (error && error.name) {
|
|
||||||
window.webContents.send('executeJavaScript-promise-error-name', error.name)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('handle-next-ipc-message-sync', function (event, returnValue) {
|
ipcMain.on('handle-next-ipc-message-sync', function (event, returnValue) {
|
||||||
|
@ -224,18 +212,10 @@ ipcMain.on('create-window-with-options-cycle', (event) => {
|
||||||
event.returnValue = window.id
|
event.returnValue = window.id
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('prevent-next-new-window', (event, id) => {
|
|
||||||
webContents.fromId(id).once('new-window', event => event.preventDefault())
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('prevent-next-will-attach-webview', (event) => {
|
ipcMain.on('prevent-next-will-attach-webview', (event) => {
|
||||||
event.sender.once('will-attach-webview', event => event.preventDefault())
|
event.sender.once('will-attach-webview', event => event.preventDefault())
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('prevent-next-will-prevent-unload', (event, id) => {
|
|
||||||
webContents.fromId(id).once('will-prevent-unload', event => event.preventDefault())
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('disable-node-on-next-will-attach-webview', (event, id) => {
|
ipcMain.on('disable-node-on-next-will-attach-webview', (event, id) => {
|
||||||
event.sender.once('will-attach-webview', (event, webPreferences, params) => {
|
event.sender.once('will-attach-webview', (event, webPreferences, params) => {
|
||||||
params.src = `file://${path.join(__dirname, '..', 'fixtures', 'pages', 'c.html')}`
|
params.src = `file://${path.join(__dirname, '..', 'fixtures', 'pages', 'c.html')}`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue