electron/spec/chromium-spec.js

1192 lines
37 KiB
JavaScript
Raw Normal View History

2016-03-25 20:03:49 +00:00
const assert = require('assert')
const fs = require('fs')
2016-03-25 20:03:49 +00:00
const http = require('http')
const path = require('path')
const ws = require('ws')
const url = require('url')
2018-02-08 18:50:19 +00:00
const ChildProcess = require('child_process')
const {ipcRenderer, remote} = require('electron')
2016-12-03 18:52:57 +00:00
const {closeWindow} = require('./window-helpers')
2018-02-08 18:50:19 +00:00
const {app, BrowserWindow, ipcMain, protocol, session, webContents} = remote
2016-03-25 20:03:49 +00:00
const isCI = remote.getGlobal('isCi')
const features = process.atomBinding('features')
2017-11-23 22:22:43 +00:00
/* Most of the APIs here don't use standard callbacks */
/* eslint-disable standard/no-callback-literal */
2017-11-13 20:13:19 +00:00
describe('chromium feature', () => {
const fixtures = path.resolve(__dirname, 'fixtures')
let listener = null
2017-04-18 23:04:27 +00:00
let w = null
2017-11-13 20:13:19 +00:00
afterEach(() => {
2016-01-12 02:40:23 +00:00
if (listener != null) {
2016-03-25 20:03:49 +00:00
window.removeEventListener('message', listener)
2016-01-12 02:40:23 +00:00
}
2016-03-25 20:03:49 +00:00
listener = null
})
2018-02-08 18:50:44 +00:00
describe('command line switches', () => {
2018-02-08 18:00:41 +00:00
describe('--lang switch', () => {
const currentLocale = app.getLocale()
2018-02-08 18:00:41 +00:00
const testLocale = (locale, result, done) => {
const appPath = path.join(__dirname, 'fixtures', 'api', 'locale-check')
const electronPath = remote.getGlobal('process').execPath
let output = ''
let appProcess = ChildProcess.spawn(electronPath, [appPath, `--lang=${locale}`])
appProcess.stdout.on('data', (data) => { output += data })
appProcess.stdout.on('end', () => {
output = output.replace(/(\r\n|\n|\r)/gm, '')
assert.equal(output, result)
done()
})
}
it('should set the locale', (done) => testLocale('fr', 'fr', done))
it('should not set an invalid locale', (done) => testLocale('asdfkl', currentLocale, done))
2018-02-08 18:00:41 +00:00
})
})
2017-11-13 20:13:19 +00:00
afterEach(() => closeWindow(w).then(() => { w = null }))
2017-04-18 23:04:27 +00:00
2017-11-13 20:13:19 +00:00
describe('heap snapshot', () => {
it('does not crash', function () {
2016-03-25 20:03:49 +00:00
process.atomBinding('v8_util').takeHeapSnapshot()
})
})
2017-11-13 20:13:19 +00:00
describe('sending request of http protocol urls', () => {
it('does not crash', (done) => {
const server = http.createServer((req, res) => {
2016-03-25 20:03:49 +00:00
res.end()
server.close()
done()
})
2017-11-13 20:13:19 +00:00
server.listen(0, '127.0.0.1', () => {
const port = server.address().port
$.get(`http://127.0.0.1:${port}`)
2016-03-25 20:03:49 +00:00
})
})
})
2017-11-13 20:13:19 +00:00
describe('navigator.webkitGetUserMedia', () => {
it('calls its callbacks', (done) => {
2016-02-17 01:39:11 +00:00
navigator.webkitGetUserMedia({
2016-01-12 02:40:23 +00:00
audio: true,
video: false
2017-11-13 20:13:19 +00:00
}, () => done(),
() => done())
2016-03-25 20:03:49 +00:00
})
})
2017-11-13 20:13:19 +00:00
describe('navigator.mediaDevices', () => {
if (isCI) return
2017-11-13 20:13:19 +00:00
it('can return labels of enumerated devices', (done) => {
navigator.mediaDevices.enumerateDevices().then((devices) => {
2016-03-25 20:03:49 +00:00
const labels = devices.map((device) => device.label)
const labelFound = labels.some((label) => !!label)
2016-03-28 23:19:18 +00:00
if (labelFound) {
2016-03-25 20:03:49 +00:00
done()
2016-03-28 23:19:18 +00:00
} else {
2017-04-18 23:06:10 +00:00
done(new Error(`No device labels found: ${JSON.stringify(labels)}`))
2016-03-28 23:19:18 +00:00
}
2016-03-25 20:03:49 +00:00
}).catch(done)
})
2016-12-03 18:52:57 +00:00
2017-11-13 20:13:19 +00:00
it('can return new device id when cookie storage is cleared', (done) => {
2016-12-03 18:52:57 +00:00
const options = {
origin: null,
storages: ['cookies']
}
2016-12-12 21:33:14 +00:00
const deviceIds = []
2016-12-03 18:52:57 +00:00
const ses = session.fromPartition('persist:media-device-id')
2017-04-18 23:04:27 +00:00
w = new BrowserWindow({
2016-12-03 18:52:57 +00:00
show: false,
webPreferences: {
session: ses
}
})
2017-11-13 20:13:19 +00:00
w.webContents.on('ipc-message', (event, args) => {
if (args[0] === 'deviceIds') deviceIds.push(args[1])
2016-12-03 18:52:57 +00:00
if (deviceIds.length === 2) {
assert.notDeepEqual(deviceIds[0], deviceIds[1])
2017-11-13 20:13:19 +00:00
closeWindow(w).then(() => {
2016-12-03 18:52:57 +00:00
w = null
done()
2017-11-13 20:13:19 +00:00
}).catch((error) => done(error))
2016-12-03 18:52:57 +00:00
} else {
2017-11-13 20:13:19 +00:00
ses.clearStorageData(options, () => {
2016-12-03 18:52:57 +00:00
w.webContents.reload()
})
}
})
2017-11-13 20:13:19 +00:00
w.loadURL(`file://${fixtures}/pages/media-id-reset.html`)
2016-12-03 18:52:57 +00:00
})
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
describe('navigator.language', () => {
it('should not be empty', () => {
2016-03-25 20:03:49 +00:00
assert.notEqual(navigator.language, '')
})
})
describe('navigator.languages', (done) => {
it('should return the system locale only', () => {
let appLocale = app.getLocale()
assert.equal(navigator.languages.length, 1)
assert.equal(navigator.languages[0], appLocale)
})
})
2017-11-13 20:13:19 +00:00
describe('navigator.serviceWorker', () => {
it('should register for file scheme', (done) => {
w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'sw-file-scheme-spec'
}
})
2017-11-13 20:13:19 +00:00
w.webContents.on('ipc-message', (event, args) => {
2016-01-12 02:40:23 +00:00
if (args[0] === 'reload') {
2016-03-25 20:03:49 +00:00
w.webContents.reload()
2016-01-12 02:40:23 +00:00
} else if (args[0] === 'error') {
done(args[1])
2016-01-12 02:40:23 +00:00
} else if (args[0] === 'response') {
2016-03-25 20:03:49 +00:00
assert.equal(args[1], 'Hello from serviceWorker!')
session.fromPartition('sw-file-scheme-spec').clearStorageData({
2016-01-12 02:40:23 +00:00
storages: ['serviceworkers']
2017-11-13 20:13:19 +00:00
}, () => done())
2016-01-12 02:40:23 +00:00
}
2016-03-25 20:03:49 +00:00
})
w.webContents.on('crashed', () => done(new Error('WebContents crashed.')))
w.loadURL(`file://${fixtures}/pages/service-worker/index.html`)
})
2017-11-13 20:13:19 +00:00
it('should register for intercepted file scheme', (done) => {
const customSession = session.fromPartition('intercept-file')
2017-11-13 20:13:19 +00:00
customSession.protocol.interceptBufferProtocol('file', (request, callback) => {
let file = url.parse(request.url).pathname
2017-11-13 20:13:19 +00:00
if (file[0] === '/' && process.platform === 'win32') file = file.slice(1)
const content = fs.readFileSync(path.normalize(file))
const ext = path.extname(file)
let type = 'text/html'
2017-11-13 20:13:19 +00:00
if (ext === '.js') type = 'application/javascript'
callback({data: content, mimeType: type})
2017-11-13 20:13:19 +00:00
}, (error) => {
if (error) done(error)
})
w = new BrowserWindow({
show: false,
2017-11-13 20:13:19 +00:00
webPreferences: { session: customSession }
})
2017-11-13 20:13:19 +00:00
w.webContents.on('ipc-message', (event, args) => {
if (args[0] === 'reload') {
w.webContents.reload()
} else if (args[0] === 'error') {
2017-11-13 20:13:19 +00:00
done(`unexpected error : ${args[1]}`)
} else if (args[0] === 'response') {
assert.equal(args[1], 'Hello from serviceWorker!')
customSession.clearStorageData({
storages: ['serviceworkers']
2017-11-13 20:13:19 +00:00
}, () => {
customSession.protocol.uninterceptProtocol('file', (error) => done(error))
})
}
})
w.webContents.on('crashed', () => done(new Error('WebContents crashed.')))
w.loadURL(`file://${fixtures}/pages/service-worker/index.html`)
2016-03-25 20:03:49 +00:00
})
})
2017-11-13 20:13:19 +00:00
describe('window.open', () => {
it('returns a BrowserWindowProxy object', () => {
const b = window.open('about:blank', '', 'show=no')
2016-03-25 20:03:49 +00:00
assert.equal(b.closed, false)
assert.equal(b.constructor.name, 'BrowserWindowProxy')
b.close()
})
2017-11-13 20:13:19 +00:00
it('accepts "nodeIntegration" as feature', (done) => {
let b
listener = (event) => {
assert.equal(event.data.isProcessGlobalUndefined, true)
2016-03-25 20:03:49 +00:00
b.close()
done()
}
window.addEventListener('message', listener)
2017-11-13 20:13:19 +00:00
b = window.open(`file://${fixtures}/pages/window-opener-node.html`, '', 'nodeIntegration=no,show=no')
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
it('inherit options of parent window', (done) => {
let b
listener = (event) => {
const ref1 = remote.getCurrentWindow().getSize()
const width = ref1[0]
const height = ref1[1]
assert.equal(event.data, `size: ${width} ${height}`)
2016-03-25 20:03:49 +00:00
b.close()
done()
}
window.addEventListener('message', listener)
2017-11-13 20:13:19 +00:00
b = window.open(`file://${fixtures}/pages/window-open-size.html`, '', 'show=no')
2016-03-25 20:03:49 +00:00
})
2018-03-13 08:09:47 +00:00
for (const show of [true, false]) {
2018-03-13 06:55:48 +00:00
it(`inherits parent visibility over parent {show=${show}} option`, (done) => {
2018-03-13 08:09:47 +00:00
const w = new BrowserWindow({show})
2018-03-13 06:55:48 +00:00
// toggle visibility
if (show) {
w.hide()
} else {
w.show()
}
w.webContents.once('new-window', (e, url, frameName, disposition, options) => {
assert.equal(options.show, w.isVisible())
w.close()
done()
})
w.loadURL(`file://${fixtures}/pages/window-open.html`)
})
}
2017-11-13 20:13:19 +00:00
it('disables node integration when it is disabled on the parent window', (done) => {
let b
listener = (event) => {
assert.equal(event.data.isProcessGlobalUndefined, true)
b.close()
done()
}
window.addEventListener('message', listener)
2017-11-13 20:13:19 +00:00
const windowUrl = require('url').format({
2016-03-24 00:40:25 +00:00
pathname: `${fixtures}/pages/window-opener-no-node-integration.html`,
protocol: 'file',
query: {
2016-03-24 00:40:25 +00:00
p: `${fixtures}/pages/window-opener-node.html`
},
slashes: true
})
2016-03-24 21:12:46 +00:00
b = window.open(windowUrl, '', 'nodeIntegration=no,show=no')
})
it('disables webviewTag when node integration is disabled on the parent window', (done) => {
let b
listener = (event) => {
assert.equal(event.data.isWebViewUndefined, true)
b.close()
done()
}
window.addEventListener('message', listener)
const windowUrl = require('url').format({
pathname: `${fixtures}/pages/window-opener-no-web-view-tag.html`,
protocol: 'file',
query: {
p: `${fixtures}/pages/window-opener-web-view.html`
},
slashes: true
})
b = window.open(windowUrl, '', 'nodeIntegration=no,show=no')
})
// TODO(alexeykuzmin): [Ch66] Times out. Fix it and enable back.
xit('disables node integration when it is disabled on the parent window for chrome devtools URLs', (done) => {
2017-11-13 20:13:19 +00:00
let b
app.once('web-contents-created', (event, contents) => {
contents.once('did-finish-load', () => {
contents.executeJavaScript('typeof process').then((typeofProcessGlobal) => {
assert.equal(typeofProcessGlobal, 'undefined')
b.close()
done()
}).catch(done)
})
})
b = window.open('chrome-devtools://devtools/bundled/inspector.html', '', 'nodeIntegration=no,show=no')
})
2017-11-13 20:13:19 +00:00
it('disables JavaScript when it is disabled on the parent window', (done) => {
let b
app.once('web-contents-created', (event, contents) => {
contents.once('did-finish-load', () => {
app.once('browser-window-created', (event, window) => {
const preferences = window.webContents.getLastWebPreferences()
assert.equal(preferences.javascript, false)
window.destroy()
b.close()
done()
})
// Click link on page
contents.sendInputEvent({type: 'mouseDown', clickCount: 1, x: 1, y: 1})
contents.sendInputEvent({type: 'mouseUp', clickCount: 1, x: 1, y: 1})
})
})
2017-11-13 20:13:19 +00:00
const windowUrl = require('url').format({
pathname: `${fixtures}/pages/window-no-javascript.html`,
protocol: 'file',
slashes: true
})
b = window.open(windowUrl, '', 'javascript=no,show=no')
})
2017-11-13 20:13:19 +00:00
it('disables the <webview> tag when it is disabled on the parent window', (done) => {
let b
2017-11-13 20:13:19 +00:00
listener = (event) => {
assert.equal(event.data.isWebViewGlobalUndefined, true)
b.close()
done()
}
window.addEventListener('message', listener)
2017-11-13 20:13:19 +00:00
const windowUrl = require('url').format({
pathname: `${fixtures}/pages/window-opener-no-webview-tag.html`,
protocol: 'file',
query: {
p: `${fixtures}/pages/window-opener-webview.html`
},
slashes: true
})
b = window.open(windowUrl, '', 'webviewTag=no,nodeIntegration=yes,show=no')
})
2017-11-13 20:13:19 +00:00
it('does not override child options', (done) => {
let b
const size = {
2016-01-12 02:40:23 +00:00
width: 350,
height: 450
2016-03-25 20:03:49 +00:00
}
2017-11-13 20:13:19 +00:00
listener = (event) => {
assert.equal(event.data, `size: ${size.width} ${size.height}`)
2016-03-25 20:03:49 +00:00
b.close()
done()
}
window.addEventListener('message', listener)
2017-11-13 20:13:19 +00:00
b = window.open(`file://${fixtures}/pages/window-open-size.html`, '', 'show=no,width=' + size.width + ',height=' + size.height)
2016-03-25 20:03:49 +00:00
})
2017-01-04 22:44:14 +00:00
it('handles cycles when merging the parent options into the child options', (done) => {
w = BrowserWindow.fromId(ipcRenderer.sendSync('create-window-with-options-cycle'))
2017-11-13 20:13:19 +00:00
w.loadURL(`file://${fixtures}/pages/window-open.html`)
2017-01-04 22:57:51 +00:00
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
assert.equal(options.show, false)
assert.deepEqual(options.foo, {
bar: null,
baz: {
hello: {
world: true
}
2017-01-04 22:54:18 +00:00
},
baz2: {
hello: {
world: true
}
2017-01-04 22:44:14 +00:00
}
})
done()
})
})
2017-11-13 20:13:19 +00:00
it('defines a window.location getter', (done) => {
let b
let targetURL
2016-06-29 16:37:10 +00:00
if (process.platform === 'win32') {
2017-11-13 20:13:19 +00:00
targetURL = `file:///${fixtures.replace(/\\/g, '/')}/pages/base-page.html`
2016-06-29 16:37:10 +00:00
} else {
2017-11-13 20:13:19 +00:00
targetURL = `file://${fixtures}/pages/base-page.html`
2016-06-29 16:37:10 +00:00
}
app.once('browser-window-created', (event, window) => {
window.webContents.once('did-finish-load', () => {
assert.equal(b.location, targetURL)
b.close()
done()
})
2016-03-25 20:03:49 +00:00
})
b = window.open(targetURL)
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
it('defines a window.location setter', (done) => {
2017-01-12 21:19:27 +00:00
let b
app.once('browser-window-created', (event, {webContents}) => {
2017-11-13 20:13:19 +00:00
webContents.once('did-finish-load', () => {
2017-01-12 21:19:27 +00:00
// When it loads, redirect
2017-11-13 20:13:19 +00:00
b.location = `file://${fixtures}/pages/base-page.html`
webContents.once('did-finish-load', () => {
2017-01-12 21:19:27 +00:00
// After our second redirect, cleanup and callback
b.close()
done()
})
2016-03-25 20:03:49 +00:00
})
})
2017-01-12 21:19:27 +00:00
b = window.open('about:blank')
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
it('open a blank page when no URL is specified', (done) => {
2017-01-12 21:19:27 +00:00
let b
app.once('browser-window-created', (event, {webContents}) => {
2017-11-13 20:13:19 +00:00
webContents.once('did-finish-load', () => {
2017-01-12 21:19:27 +00:00
const {location} = b
b.close()
assert.equal(location, 'about:blank')
2017-01-12 21:19:27 +00:00
let c
app.once('browser-window-created', (event, {webContents}) => {
2017-11-13 20:13:19 +00:00
webContents.once('did-finish-load', () => {
2017-01-12 21:19:27 +00:00
const {location} = c
c.close()
assert.equal(location, 'about:blank')
done()
})
})
c = window.open('')
})
})
2017-01-12 21:19:27 +00:00
b = window.open()
})
2017-11-13 20:13:19 +00:00
it('throws an exception when the arguments cannot be converted to strings', () => {
assert.throws(() => {
window.open('', {toString: null})
}, /Cannot convert object to primitive value/)
2017-11-13 20:13:19 +00:00
assert.throws(() => {
window.open('', '', {toString: 3})
}, /Cannot convert object to primitive value/)
})
2017-11-13 20:13:19 +00:00
it('sets the window title to the specified frameName', (done) => {
let b
app.once('browser-window-created', (event, createdWindow) => {
assert.equal(createdWindow.getTitle(), 'hello')
b.close()
done()
})
b = window.open('', 'hello')
})
2017-11-13 20:13:19 +00:00
it('does not throw an exception when the frameName is a built-in object property', (done) => {
let b
app.once('browser-window-created', (event, createdWindow) => {
assert.equal(createdWindow.getTitle(), '__proto__')
b.close()
done()
})
b = window.open('', '__proto__')
})
2017-11-13 20:13:19 +00:00
it('does not throw an exception when the features include webPreferences', () => {
let b
2017-11-13 20:13:19 +00:00
assert.doesNotThrow(() => {
b = window.open('', '', 'webPreferences=')
})
b.close()
})
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
describe('window.opener', () => {
let url = `file://${fixtures}/pages/window-opener.html`
2016-02-17 01:39:11 +00:00
2017-11-13 20:13:19 +00:00
it('is null for main window', (done) => {
w = new BrowserWindow({ show: false })
w.webContents.once('ipc-message', (event, args) => {
2016-03-25 20:03:49 +00:00
assert.deepEqual(args, ['opener', null])
done()
})
w.loadURL(url)
})
2017-11-13 20:13:19 +00:00
it('is not null for window opened by window.open', (done) => {
let b
2017-11-13 20:13:19 +00:00
listener = (event) => {
2016-03-25 20:03:49 +00:00
assert.equal(event.data, 'object')
b.close()
done()
}
window.addEventListener('message', listener)
b = window.open(url, '', 'show=no')
})
})
2017-11-13 20:13:19 +00:00
describe('window.opener access from BrowserWindow', () => {
2016-11-16 16:03:07 +00:00
const scheme = 'other'
let url = `${scheme}://${fixtures}/pages/window-opener-location.html`
let w = null
2017-11-13 20:13:19 +00:00
before((done) => {
protocol.registerFileProtocol(scheme, (request, callback) => {
callback(`${fixtures}/pages/window-opener-location.html`)
2017-11-13 20:13:19 +00:00
}, (error) => done(error))
})
2017-11-13 20:13:19 +00:00
after(() => {
protocol.unregisterProtocol(scheme)
})
2017-11-13 20:13:19 +00:00
afterEach(() => {
w.close()
})
2017-11-13 20:13:19 +00:00
it('does nothing when origin of current window does not match opener', (done) => {
listener = (event) => {
assert.equal(event.data, undefined)
done()
}
window.addEventListener('message', listener)
w = window.open(url, '', 'show=no,nodeIntegration=no')
})
2017-11-13 20:13:19 +00:00
it('works when origin matches', (done) => {
listener = (event) => {
2016-11-25 17:47:28 +00:00
assert.equal(event.data, location.href)
done()
}
window.addEventListener('message', listener)
w = window.open(`file://${fixtures}/pages/window-opener-location.html`, '', 'show=no,nodeIntegration=no')
2016-11-25 17:47:28 +00:00
})
2017-11-13 20:13:19 +00:00
it('works when origin does not match opener but has node integration', (done) => {
listener = (event) => {
assert.equal(event.data, location.href)
done()
}
window.addEventListener('message', listener)
w = window.open(url, '', 'show=no,nodeIntegration=yes')
})
})
2017-11-13 20:13:19 +00:00
describe('window.opener access from <webview>', () => {
const scheme = 'other'
const srcPath = `${fixtures}/pages/webview-opener-postMessage.html`
const pageURL = `file://${fixtures}/pages/window-opener-location.html`
let webview = null
2017-11-13 20:13:19 +00:00
before((done) => {
protocol.registerFileProtocol(scheme, (request, callback) => {
callback(srcPath)
2017-11-13 20:13:19 +00:00
}, (error) => done(error))
})
2017-11-13 20:13:19 +00:00
after(() => {
protocol.unregisterProtocol(scheme)
})
2017-11-13 20:13:19 +00:00
afterEach(() => {
if (webview != null) webview.remove()
})
2017-11-13 20:13:19 +00:00
it('does nothing when origin of webview src URL does not match opener', (done) => {
webview = new WebView()
2017-11-13 20:13:19 +00:00
webview.addEventListener('console-message', (e) => {
assert.equal(e.message, 'null')
done()
})
webview.setAttribute('allowpopups', 'on')
webview.src = url.format({
pathname: srcPath,
protocol: scheme,
query: {
p: pageURL
},
slashes: true
})
document.body.appendChild(webview)
})
2017-11-13 20:13:19 +00:00
it('works when origin matches', (done) => {
2016-11-25 17:47:28 +00:00
webview = new WebView()
2017-11-13 20:13:19 +00:00
webview.addEventListener('console-message', (e) => {
2016-11-25 17:47:28 +00:00
assert.equal(e.message, webview.src)
done()
})
webview.setAttribute('allowpopups', 'on')
webview.src = url.format({
pathname: srcPath,
protocol: 'file',
query: {
p: pageURL
},
slashes: true
})
document.body.appendChild(webview)
})
2017-11-13 20:13:19 +00:00
it('works when origin does not match opener but has node integration', (done) => {
webview = new WebView()
2017-11-13 20:13:19 +00:00
webview.addEventListener('console-message', (e) => {
webview.remove()
assert.equal(e.message, webview.src)
done()
})
webview.setAttribute('allowpopups', 'on')
webview.setAttribute('nodeintegration', 'on')
webview.src = url.format({
pathname: srcPath,
protocol: scheme,
query: {
p: pageURL
},
slashes: true
})
document.body.appendChild(webview)
})
})
2017-11-13 20:13:19 +00:00
describe('window.postMessage', () => {
it('sets the source and origin correctly', (done) => {
let b
listener = (event) => {
2016-03-25 20:03:49 +00:00
window.removeEventListener('message', listener)
b.close()
2017-11-13 20:13:19 +00:00
const message = JSON.parse(event.data)
2016-03-25 20:03:49 +00:00
assert.equal(message.data, 'testing')
assert.equal(message.origin, 'file://')
assert.equal(message.sourceEqualsOpener, true)
assert.equal(event.origin, 'file://')
done()
}
window.addEventListener('message', listener)
2017-01-12 21:19:27 +00:00
app.once('browser-window-created', (event, {webContents}) => {
2017-11-13 20:13:19 +00:00
webContents.once('did-finish-load', () => {
2017-01-12 21:19:27 +00:00
b.postMessage('testing', '*')
})
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
b = window.open(`file://${fixtures}/pages/window-open-postMessage.html`, '', 'show=no')
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
it('throws an exception when the targetOrigin cannot be converted to a string', () => {
const b = window.open('')
assert.throws(() => {
b.postMessage('test', {toString: null})
}, /Cannot convert object to primitive value/)
b.close()
})
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
describe('window.opener.postMessage', () => {
it('sets source and origin correctly', (done) => {
let b
listener = (event) => {
2016-03-25 20:03:49 +00:00
window.removeEventListener('message', listener)
b.close()
assert.equal(event.source, b)
assert.equal(event.origin, 'file://')
done()
}
window.addEventListener('message', listener)
2017-11-13 20:13:19 +00:00
b = window.open(`file://${fixtures}/pages/window-opener-postMessage.html`, '', 'show=no')
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
it('supports windows opened from a <webview>', (done) => {
const webview = new WebView()
2017-11-13 20:13:19 +00:00
webview.addEventListener('console-message', (e) => {
webview.remove()
assert.equal(e.message, 'message')
done()
})
webview.allowpopups = true
webview.src = url.format({
pathname: `${fixtures}/pages/webview-opener-postMessage.html`,
protocol: 'file',
query: {
p: `${fixtures}/pages/window-opener-postMessage.html`
},
slashes: true
})
document.body.appendChild(webview)
})
2017-11-13 20:13:19 +00:00
describe('targetOrigin argument', () => {
let serverURL
let server
2017-11-13 20:13:19 +00:00
beforeEach((done) => {
server = http.createServer((req, res) => {
res.writeHead(200)
const filePath = path.join(fixtures, 'pages', 'window-opener-targetOrigin.html')
res.end(fs.readFileSync(filePath, 'utf8'))
})
2017-11-13 20:13:19 +00:00
server.listen(0, '127.0.0.1', () => {
serverURL = `http://127.0.0.1:${server.address().port}`
done()
})
})
2017-11-13 20:13:19 +00:00
afterEach(() => {
server.close()
})
2017-11-13 20:13:19 +00:00
it('delivers messages that match the origin', (done) => {
let b
2017-11-13 20:13:19 +00:00
listener = (event) => {
window.removeEventListener('message', listener)
b.close()
2017-04-26 18:03:11 +00:00
assert.equal(event.data, 'deliver')
done()
}
window.addEventListener('message', listener)
b = window.open(serverURL, '', 'show=no')
})
})
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
describe('creating a Uint8Array under browser side', () => {
it('does not crash', () => {
const RUint8Array = remote.getGlobal('Uint8Array')
const arr = new RUint8Array()
2016-03-28 23:11:00 +00:00
assert(arr)
2016-03-25 20:03:49 +00:00
})
})
2017-11-13 20:13:19 +00:00
describe('webgl', () => {
before(function () {
if (isCI && process.platform === 'win32') {
this.skip()
}
})
2016-04-30 09:21:18 +00:00
2017-11-13 20:13:19 +00:00
it('can be get as context in canvas', () => {
if (process.platform === 'linux') {
// FIXME(alexeykuzmin): Skip the test.
// this.skip()
return
}
2016-03-28 23:11:00 +00:00
2017-11-13 20:13:19 +00:00
const webgl = document.createElement('canvas').getContext('webgl')
2016-03-25 20:03:49 +00:00
assert.notEqual(webgl, null)
})
})
2017-11-13 20:13:19 +00:00
describe('web workers', () => {
it('Worker can work', (done) => {
const worker = new Worker('../fixtures/workers/worker.js')
const message = 'ping'
worker.onmessage = (event) => {
2016-03-25 20:03:49 +00:00
assert.equal(event.data, message)
worker.terminate()
done()
}
worker.postMessage(message)
})
2017-11-13 20:13:19 +00:00
it('Worker has no node integration by default', (done) => {
2017-03-15 11:07:28 +00:00
let worker = new Worker('../fixtures/workers/worker_node.js')
2017-11-13 20:13:19 +00:00
worker.onmessage = (event) => {
2017-03-15 11:07:28 +00:00
assert.equal(event.data, 'undefined undefined undefined undefined')
worker.terminate()
done()
}
})
2017-11-13 20:13:19 +00:00
it('Worker has node integration with nodeIntegrationInWorker', (done) => {
2017-03-16 10:51:43 +00:00
let webview = new WebView()
2017-11-13 20:13:19 +00:00
webview.addEventListener('ipc-message', (e) => {
2017-03-15 11:07:28 +00:00
assert.equal(e.channel, 'object function object function')
webview.remove()
done()
})
2017-11-13 20:13:19 +00:00
webview.src = `file://${fixtures}/pages/worker.html`
2017-03-15 11:07:28 +00:00
webview.setAttribute('webpreferences', 'nodeIntegration, nodeIntegrationInWorker')
document.body.appendChild(webview)
})
2017-11-13 20:13:19 +00:00
it('SharedWorker can work', (done) => {
const worker = new SharedWorker('../fixtures/workers/shared_worker.js')
const message = 'ping'
worker.port.onmessage = (event) => {
2016-03-25 20:03:49 +00:00
assert.equal(event.data, message)
done()
}
worker.port.postMessage(message)
})
2017-03-15 11:07:28 +00:00
2017-11-13 20:13:19 +00:00
it('SharedWorker has no node integration by default', (done) => {
2017-03-15 11:07:28 +00:00
let worker = new SharedWorker('../fixtures/workers/shared_worker_node.js')
2017-11-13 20:13:19 +00:00
worker.port.onmessage = (event) => {
2017-03-15 11:07:28 +00:00
assert.equal(event.data, 'undefined undefined undefined undefined')
done()
}
})
2017-11-13 20:13:19 +00:00
it('SharedWorker has node integration with nodeIntegrationInWorker', (done) => {
2017-03-16 10:51:43 +00:00
let webview = new WebView()
2017-11-13 20:13:19 +00:00
webview.addEventListener('console-message', (e) => {
2017-03-15 11:07:28 +00:00
console.log(e)
})
2017-11-13 20:13:19 +00:00
webview.addEventListener('ipc-message', (e) => {
2017-03-15 11:07:28 +00:00
assert.equal(e.channel, 'object function object function')
webview.remove()
done()
})
2017-11-13 20:13:19 +00:00
webview.src = `file://${fixtures}/pages/shared_worker.html`
2017-03-15 11:07:28 +00:00
webview.setAttribute('webpreferences', 'nodeIntegration, nodeIntegrationInWorker')
document.body.appendChild(webview)
})
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
describe('iframe', () => {
let iframe = null
2016-03-25 20:03:49 +00:00
2017-11-13 20:13:19 +00:00
beforeEach(() => {
2016-03-25 20:03:49 +00:00
iframe = document.createElement('iframe')
})
2017-11-13 20:13:19 +00:00
afterEach(() => {
2016-03-25 20:03:49 +00:00
document.body.removeChild(iframe)
})
2017-11-13 20:13:19 +00:00
it('does not have node integration', (done) => {
iframe.src = `file://${fixtures}/pages/set-global.html`
2016-03-25 20:03:49 +00:00
document.body.appendChild(iframe)
2017-11-13 20:13:19 +00:00
iframe.onload = () => {
2016-03-25 20:03:49 +00:00
assert.equal(iframe.contentWindow.test, 'undefined undefined undefined')
done()
}
})
})
2017-11-13 20:13:19 +00:00
describe('storage', () => {
it('requesting persitent quota works', (done) => {
navigator.webkitPersistentStorage.requestQuota(1024 * 1024, (grantedBytes) => {
2016-03-25 20:03:49 +00:00
assert.equal(grantedBytes, 1048576)
done()
})
})
2016-09-21 18:35:37 +00:00
2017-11-13 20:13:19 +00:00
describe('custom non standard schemes', () => {
2016-09-21 18:35:37 +00:00
const protocolName = 'storage'
let contents = null
2017-11-13 20:13:19 +00:00
before((done) => {
const handler = (request, callback) => {
2016-09-21 18:35:37 +00:00
let parsedUrl = url.parse(request.url)
let filename
switch (parsedUrl.pathname) {
case '/localStorage' : filename = 'local_storage.html'; break
case '/sessionStorage' : filename = 'session_storage.html'; break
case '/WebSQL' : filename = 'web_sql.html'; break
case '/indexedDB' : filename = 'indexed_db.html'; break
case '/cookie' : filename = 'cookie.html'; break
default : filename = ''
}
2017-11-13 20:13:19 +00:00
callback({path: `${fixtures}/pages/storage/${filename}`})
2016-09-21 18:35:37 +00:00
}
2017-11-13 20:13:19 +00:00
protocol.registerFileProtocol(protocolName, handler, (error) => done(error))
2016-09-21 18:35:37 +00:00
})
2017-11-13 20:13:19 +00:00
after((done) => {
2016-09-21 18:35:37 +00:00
protocol.unregisterProtocol(protocolName, () => done())
})
2017-11-13 20:13:19 +00:00
beforeEach(() => {
2016-09-21 18:35:37 +00:00
contents = webContents.create({})
})
2017-11-13 20:13:19 +00:00
afterEach(() => {
2016-09-21 18:35:37 +00:00
contents.destroy()
contents = null
})
2017-11-13 20:13:19 +00:00
it('cannot access localStorage', (done) => {
ipcMain.once('local-storage-response', (event, error) => {
2016-09-21 18:35:37 +00:00
assert.equal(
error,
'Failed to read the \'localStorage\' property from \'Window\': Access is denied for this document.')
done()
})
contents.loadURL(protocolName + '://host/localStorage')
})
2017-11-13 20:13:19 +00:00
it('cannot access sessionStorage', (done) => {
ipcMain.once('session-storage-response', (event, error) => {
2016-09-21 18:35:37 +00:00
assert.equal(
error,
'Failed to read the \'sessionStorage\' property from \'Window\': Access is denied for this document.')
done()
})
2017-11-13 20:13:19 +00:00
contents.loadURL(`${protocolName}://host/sessionStorage`)
2016-09-21 18:35:37 +00:00
})
2017-11-13 20:13:19 +00:00
it('cannot access WebSQL database', (done) => {
ipcMain.once('web-sql-response', (event, error) => {
2016-09-21 18:35:37 +00:00
assert.equal(
error,
'An attempt was made to break through the security policy of the user agent.')
done()
})
2017-11-13 20:13:19 +00:00
contents.loadURL(`${protocolName}://host/WebSQL`)
2016-09-21 18:35:37 +00:00
})
2017-11-13 20:13:19 +00:00
it('cannot access indexedDB', (done) => {
ipcMain.once('indexed-db-response', (event, error) => {
2016-09-21 18:35:37 +00:00
assert.equal(error, 'The user denied permission to access the database.')
done()
})
2017-11-13 20:13:19 +00:00
contents.loadURL(`${protocolName}://host/indexedDB`)
2016-09-21 18:35:37 +00:00
})
2017-11-13 20:13:19 +00:00
it('cannot access cookie', (done) => {
ipcMain.once('cookie-response', (event, cookie) => {
2016-09-21 18:35:37 +00:00
assert(!cookie)
done()
})
2017-11-13 20:13:19 +00:00
contents.loadURL(`${protocolName}://host/cookie`)
2016-09-21 18:35:37 +00:00
})
})
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
describe('websockets', () => {
let wss = null
let server = null
const WebSocketServer = ws.Server
2016-03-25 20:03:49 +00:00
2017-11-13 20:13:19 +00:00
afterEach(() => {
2016-03-25 20:03:49 +00:00
wss.close()
server.close()
})
2017-11-13 20:13:19 +00:00
it('has user agent', (done) => {
2016-03-25 20:03:49 +00:00
server = http.createServer()
2017-11-13 20:13:19 +00:00
server.listen(0, '127.0.0.1', () => {
const port = server.address().port
wss = new WebSocketServer({ server: server })
2016-03-25 20:03:49 +00:00
wss.on('error', done)
2017-11-13 20:13:19 +00:00
wss.on('connection', (ws) => {
2016-01-12 02:40:23 +00:00
if (ws.upgradeReq.headers['user-agent']) {
2016-03-25 20:03:49 +00:00
done()
2016-01-12 02:40:23 +00:00
} else {
2016-03-25 20:03:49 +00:00
done('user agent is empty')
2016-01-12 02:40:23 +00:00
}
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
const socket = new WebSocket(`ws://127.0.0.1:${port}`)
2016-03-28 23:11:00 +00:00
assert(socket)
2016-03-25 20:03:49 +00:00
})
})
})
2017-11-13 20:13:19 +00:00
describe('Promise', () => {
it('resolves correctly in Node.js calls', (done) => {
2016-01-12 02:40:23 +00:00
document.registerElement('x-element', {
prototype: Object.create(HTMLElement.prototype, {
createdCallback: {
2017-11-13 20:13:19 +00:00
value: () => {}
2016-01-12 02:40:23 +00:00
}
})
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
setImmediate(() => {
let called = false
Promise.resolve().then(() => {
2016-03-25 20:03:49 +00:00
done(called ? void 0 : new Error('wrong sequence'))
})
document.createElement('x-element')
called = true
})
})
2017-11-13 20:13:19 +00:00
it('resolves correctly in Electron calls', (done) => {
2016-01-12 02:40:23 +00:00
document.registerElement('y-element', {
prototype: Object.create(HTMLElement.prototype, {
createdCallback: {
2017-11-13 20:13:19 +00:00
value: () => {}
2016-01-12 02:40:23 +00:00
}
})
2016-03-25 20:03:49 +00:00
})
2017-11-13 20:13:19 +00:00
remote.getGlobal('setImmediate')(() => {
let called = false
Promise.resolve().then(() => {
2016-03-25 20:03:49 +00:00
done(called ? void 0 : new Error('wrong sequence'))
})
document.createElement('y-element')
called = true
})
})
})
2016-08-22 10:26:07 +00:00
2017-11-13 20:13:19 +00:00
describe('fetch', () => {
it('does not crash', (done) => {
const server = http.createServer((req, res) => {
2016-08-22 10:26:07 +00:00
res.end('test')
server.close()
})
2017-11-13 20:13:19 +00:00
server.listen(0, '127.0.0.1', () => {
2016-08-22 10:26:07 +00:00
const port = server.address().port
2017-11-13 20:13:19 +00:00
fetch(`http://127.0.0.1:${port}`).then((res) => res.body.getReader())
.then((reader) => {
reader.read().then((r) => {
reader.cancel()
done()
})
}).catch((e) => done(e))
2016-08-22 10:26:07 +00:00
})
})
})
2017-02-04 14:48:16 +00:00
2017-11-13 20:13:19 +00:00
describe('PDF Viewer', () => {
2018-03-15 08:51:48 +00:00
before(function () {
if (!features.isPDFViewerEnabled()) {
2018-03-15 08:51:48 +00:00
return this.skip()
}
})
2017-10-20 06:46:41 +00:00
beforeEach(() => {
this.pdfSource = url.format({
2018-03-15 08:51:48 +00:00
pathname: path.join(fixtures, 'assets', 'cat.pdf').replace(/\\/g, '/'),
2017-10-20 06:46:41 +00:00
protocol: 'file',
slashes: true
})
this.pdfSourceWithParams = url.format({
2018-03-15 08:51:48 +00:00
pathname: path.join(fixtures, 'assets', 'cat.pdf').replace(/\\/g, '/'),
query: {
a: 1,
b: 2
},
protocol: 'file',
slashes: true
2017-10-20 06:46:41 +00:00
})
2018-03-15 08:51:48 +00:00
this.createBrowserWindow = ({plugins, preload}) => {
2018-03-15 08:51:48 +00:00
w = new BrowserWindow({
show: false,
webPreferences: {
preload: path.join(fixtures, 'module', preload),
plugins: plugins
}
})
}
this.testPDFIsLoadedInSubFrame = (page, preloadFile, done) => {
2018-03-15 08:51:48 +00:00
const pagePath = url.format({
pathname: path.join(fixtures, 'pages', page).replace(/\\/g, '/'),
protocol: 'file',
slashes: true
})
this.createBrowserWindow({plugins: true, preload: preloadFile})
2018-03-15 08:51:48 +00:00
ipcMain.once('pdf-loaded', (event, state) => {
assert.equal(state, 'success')
done()
})
w.webContents.on('page-title-updated', () => {
const parsedURL = url.parse(w.webContents.getURL(), true)
assert.equal(parsedURL.protocol, 'chrome:')
assert.equal(parsedURL.hostname, 'pdf-viewer')
assert.equal(parsedURL.query.src, pagePath)
assert.equal(w.webContents.getTitle(), 'cat.pdf')
})
w.webContents.loadURL(pagePath)
}
})
2017-10-20 06:46:41 +00:00
2017-11-13 20:13:19 +00:00
it('opens when loading a pdf resource as top level navigation', (done) => {
this.createBrowserWindow({plugins: true, preload: 'preload-pdf-loaded.js'})
2017-11-13 20:13:19 +00:00
ipcMain.once('pdf-loaded', (event, state) => {
2017-06-28 20:01:22 +00:00
assert.equal(state, 'success')
done()
2017-03-11 21:36:08 +00:00
})
2017-11-13 20:13:19 +00:00
w.webContents.on('page-title-updated', () => {
2017-02-04 14:48:16 +00:00
const parsedURL = url.parse(w.webContents.getURL(), true)
assert.equal(parsedURL.protocol, 'chrome:')
assert.equal(parsedURL.hostname, 'pdf-viewer')
assert.equal(parsedURL.query.src, this.pdfSource)
2017-03-10 05:20:26 +00:00
assert.equal(w.webContents.getTitle(), 'cat.pdf')
2017-02-04 14:48:16 +00:00
})
w.webContents.loadURL(this.pdfSource)
2017-02-04 14:48:16 +00:00
})
2017-11-13 20:13:19 +00:00
it('opens a pdf link given params, the query string should be escaped', (done) => {
this.createBrowserWindow({plugins: true, preload: 'preload-pdf-loaded.js'})
2017-11-13 20:13:19 +00:00
ipcMain.once('pdf-loaded', (event, state) => {
assert.equal(state, 'success')
done()
})
2017-11-13 20:13:19 +00:00
w.webContents.on('page-title-updated', () => {
const parsedURL = url.parse(w.webContents.getURL(), true)
assert.equal(parsedURL.protocol, 'chrome:')
assert.equal(parsedURL.hostname, 'pdf-viewer')
assert.equal(parsedURL.query.src, this.pdfSourceWithParams)
assert.equal(parsedURL.query.b, undefined)
Fix some flaky tests in CI (#12153) * Guard whole InitPrefs with ScopedAllowIO Saw a crash: 0 0x7f8d2f7d918d base::debug::StackTrace::StackTrace() 1 0x7f8d2f7d755c base::debug::StackTrace::StackTrace() 2 0x7f8d2f867caa logging::LogMessage::~LogMessage() 3 0x7f8d2fa157c7 base::ThreadRestrictions::AssertIOAllowed() 4 0x7f8d2f83453a base::OpenFile() 5 0x7f8d2f82a967 base::ReadFileToStringWithMaxSize() 6 0x7f8d2f82ad44 base::ReadFileToString() 7 0x7f8d2f846f73 JSONFileValueDeserializer::ReadFileToString() 8 0x7f8d2f84738c JSONFileValueDeserializer::Deserialize() 9 0x7f8d35a5d1f6 <unknown> 10 0x7f8d35a5c217 JsonPrefStore::ReadPrefs() 11 0x7f8d35a87d3e PrefService::InitFromStorage() 12 0x7f8d35a87c60 PrefService::PrefService() 13 0x7f8d35a91a10 PrefServiceFactory::Create() 14 0x000000e86e1b brightray::BrowserContext::InitPrefs() 15 0x000000c2bd64 atom::AtomBrowserContext::AtomBrowserContext() 16 0x000000c320db atom::AtomBrowserContext::From() 17 0x000000b4b8b5 atom::api::Session::FromPartition() * Fix done being called twice in setInterval test The callback passed to browser process is called asyncly, so it is possible that multiple callbacks has already been scheduled before we can clearInternval. * Fix failing test when dir name has special chars The pdfSource is not escaped while parsedURL.search is. * Call done with Error instead of string * Fix crash caused by not removing input observer Solve crash: 0 libcontent.dylib content::RenderWidgetHostImpl::DispatchInputEventWithLatencyInfo(blink::WebInputEvent const&, ui::LatencyInfo*) + 214 1 libcontent.dylib content::RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo(blink::WebMouseEvent const&, ui::LatencyInfo const&) + 1350 2 libcontent.dylib content::RenderWidgetHostViewMac::ProcessMouseEvent(blink::WebMouseEvent const&, ui::LatencyInfo const&) + 44 3 libcontent.dylib content::RenderWidgetHostInputEventRouter::RouteMouseEvent(content::RenderWidgetHostViewBase*, blink::WebMouseEvent*, ui::LatencyInfo const&) + 1817 * Print detailed error * Run tests after server is ready
2018-03-07 05:40:27 +00:00
assert(parsedURL.search.endsWith('%3Fa%3D1%26b%3D2'))
assert.equal(w.webContents.getTitle(), 'cat.pdf')
})
w.webContents.loadURL(this.pdfSourceWithParams)
})
2017-11-13 20:13:19 +00:00
it('should download a pdf when plugins are disabled', (done) => {
this.createBrowserWindow({plugins: false, preload: 'preload-pdf-loaded.js'})
ipcRenderer.sendSync('set-download-option', false, false)
2017-11-13 20:13:19 +00:00
ipcRenderer.once('download-done', (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) => {
assert.equal(state, 'completed')
assert.equal(filename, 'cat.pdf')
assert.equal(mimeType, 'application/pdf')
fs.unlinkSync(path.join(fixtures, 'mock.pdf'))
done()
})
w.webContents.loadURL(this.pdfSource)
})
2017-11-13 20:13:19 +00:00
it('should not open when pdf is requested as sub resource', (done) => {
fetch(this.pdfSource).then((res) => {
2017-02-04 14:48:16 +00:00
assert.equal(res.status, 200)
2017-03-10 05:20:26 +00:00
assert.notEqual(document.title, 'cat.pdf')
2017-02-04 14:48:16 +00:00
done()
2017-11-13 20:13:19 +00:00
}).catch((e) => done(e))
2017-02-04 14:48:16 +00:00
})
2017-10-20 06:46:41 +00:00
2017-11-13 20:13:19 +00:00
it('opens when loading a pdf resource in a iframe', (done) => {
this.testPDFIsLoadedInSubFrame('pdf-in-iframe.html', 'preload-pdf-loaded-in-subframe.js', done)
2017-10-19 14:15:02 +00:00
})
2017-10-20 06:46:41 +00:00
2017-11-13 20:13:19 +00:00
it('opens when loading a pdf resource in a nested iframe', (done) => {
this.testPDFIsLoadedInSubFrame('pdf-in-nested-iframe.html', 'preload-pdf-loaded-in-nested-subframe.js', done)
2017-10-19 14:15:02 +00:00
})
2017-02-04 14:48:16 +00:00
})
2017-11-13 20:13:19 +00:00
describe('window.alert(message, title)', () => {
it('throws an exception when the arguments cannot be converted to strings', () => {
assert.throws(() => {
window.alert({toString: null})
}, /Cannot convert object to primitive value/)
})
})
2017-11-13 20:13:19 +00:00
describe('window.confirm(message, title)', () => {
it('throws an exception when the arguments cannot be converted to strings', () => {
assert.throws(() => {
window.confirm({toString: null}, 'title')
}, /Cannot convert object to primitive value/)
})
})
2017-11-13 20:13:19 +00:00
describe('window.history', () => {
describe('window.history.go(offset)', () => {
it('throws an exception when the argumnet cannot be converted to a string', () => {
assert.throws(() => {
window.history.go({toString: null})
}, /Cannot convert object to primitive value/)
})
})
2017-11-13 20:13:19 +00:00
describe('window.history.pushState', () => {
it('should push state after calling history.pushState() from the same url', (done) => {
2017-11-13 20:13:19 +00:00
w = new BrowserWindow({ show: false })
w.webContents.once('did-finish-load', () => {
// History should have current page by now.
assert.equal(w.webContents.length(), 1)
w.webContents.executeJavaScript('window.history.pushState({}, "")', () => {
// Initial page + pushed state
assert.equal(w.webContents.length(), 2)
done()
})
})
2017-06-05 21:47:11 +00:00
w.loadURL('about:blank')
})
})
})
2016-03-25 20:03:49 +00:00
})