diff --git a/spec/fixtures/module/preload-node-off.js b/spec/fixtures/module/preload-node-off.js index 452ee41b68b3..65db2a7e4dc0 100644 --- a/spec/fixtures/module/preload-node-off.js +++ b/spec/fixtures/module/preload-node-off.js @@ -1,6 +1,12 @@ setImmediate(function () { try { - console.log([typeof process, typeof setImmediate, typeof global, typeof Buffer].join(' ')) + const types = { + process: typeof process, + setImmediate: typeof setImmediate, + global: typeof global, + Buffer: typeof Buffer + } + console.log(JSON.stringify(types)) } catch (e) { console.log(e.message) } diff --git a/spec/fixtures/module/preload-required-module.js b/spec/fixtures/module/preload-required-module.js index 1028d55cb0ef..75b2bf4add88 100644 --- a/spec/fixtures/module/preload-required-module.js +++ b/spec/fixtures/module/preload-required-module.js @@ -1,5 +1,12 @@ try { - console.log([typeof process, typeof setImmediate, typeof global, typeof Buffer, typeof global.Buffer].join(' ')) + const types = { + process: typeof process, + setImmediate: typeof setImmediate, + global: typeof global, + Buffer: typeof Buffer, + 'global.Buffer': typeof global.Buffer + } + console.log(JSON.stringify(types)) } catch (e) { console.log(e.message) } diff --git a/spec/fixtures/module/preload.js b/spec/fixtures/module/preload.js index e9dad8ac99bb..6b77bde03294 100644 --- a/spec/fixtures/module/preload.js +++ b/spec/fixtures/module/preload.js @@ -1 +1,7 @@ -console.log([typeof require, typeof module, typeof process, typeof Buffer].join(' ')) +const types = { + require: typeof require, + module: typeof module, + process: typeof process, + Buffer: typeof Buffer +} +console.log(JSON.stringify(types)) diff --git a/spec/fixtures/pages/c.html b/spec/fixtures/pages/c.html index bc55104ec535..a9e5b129b28c 100644 --- a/spec/fixtures/pages/c.html +++ b/spec/fixtures/pages/c.html @@ -1,7 +1,13 @@ diff --git a/spec/fixtures/pages/d.html b/spec/fixtures/pages/d.html index f0e33fde5ea1..8d6c6ef712f1 100644 --- a/spec/fixtures/pages/d.html +++ b/spec/fixtures/pages/d.html @@ -1,7 +1,12 @@ diff --git a/spec/fixtures/pages/partition/one.html b/spec/fixtures/pages/partition/one.html index ad22c341df95..cc5f66e4a884 100644 --- a/spec/fixtures/pages/partition/one.html +++ b/spec/fixtures/pages/partition/one.html @@ -1,4 +1,6 @@ diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 66f1d882c169..072719e6ad8a 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -20,6 +20,25 @@ describe(' tag', function () { let webview = null let w = null + const waitForEvent = (eventTarget, eventName) => { + return new Promise((resolve) => { + eventTarget.addEventListener(eventName, resolve, {once: true}) + }) + } + + const loadWebView = (webview, attributes = {}) => { + for (const [name, value] of Object.entries(attributes)) { + webview.setAttribute(name, value) + } + document.body.appendChild(webview) + return waitForEvent(webview, 'did-finish-load') + } + + const startLoadingWebViewAndWaitForMessage = (webview, attributes = {}) => { + loadWebView(webview, attributes) // Don't wait for load to be finished. + return waitForEvent(webview, 'console-message') + } + beforeEach(() => { webview = new WebView() }) @@ -76,86 +95,73 @@ describe(' tag', function () { }) describe('src attribute', () => { - it('specifies the page to load', (done) => { - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'a') - done() + it('specifies the page to load', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + src: `file://${fixtures}/pages/a.html` }) - webview.src = `file://${fixtures}/pages/a.html` - document.body.appendChild(webview) + assert.equal(message, 'a') }) - it('navigates to new page when changed', (done) => { - const listener = () => { - webview.src = `file://${fixtures}/pages/b.html` - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'b') - done() - }) - webview.removeEventListener('did-finish-load', listener) - } - webview.addEventListener('did-finish-load', listener) - webview.src = `file://${fixtures}/pages/a.html` - document.body.appendChild(webview) + it('navigates to new page when changed', async () => { + await loadWebView(webview, { + src: `file://${fixtures}/pages/a.html` + }) + + webview.src = `file://${fixtures}/pages/b.html` + + const {message} = await waitForEvent(webview, 'console-message') + assert.equal(message, 'b') }) - it('resolves relative URLs', (done) => { - const listener = (e) => { - assert.equal(e.message, 'Window script is loaded before preload script') - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.src = '../fixtures/pages/e.html' - document.body.appendChild(webview) + it('resolves relative URLs', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + src: '../fixtures/pages/e.html' + }) + assert.equal(message, 'Window script is loaded before preload script') }) it('ignores empty values', () => { assert.equal(webview.src, '') - webview.src = '' - assert.equal(webview.src, '') - webview.src = null - assert.equal(webview.src, '') - webview.src = undefined - assert.equal(webview.src, '') + + for (const emptyValue of ['', null, undefined]) { + webview.src = emptyValue + assert.equal(webview.src, '') + } }) }) describe('nodeintegration attribute', () => { - it('inserts no node symbols when not set', (done) => { - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'undefined undefined undefined undefined') - done() + it('inserts no node symbols when not set', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + src: `file://${fixtures}/pages/c.html` }) - webview.src = `file://${fixtures}/pages/c.html` - document.body.appendChild(webview) + + assert.equal(message, '{"require":"undefined","module":"undefined","process":"undefined","global":"undefined"}') }) - it('inserts node symbols when set', (done) => { - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'function object object') - done() + it('inserts node symbols when set', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + nodeintegration: 'on', + src: `file://${fixtures}/pages/d.html` }) - webview.setAttribute('nodeintegration', 'on') - webview.src = `file://${fixtures}/pages/d.html` - document.body.appendChild(webview) + + assert.equal(message, '{"require":"function","module":"object","process":"object"}') }) - it('loads node symbols after POST navigation when set', function (done) { + it('loads node symbols after POST navigation when set', async function () { // FIXME Figure out why this is timing out on AppVeyor if (process.env.APPVEYOR === 'True') { // FIXME(alexeykuzmin): Skip the test. - // this.skip() - return done() + this.skip() + return } - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'function object object') - done() + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + nodeintegration: 'on', + src: `file://${fixtures}/pages/post.html` }) - webview.setAttribute('nodeintegration', 'on') - webview.src = `file://${fixtures}/pages/post.html` - document.body.appendChild(webview) + + assert.equal(message, '{"require":"function","module":"object","process":"object"}') }) it('disables node integration on child windows when it is disabled on the webview', (done) => { @@ -164,9 +170,7 @@ describe(' tag', function () { done() }) - webview.setAttribute('allowpopups', 'on') - - webview.src = url.format({ + const src = url.format({ pathname: `${fixtures}/pages/webview-opener-no-node-integration.html`, protocol: 'file', query: { @@ -174,112 +178,119 @@ describe(' tag', function () { }, slashes: true }) - document.body.appendChild(webview) + loadWebView(webview, { + allowpopups: 'on', + src + }) }) - it('loads native modules when navigation happens', (done) => { - if (!nativeModulesEnabled) return done() - - const listener = () => { - webview.removeEventListener('did-finish-load', listener) - const listener2 = (e) => { - assert.equal(e.message, 'function') - done() - } - webview.addEventListener('console-message', listener2) - webview.reload() + it('loads native modules when navigation happens', async function () { + if (!nativeModulesEnabled) { + this.skip() + return } - webview.addEventListener('did-finish-load', listener) - webview.setAttribute('nodeintegration', 'on') - webview.src = `file://${fixtures}/pages/native-module.html` - document.body.appendChild(webview) + + await loadWebView(webview, { + nodeintegration: 'on', + src: `file://${fixtures}/pages/native-module.html` + }) + + webview.reload() + + const {message} = await waitForEvent(webview, 'console-message') + assert.equal(message, 'function') }) }) describe('preload attribute', () => { - it('loads the script before other scripts in window', (done) => { - const listener = (e) => { - assert.equal(e.message, 'function object object function') - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.setAttribute('preload', `${fixtures}/module/preload.js`) - webview.src = `file://${fixtures}/pages/e.html` - document.body.appendChild(webview) - }) - - it('preload script can still use "process" and "Buffer" when nodeintegration is off', (done) => { - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'object undefined object function') - done() + it('loads the script before other scripts in window', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + preload: `${fixtures}/module/preload.js`, + src: `file://${fixtures}/pages/e.html` }) - webview.setAttribute('preload', `${fixtures}/module/preload-node-off.js`) - webview.src = `file://${fixtures}/api/blank.html` - document.body.appendChild(webview) + + expect(message).to.be.a('string') + expect(message).to.be.not.equal('Window script is loaded before preload script') }) - it('preload script can require modules that still use "process" and "Buffer" when nodeintegration is off', (done) => { - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'object undefined object function undefined') - done() + it('preload script can still use "process" and "Buffer" when nodeintegration is off', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + preload: `${fixtures}/module/preload-node-off.js`, + src: `file://${fixtures}/api/blank.html` + }) + + const types = JSON.parse(message) + expect(types).to.include({ + process: 'object', + Buffer: 'function' }) - webview.setAttribute('preload', `${fixtures}/module/preload-node-off-wrapper.js`) - webview.src = `file://${fixtures}/api/blank.html` - document.body.appendChild(webview) }) - it('receives ipc message in preload script', (done) => { + it('preload script can require modules that still use "process" and "Buffer" when nodeintegration is off', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + preload: `${fixtures}/module/preload-node-off-wrapper.js`, + src: `file://${fixtures}/api/blank.html` + }) + + const types = JSON.parse(message) + expect(types).to.include({ + process: 'object', + Buffer: 'function' + }) + }) + + it('receives ipc message in preload script', async () => { const message = 'boom!' - const listener = (e) => { - assert.equal(e.channel, 'pong') - assert.deepEqual(e.args, [message]) - webview.removeEventListener('ipc-message', listener) - done() - } - const listener2 = () => { - webview.send('ping', message) - webview.removeEventListener('did-finish-load', listener2) - } - webview.addEventListener('ipc-message', listener) - webview.addEventListener('did-finish-load', listener2) + webview.setAttribute('preload', `${fixtures}/module/preload-ipc.js`) webview.src = `file://${fixtures}/pages/e.html` document.body.appendChild(webview) + + await waitForEvent(webview, 'did-finish-load') + webview.send('ping', message) + const e = await waitForEvent(webview, 'ipc-message') + + assert.equal(e.channel, 'pong') + assert.deepEqual(e.args, [message]) }) - it('works without script tag in page', (done) => { - const listener = (e) => { - assert.equal(e.message, 'function object object function') - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.setAttribute('preload', `${fixtures}/module/preload.js`) - webview.src = `file://${fixtures}pages/base-page.html` - document.body.appendChild(webview) + it('works without script tag in page', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + preload: `${fixtures}/module/preload.js`, + src: `file://${fixtures}pages/base-page.html` + }) + + const types = JSON.parse(message) + expect(types).to.include({ + require: 'function', + module: 'object', + process: 'object', + Buffer: 'function' + }) }) - it('resolves relative URLs', (done) => { - const listener = (e) => { - assert.equal(e.message, 'function object object function') - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.src = `file://${fixtures}/pages/e.html` - webview.preload = '../fixtures/module/preload.js' - document.body.appendChild(webview) + it('resolves relative URLs', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + preload: '../fixtures/module/preload.js', + src: `file://${fixtures}/pages/e.html` + }) + + const types = JSON.parse(message) + expect(types).to.include({ + require: 'function', + module: 'object', + process: 'object', + Buffer: 'function' + }) }) it('ignores empty values', () => { assert.equal(webview.preload, '') - webview.preload = '' - assert.equal(webview.preload, '') - webview.preload = null - assert.equal(webview.preload, '') - webview.preload = undefined - assert.equal(webview.preload, '') + + for (const emptyValue of ['', null, undefined]) { + webview.preload = emptyValue + assert.equal(webview.preload, '') + } }) }) @@ -293,180 +304,155 @@ describe(' tag', function () { done() }).listen(0, '127.0.0.1', () => { const port = server.address().port - webview.setAttribute('httpreferrer', referrer) - webview.src = 'http://127.0.0.1:' + port - document.body.appendChild(webview) + loadWebView(webview, { + httpreferrer: referrer, + src: `http://127.0.0.1:${port}` + }) }) }) }) describe('useragent attribute', () => { - it('sets the user agent', (done) => { + it('sets the user agent', async () => { const referrer = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko' - const listener = (e) => { - assert.equal(e.message, referrer) - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.setAttribute('useragent', referrer) - webview.src = `file://${fixtures}/pages/useragent.html` - document.body.appendChild(webview) + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + src: `file://${fixtures}/pages/useragent.html`, + useragent: referrer + }) + assert.equal(message, referrer) }) }) describe('disablewebsecurity attribute', () => { - it('does not disable web security when not set', (done) => { + it('does not disable web security when not set', async () => { const jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js') const src = ` ` const encoded = btoa(unescape(encodeURIComponent(src))) - const listener = (e) => { - assert(/Not allowed to load local resource/.test(e.message)) - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.src = `data:text/html;base64,${encoded}` - document.body.appendChild(webview) - }) - it('disables web security when set', (done) => { - const jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js') - const src = ` ` - const encoded = btoa(unescape(encodeURIComponent(src))) - const listener = (e) => { - assert.equal(e.message, 'ok') - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.setAttribute('disablewebsecurity', '') - webview.src = `data:text/html;base64,${encoded}` - document.body.appendChild(webview) - }) - - it('does not break node integration', (done) => { - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'function object object') - done() + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + src: `data:text/html;base64,${encoded}` }) - webview.setAttribute('nodeintegration', 'on') - webview.setAttribute('disablewebsecurity', '') - webview.src = `file://${fixtures}/pages/d.html` - document.body.appendChild(webview) + expect(message).to.be.a('string') + expect(message).to.contain('Not allowed to load local resource') }) - it('does not break preload script', (done) => { - const listener = (e) => { - assert.equal(e.message, 'function object object function') - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.setAttribute('disablewebsecurity', '') - webview.setAttribute('preload', `${fixtures}/module/preload.js`) - webview.src = `file://${fixtures}/pages/e.html` - document.body.appendChild(webview) + it('disables web security when set', async () => { + const jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js') + const src = ` ` + const encoded = btoa(unescape(encodeURIComponent(src))) + + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + disablewebsecurity: '', + src: `data:text/html;base64,${encoded}` + }) + assert.equal(message, 'ok') + }) + + it('does not break node integration', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + disablewebsecurity: '', + nodeintegration: 'on', + src: `file://${fixtures}/pages/d.html` + }) + assert.equal(message, '{"require":"function","module":"object","process":"object"}') + }) + + it('does not break preload script', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + disablewebsecurity: '', + preload: `${fixtures}/module/preload.js`, + src: `file://${fixtures}/pages/e.html` + }) + assert.equal(message, '{"require":"function","module":"object","process":"object","Buffer":"function"}') }) }) describe('partition attribute', () => { - it('inserts no node symbols when not set', (done) => { - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'undefined undefined undefined undefined') - done() + it('inserts no node symbols when not set', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + partition: 'test1', + src: `file://${fixtures}/pages/c.html` }) - webview.src = `file://${fixtures}/pages/c.html` - webview.partition = 'test1' - document.body.appendChild(webview) + assert.equal(message, '{"require":"undefined","module":"undefined","process":"undefined","global":"undefined"}') }) - it('inserts node symbols when set', (done) => { - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'function object object') - done() + it('inserts node symbols when set', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + nodeintegration: 'on', + partition: 'test2', + src: `file://${fixtures}/pages/d.html` }) - webview.setAttribute('nodeintegration', 'on') - webview.src = `file://${fixtures}/pages/d.html` - webview.partition = 'test2' - document.body.appendChild(webview) + assert.equal(message, '{"require":"function","module":"object","process":"object"}') }) - it('isolates storage for different id', (done) => { - const listener = (e) => { - assert.equal(e.message, ' 0') - webview.removeEventListener('console-message', listener) - done() - } + it('isolates storage for different id', async () => { window.localStorage.setItem('test', 'one') - webview.addEventListener('console-message', listener) - webview.src = `file://${fixtures}/pages/partition/one.html` - webview.partition = 'test3' - document.body.appendChild(webview) + + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + partition: 'test3', + src: `file://${fixtures}/pages/partition/one.html` + }) + + const parsedMessage = JSON.parse(message) + expect(parsedMessage).to.include({ + numberOfEntries: 0, + testValue: null + }) }) - it('uses current session storage when no id is provided', (done) => { - const listener = (e) => { - assert.equal(e.message, 'one 1') - webview.removeEventListener('console-message', listener) - done() - } - window.localStorage.setItem('test', 'one') - webview.addEventListener('console-message', listener) - webview.src = `file://${fixtures}/pages/partition/one.html` - document.body.appendChild(webview) + it('uses current session storage when no id is provided', async () => { + const testValue = 'one' + window.localStorage.setItem('test', testValue) + + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + src: `file://${fixtures}/pages/partition/one.html` + }) + + const parsedMessage = JSON.parse(message) + expect(parsedMessage).to.include({ + numberOfEntries: 1, + testValue + }) }) }) describe('allowpopups attribute', () => { - it('can not open new window when not set', (done) => { - const listener = (e) => { - assert.equal(e.message, 'null') - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.src = `file://${fixtures}/pages/window-open-hide.html` - document.body.appendChild(webview) + it('can not open new window when not set', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + src: `file://${fixtures}/pages/window-open-hide.html` + }) + assert.equal(message, 'null') }) - it('can open new window when set', (done) => { - const listener = (e) => { - assert.equal(e.message, 'window') - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.setAttribute('allowpopups', 'on') - webview.src = `file://${fixtures}/pages/window-open-hide.html` - document.body.appendChild(webview) + it('can open new window when set', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + allowpopups: 'on', + src: `file://${fixtures}/pages/window-open-hide.html` + }) + assert.equal(message, 'window') }) }) describe('webpreferences attribute', () => { - it('can enable nodeintegration', (done) => { - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'function object object') - done() + it('can enable nodeintegration', async () => { + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + src: `file://${fixtures}/pages/d.html`, + webpreferences: 'nodeIntegration' }) - webview.setAttribute('webpreferences', 'nodeIntegration') - webview.src = `file://${fixtures}/pages/d.html` - document.body.appendChild(webview) + assert.equal(message, '{"require":"function","module":"object","process":"object"}') }) - it('can disables web security and enable nodeintegration', (done) => { + it('can disables web security and enable nodeintegration', async () => { const jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js') - const src = ` ` + const src = ` ` const encoded = btoa(unescape(encodeURIComponent(src))) - const listener = (e) => { - assert.equal(e.message, 'ok function') - webview.removeEventListener('console-message', listener) - done() - } - webview.addEventListener('console-message', listener) - webview.setAttribute('webpreferences', 'webSecurity=no, nodeIntegration=yes') - webview.src = `data:text/html;base64,${encoded}` - document.body.appendChild(webview) + + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + src: `data:text/html;base64,${encoded}`, + webpreferences: 'webSecurity=no, nodeIntegration=yes' + }) + + assert.equal(message, 'function') }) it('can enable context isolation', (done) => { @@ -494,85 +480,87 @@ describe(' tag', function () { done() }) - webview.setAttribute('preload', path.join(fixtures, 'api', 'isolated-preload.js')) - webview.setAttribute('allowpopups', 'yes') - webview.setAttribute('webpreferences', 'contextIsolation=yes') - webview.src = 'file://' + fixtures + '/api/isolated.html' - document.body.appendChild(webview) + loadWebView(webview, { + allowpopups: 'yes', + preload: path.join(fixtures, 'api', 'isolated-preload.js'), + src: `file://${fixtures}/api/isolated.html`, + webpreferences: 'contextIsolation=yes' + }) }) }) describe('new-window event', () => { - it('emits when window.open is called', (done) => { - webview.addEventListener('new-window', (e) => { - assert.equal(e.url, 'http://host/') - assert.equal(e.frameName, 'host') - done() + it('emits when window.open is called', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/window-open.html` }) - webview.src = `file://${fixtures}/pages/window-open.html` - document.body.appendChild(webview) + const event = await waitForEvent(webview, 'new-window') + + assert.equal(event.url, 'http://host/') + assert.equal(event.frameName, 'host') }) - it('emits when link with target is called', (done) => { - webview.addEventListener('new-window', (e) => { - assert.equal(e.url, 'http://host/') - assert.equal(e.frameName, 'target') - done() + it('emits when link with target is called', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/target-name.html` }) - webview.src = `file://${fixtures}/pages/target-name.html` - document.body.appendChild(webview) + const event = await waitForEvent(webview, 'new-window') + + assert.equal(event.url, 'http://host/') + assert.equal(event.frameName, 'target') }) }) describe('ipc-message event', () => { - it('emits when guest sends a ipc message to browser', (done) => { - webview.addEventListener('ipc-message', (e) => { - assert.equal(e.channel, 'channel') - assert.deepEqual(e.args, ['arg1', 'arg2']) - done() + it('emits when guest sends a ipc message to browser', async () => { + loadWebView(webview, { + nodeintegration: 'on', + src: `file://${fixtures}/pages/ipc-message.html` }) - webview.src = `file://${fixtures}/pages/ipc-message.html` - webview.setAttribute('nodeintegration', 'on') - document.body.appendChild(webview) + const event = await waitForEvent(webview, 'ipc-message') + + assert.equal(event.channel, 'channel') + assert.deepEqual(event.args, ['arg1', 'arg2']) }) }) describe('page-title-set event', () => { - it('emits when title is set', (done) => { - webview.addEventListener('page-title-set', (e) => { - assert.equal(e.title, 'test') - assert(e.explicitSet) - done() + it('emits when title is set', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/a.html` }) - webview.src = `file://${fixtures}/pages/a.html` - document.body.appendChild(webview) + const event = await waitForEvent(webview, 'page-title-set') + + assert.equal(event.title, 'test') + assert(event.explicitSet) }) }) describe('page-favicon-updated event', () => { - it('emits when favicon urls are received', (done) => { - webview.addEventListener('page-favicon-updated', (e) => { - assert.equal(e.favicons.length, 2) - if (process.platform === 'win32') { - assert(/^file:\/\/\/[A-Z]:\/favicon.png$/i.test(e.favicons[0])) - } else { - assert.equal(e.favicons[0], 'file:///favicon.png') - } - done() + it('emits when favicon urls are received', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/a.html` }) - webview.src = `file://${fixtures}/pages/a.html` - document.body.appendChild(webview) + const {favicons} = await waitForEvent(webview, 'page-favicon-updated') + + assert(favicons) + assert.equal(favicons.length, 2) + if (process.platform === 'win32') { + assert(/^file:\/\/\/[A-Z]:\/favicon.png$/i.test(favicons[0])) + } else { + assert.equal(favicons[0], 'file:///favicon.png') + } }) }) describe('will-navigate event', () => { - it('emits when a url that leads to oustide of the page is clicked', (done) => { - webview.addEventListener('will-navigate', (e) => { - assert.equal(e.url, 'http://host/') - done() + it('emits when a url that leads to oustide of the page is clicked', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/webview-will-navigate.html` }) - webview.src = `file://${fixtures}/pages/webview-will-navigate.html` - document.body.appendChild(webview) + const {url} = await waitForEvent(webview, 'will-navigate') + + assert.equal(url, 'http://host/') }) }) @@ -585,18 +573,16 @@ describe(' tag', function () { pathname: p }) - it('emits when a url that leads to outside of the page is clicked', (done) => { - webview.addEventListener('did-navigate', (e) => { - assert.equal(e.url, pageUrl) - done() - }) - webview.src = pageUrl - document.body.appendChild(webview) + it('emits when a url that leads to outside of the page is clicked', async () => { + loadWebView(webview, {src: pageUrl}) + const {url} = await waitForEvent(webview, 'did-navigate') + + assert.equal(url, pageUrl) }) }) describe('did-navigate-in-page event', () => { - it('emits when an anchor link is clicked', (done) => { + it('emits when an anchor link is clicked', async () => { let p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page.html') p = p.replace(/\\/g, '/') const pageUrl = url.format({ @@ -604,24 +590,20 @@ describe(' tag', function () { slashes: true, pathname: p }) - webview.addEventListener('did-navigate-in-page', (e) => { - assert.equal(e.url, `${pageUrl}#test_content`) - done() - }) - webview.src = pageUrl - document.body.appendChild(webview) + loadWebView(webview, {src: pageUrl}) + const event = await waitForEvent(webview, 'did-navigate-in-page') + assert.equal(event.url, `${pageUrl}#test_content`) }) - it('emits when window.history.replaceState is called', (done) => { - webview.addEventListener('did-navigate-in-page', (e) => { - assert.equal(e.url, 'http://host/') - done() + it('emits when window.history.replaceState is called', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/webview-did-navigate-in-page-with-history.html` }) - webview.src = `file://${fixtures}/pages/webview-did-navigate-in-page-with-history.html` - document.body.appendChild(webview) + const {url} = await waitForEvent(webview, 'did-navigate-in-page') + assert.equal(url, 'http://host/') }) - it('emits when window.location.hash is changed', (done) => { + it('emits when window.location.hash is changed', async () => { let p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page-with-hash.html') p = p.replace(/\\/g, '/') const pageUrl = url.format({ @@ -629,115 +611,108 @@ describe(' tag', function () { slashes: true, pathname: p }) - webview.addEventListener('did-navigate-in-page', (e) => { - assert.equal(e.url, `${pageUrl}#test`) - done() - }) - webview.src = pageUrl - document.body.appendChild(webview) + loadWebView(webview, {src: pageUrl}) + const event = await waitForEvent(webview, 'did-navigate-in-page') + assert.equal(event.url, `${pageUrl}#test`) }) }) describe('close event', () => { - it('should fire when interior page calls window.close', (done) => { - webview.addEventListener('close', () => done()) - webview.src = `file://${fixtures}/pages/close.html` - document.body.appendChild(webview) + it('should fire when interior page calls window.close', async () => { + loadWebView(webview, {src: `file://${fixtures}/pages/close.html`}) + await waitForEvent(webview, 'close') }) }) describe('setDevToolsWebContents() API', () => { - it('sets webContents of webview as devtools', (done) => { + it('sets webContents of webview as devtools', async () => { const webview2 = new WebView() - webview2.addEventListener('did-attach', () => { - webview2.addEventListener('dom-ready', () => { - const devtools = webview2.getWebContents() - assert.ok(devtools.getURL().startsWith('chrome-devtools://devtools')) - devtools.executeJavaScript('InspectorFrontendHost.constructor.name', (name) => { - assert.ok(name, 'InspectorFrontendHostImpl') - document.body.removeChild(webview2) - done() - }) + loadWebView(webview2) + await waitForEvent(webview2, 'did-attach') + + // Setup an event handler for further usage. + const waitForDomReady = waitForEvent(webview2, 'dom-ready') + + loadWebView(webview, {src: 'about:blank'}) + await waitForEvent(webview, 'dom-ready') + webview.getWebContents().setDevToolsWebContents(webview2.getWebContents()) + webview.getWebContents().openDevTools() + + await waitForDomReady + + // Its WebContents should be a DevTools. + const devtools = webview2.getWebContents() + assert.ok(devtools.getURL().startsWith('chrome-devtools://devtools')) + + return new Promise((resolve) => { + devtools.executeJavaScript('InspectorFrontendHost.constructor.name', (name) => { + document.body.removeChild(webview2) + expect(name).to.be.equal('InspectorFrontendHostImpl') + resolve() }) - webview.addEventListener('dom-ready', () => { - webview.getWebContents().setDevToolsWebContents(webview2.getWebContents()) - webview.getWebContents().openDevTools() - }) - webview.src = 'about:blank' - document.body.appendChild(webview) }) - document.body.appendChild(webview2) }) }) describe('devtools-opened event', () => { - it('should fire when webview.openDevTools() is called', (done) => { - const listener = () => { - webview.removeEventListener('devtools-opened', listener) - webview.closeDevTools() - done() - } - webview.addEventListener('devtools-opened', listener) - webview.addEventListener('dom-ready', () => { - webview.openDevTools() + it('should fire when webview.openDevTools() is called', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/base-page.html` }) - webview.src = `file://${fixtures}/pages/base-page.html` - document.body.appendChild(webview) + await waitForEvent(webview, 'dom-ready') + + webview.openDevTools() + await waitForEvent(webview, 'devtools-opened') + + webview.closeDevTools() }) }) describe('devtools-closed event', () => { - it('should fire when webview.closeDevTools() is called', (done) => { - const listener2 = () => { - webview.removeEventListener('devtools-closed', listener2) - done() - } - const listener = () => { - webview.removeEventListener('devtools-opened', listener) - webview.closeDevTools() - } - webview.addEventListener('devtools-opened', listener) - webview.addEventListener('devtools-closed', listener2) - webview.addEventListener('dom-ready', () => { - webview.openDevTools() + it('should fire when webview.closeDevTools() is called', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/base-page.html` }) - webview.src = `file://${fixtures}/pages/base-page.html` - document.body.appendChild(webview) + await waitForEvent(webview, 'dom-ready') + + webview.openDevTools() + await waitForEvent(webview, 'devtools-opened') + + webview.closeDevTools() + await waitForEvent(webview, 'devtools-closed') }) }) describe('devtools-focused event', () => { - it('should fire when webview.openDevTools() is called', (done) => { - const listener = () => { - webview.removeEventListener('devtools-focused', listener) - webview.closeDevTools() - done() - } - webview.addEventListener('devtools-focused', listener) - webview.addEventListener('dom-ready', () => { - webview.openDevTools() + it('should fire when webview.openDevTools() is called', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/base-page.html` }) - webview.src = `file://${fixtures}/pages/base-page.html` - document.body.appendChild(webview) + + const waitForDevToolsFocused = waitForEvent(webview, 'devtools-focused') + + await waitForEvent(webview, 'dom-ready') + webview.openDevTools() + + await waitForDevToolsFocused + webview.closeDevTools() }) }) describe('.reload()', () => { - it('should emit beforeunload handler', (done) => { - const listener = (e) => { - assert.equal(e.channel, 'onbeforeunload') - webview.removeEventListener('ipc-message', listener) - done() - } - const listener2 = () => { - webview.reload() - webview.removeEventListener('did-finish-load', listener2) - } - webview.addEventListener('ipc-message', listener) - webview.addEventListener('did-finish-load', listener2) - webview.setAttribute('nodeintegration', 'on') - webview.src = `file://${fixtures}/pages/beforeunload-false.html` - document.body.appendChild(webview) + it('should emit beforeunload handler', async () => { + await loadWebView(webview, { + nodeintegration: 'on', + src: `file://${fixtures}/pages/beforeunload-false.html` + }) + + // Event handler has to be added before reload. + const waitForOnbeforeunload = waitForEvent(webview, 'ipc-message') + + webview.reload() + + const {channel} = await waitForOnbeforeunload + assert.equal(channel, 'onbeforeunload') }) }) @@ -759,7 +734,7 @@ describe(' tag', function () { } } - const loadListener = (e) => { + const loadListener = () => { if (loadCount === 1) { webview.src = `file://${fixtures}/pages/base-page.html` } else if (loadCount === 2) { @@ -782,27 +757,28 @@ describe(' tag', function () { webview.addEventListener('ipc-message', listener) webview.addEventListener('did-finish-load', loadListener) - webview.setAttribute('nodeintegration', 'on') - webview.src = `file://${fixtures}/pages/history-replace.html` - document.body.appendChild(webview) + + loadWebView(webview, { + nodeintegration: 'on', + src: `file://${fixtures}/pages/history-replace.html` + }) }) }) describe('.clearHistory()', () => { - it('should clear the navigation history', (done) => { - const listener = (e) => { - assert.equal(e.channel, 'history') - assert.equal(e.args[0], 2) - assert(webview.canGoBack()) - webview.clearHistory() - assert(!webview.canGoBack()) - webview.removeEventListener('ipc-message', listener) - done() - } - webview.addEventListener('ipc-message', listener) - webview.setAttribute('nodeintegration', 'on') - webview.src = `file://${fixtures}/pages/history.html` - document.body.appendChild(webview) + it('should clear the navigation history', async () => { + loadWebView(webview, { + nodeintegration: 'on', + src: `file://${fixtures}/pages/history.html` + }) + const event = await waitForEvent(webview, 'ipc-message') + + assert.equal(event.channel, 'history') + assert.equal(event.args[0], 2) + assert(webview.canGoBack()) + + webview.clearHistory() + assert(!webview.canGoBack()) }) }) @@ -826,9 +802,10 @@ describe(' tag', function () { assert.equal(e.channel, message) done() }) - webview.src = `file://${fixtures}/pages/basic-auth.html?port=${port}` - webview.setAttribute('nodeintegration', 'on') - document.body.appendChild(webview) + loadWebView(webview, { + nodeintegration: 'on', + src: `file://${fixtures}/pages/basic-auth.html?port=${port}` + }) }) }) }) @@ -841,8 +818,9 @@ describe(' tag', function () { webview.addEventListener('dom-ready', () => { done() }) - webview.src = `file://${fixtures}/pages/dom-ready.html?port=${port}` - document.body.appendChild(webview) + loadWebView(webview, { + src: `file://${fixtures}/pages/dom-ready.html?port=${port}` + }) }) }) @@ -856,88 +834,83 @@ describe(' tag', function () { }) describe('executeJavaScript', () => { - it('should support user gesture', function (done) { - const listener = () => { - webview.removeEventListener('enter-html-full-screen', listener) - done() - } - const listener2 = () => { - const jsScript = "document.querySelector('video').webkitRequestFullscreen()" - webview.executeJavaScript(jsScript, true) - webview.removeEventListener('did-finish-load', listener2) - } - webview.addEventListener('enter-html-full-screen', listener) - webview.addEventListener('did-finish-load', listener2) - webview.src = `file://${fixtures}/pages/fullscreen.html` - document.body.appendChild(webview) + it('should support user gesture', async () => { + await loadWebView(webview, { + src: `file://${fixtures}/pages/fullscreen.html` + }) + + // Event handler has to be added before js execution. + const waitForEnterHtmlFullScreen = waitForEvent(webview, 'enter-html-full-screen') + + const jsScript = "document.querySelector('video').webkitRequestFullscreen()" + webview.executeJavaScript(jsScript, true) + + return waitForEnterHtmlFullScreen }) - it('can return the result of the executed script', function (done) { - const listener = () => { - const jsScript = "'4'+2" + it('can return the result of the executed script', async () => { + await loadWebView(webview, { + src: 'about:blank' + }) + + const jsScript = "'4'+2" + const expectedResult = '42' + + return new Promise((resolve) => { webview.executeJavaScript(jsScript, false, (result) => { - assert.equal(result, '42') - done() + assert.equal(result, expectedResult) + resolve() }) - webview.removeEventListener('did-finish-load', listener) - } - webview.addEventListener('did-finish-load', listener) - webview.src = 'about:blank' - document.body.appendChild(webview) + }) }) }) describe('sendInputEvent', () => { - it('can send keyboard event', (done) => { - webview.addEventListener('ipc-message', (e) => { - assert.equal(e.channel, 'keyup') - assert.deepEqual(e.args, ['C', 'KeyC', 67, true, false]) - done() + it('can send keyboard event', async () => { + loadWebView(webview, { + nodeintegration: 'on', + src: `file://${fixtures}/pages/onkeyup.html` }) - webview.addEventListener('dom-ready', () => { - webview.sendInputEvent({ - type: 'keyup', - keyCode: 'c', - modifiers: ['shift'] - }) + await waitForEvent(webview, 'dom-ready') + + const waitForIpcMessage = waitForEvent(webview, 'ipc-message') + webview.sendInputEvent({ + type: 'keyup', + keyCode: 'c', + modifiers: ['shift'] }) - webview.src = `file://${fixtures}/pages/onkeyup.html` - webview.setAttribute('nodeintegration', 'on') - document.body.appendChild(webview) + + const event = await waitForIpcMessage + assert.equal(event.channel, 'keyup') + assert.deepEqual(event.args, ['C', 'KeyC', 67, true, false]) }) - it('can send mouse event', (done) => { - webview.addEventListener('ipc-message', (e) => { - assert.equal(e.channel, 'mouseup') - assert.deepEqual(e.args, [10, 20, false, true]) - done() + it('can send mouse event', async () => { + loadWebView(webview, { + nodeintegration: 'on', + src: `file://${fixtures}/pages/onmouseup.html` }) - webview.addEventListener('dom-ready', () => { - webview.sendInputEvent({ - type: 'mouseup', - modifiers: ['ctrl'], - x: 10, - y: 20 - }) + await waitForEvent(webview, 'dom-ready') + + const waitForIpcMessage = waitForEvent(webview, 'ipc-message') + webview.sendInputEvent({ + type: 'mouseup', + modifiers: ['ctrl'], + x: 10, + y: 20 }) - webview.src = `file://${fixtures}/pages/onmouseup.html` - webview.setAttribute('nodeintegration', 'on') - document.body.appendChild(webview) + + const event = await waitForIpcMessage + assert.equal(event.channel, 'mouseup') + assert.deepEqual(event.args, [10, 20, false, true]) }) }) describe('media-started-playing media-paused events', () => { - it('emits when audio starts and stops playing', (done) => { - let audioPlayed = false - webview.addEventListener('media-started-playing', () => { - audioPlayed = true - }) - webview.addEventListener('media-paused', () => { - assert(audioPlayed) - done() - }) - webview.src = `file://${fixtures}/pages/audio.html` - document.body.appendChild(webview) + it('emits when audio starts and stops playing', async () => { + loadWebView(webview, {src: `file://${fixtures}/pages/audio.html`}) + await waitForEvent(webview, 'media-started-playing') + await waitForEvent(webview, 'media-paused') }) }) @@ -973,15 +946,18 @@ describe(' tag', function () { }) describe('did-change-theme-color event', () => { - it('emits when theme color changes', (done) => { - webview.addEventListener('did-change-theme-color', () => done()) - webview.src = `file://${fixtures}/pages/theme-color.html` - document.body.appendChild(webview) + it('emits when theme color changes', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/theme-color.html` + }) + await waitForEvent(webview, 'did-change-theme-color') }) }) describe('permission-request event', () => { function setUpRequestHandler (webview, requestedPermission, completed) { + assert.ok(webview.partition) + const listener = function (webContents, permission, callback) { if (webContents.getId() === webview.getId()) { // requestMIDIAccess with sysex requests both midi and midiSysex so @@ -1079,15 +1055,13 @@ describe(' tag', function () { }) describe('.getWebContents', () => { - it('can return the webcontents associated', (done) => { - webview.addEventListener('did-finish-load', () => { - const webviewContents = webview.getWebContents() - assert(webviewContents) - assert.equal(webviewContents.getURL(), 'about:blank') - done() - }) - webview.src = 'about:blank' - document.body.appendChild(webview) + it('can return the webcontents associated', async () => { + const src = 'about:blank' + await loadWebView(webview, {src}) + + const webviewContents = webview.getWebContents() + assert(webviewContents) + assert.equal(webviewContents.getURL(), src) }) }) @@ -1158,36 +1132,36 @@ describe(' tag', function () { }) describe('will-attach-webview event', () => { - it('supports changing the web preferences', (done) => { + it('supports changing the web preferences', async () => { ipcRenderer.send('disable-node-on-next-will-attach-webview') - webview.addEventListener('console-message', (event) => { - assert.equal(event.message, 'undefined undefined undefined undefined') - done() + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + nodeintegration: 'yes', + src: `file://${fixtures}/pages/a.html` }) - webview.setAttribute('nodeintegration', 'yes') - webview.src = `file://${fixtures}/pages/a.html` - document.body.appendChild(webview) + + assert.equal(message, + '{"require":"undefined","module":"undefined","process":"undefined","global":"undefined"}') }) - it('supports preventing a webview from being created', (done) => { + it('supports preventing a webview from being created', async () => { ipcRenderer.send('prevent-next-will-attach-webview') - webview.addEventListener('destroyed', () => { - done() + + loadWebView(webview, { + src: `file://${fixtures}/pages/c.html` }) - webview.src = `file://${fixtures}/pages/c.html` - document.body.appendChild(webview) + await waitForEvent(webview, 'destroyed') }) - it('supports removing the preload script', (done) => { + it('supports removing the preload script', async () => { ipcRenderer.send('disable-preload-on-next-will-attach-webview') - webview.addEventListener('console-message', (event) => { - assert.equal(event.message, 'undefined') - done() + + const {message} = await startLoadingWebViewAndWaitForMessage(webview, { + nodeintegration: 'yes', + preload: path.join(fixtures, 'module', 'preload-set-global.js'), + src: `file://${fixtures}/pages/a.html` }) - webview.setAttribute('nodeintegration', 'yes') - webview.setAttribute('preload', path.join(fixtures, 'module', 'preload-set-global.js')) - webview.src = `file://${fixtures}/pages/a.html` - document.body.appendChild(webview) + + assert.equal(message, 'undefined') }) }) @@ -1222,52 +1196,43 @@ describe(' tag', function () { describe('guestinstance attribute', () => { it('before loading there is no attribute', () => { - document.body.appendChild(webview) + loadWebView(webview) // Don't wait for loading to finish. assert(!webview.hasAttribute('guestinstance')) }) - it('loading a page sets the guest view', (done) => { - const loadListener = () => { - webview.removeEventListener('did-finish-load', loadListener, false) - const instance = webview.getAttribute('guestinstance') - assert.equal(instance, parseInt(instance)) + it('loading a page sets the guest view', async () => { + await loadWebView(webview, { + src: `file://${fixtures}/api/blank.html` + }) - const guest = getGuestWebContents(parseInt(instance)) - assert.equal(guest, webview.getWebContents()) - done() - } - webview.addEventListener('did-finish-load', loadListener, false) - webview.src = `file://${fixtures}/api/blank.html` - document.body.appendChild(webview) + const instance = webview.getAttribute('guestinstance') + assert.equal(instance, parseInt(instance)) + + const guest = getGuestWebContents(parseInt(instance)) + assert.equal(guest, webview.getWebContents()) }) - it('deleting the attribute destroys the webview', (done) => { - const loadListener = () => { - webview.removeEventListener('did-finish-load', loadListener, false) - const destroyListener = () => { - webview.removeEventListener('destroyed', destroyListener, false) - assert.equal(getGuestWebContents(instance), null) - done() - } - webview.addEventListener('destroyed', destroyListener, false) + it('deleting the attribute destroys the webview', async () => { + await loadWebView(webview, { + src: `file://${fixtures}/api/blank.html` + }) - const instance = parseInt(webview.getAttribute('guestinstance')) - webview.removeAttribute('guestinstance') - } - webview.addEventListener('did-finish-load', loadListener, false) - webview.src = `file://${fixtures}/api/blank.html` - document.body.appendChild(webview) + const instance = parseInt(webview.getAttribute('guestinstance')) + const waitForDestroy = waitForEvent(webview, 'destroyed') + webview.removeAttribute('guestinstance') + + await waitForDestroy + assert.equal(getGuestWebContents(instance), null) }) it('setting the attribute on a new webview moves the contents', (done) => { const loadListener = () => { - webview.removeEventListener('did-finish-load', loadListener, false) const webContents = webview.getWebContents() const instance = webview.getAttribute('guestinstance') const destroyListener = () => { - webview.removeEventListener('destroyed', destroyListener, false) assert.equal(webContents, webview2.getWebContents()) + // Make sure that events are hooked up to the right webview now webview2.addEventListener('console-message', (e) => { assert.equal(e.message, 'a') @@ -1277,44 +1242,39 @@ describe(' tag', function () { webview2.src = `file://${fixtures}/pages/a.html` } - webview.addEventListener('destroyed', destroyListener, false) + webview.addEventListener('destroyed', destroyListener, {once: true}) const webview2 = new WebView() - webview2.setAttribute('guestinstance', instance) - document.body.appendChild(webview2) + loadWebView(webview2, { + guestinstance: instance + }) } - webview.addEventListener('did-finish-load', loadListener, false) - webview.src = `file://${fixtures}/api/blank.html` - document.body.appendChild(webview) + webview.addEventListener('did-finish-load', loadListener, {once: true}) + loadWebView(webview, { + src: `file://${fixtures}/api/blank.html` + }) }) - it('setting the attribute to an invalid guestinstance does nothing', (done) => { - const loadListener = () => { - webview.removeEventListener('did-finish-load', loadListener, false) - webview.setAttribute('guestinstance', 55) + it('setting the attribute to an invalid guestinstance does nothing', async () => { + await loadWebView(webview, { + src: `file://${fixtures}/api/blank.html` + }) + webview.setAttribute('guestinstance', 55) - // Make sure that events are still hooked up to the webview - webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'a') - done() - }) - webview.src = `file://${fixtures}/pages/a.html` - } - webview.addEventListener('did-finish-load', loadListener, false) - - webview.src = `file://${fixtures}/api/blank.html` - document.body.appendChild(webview) + // Make sure that events are still hooked up to the webview + const waitForMessage = waitForEvent(webview, 'console-message') + webview.src = `file://${fixtures}/pages/a.html` + const {message} = await waitForMessage + assert.equal(message, 'a') }) it('setting the attribute on an existing webview moves the contents', (done) => { const load1Listener = () => { - webview.removeEventListener('did-finish-load', load1Listener, false) const webContents = webview.getWebContents() const instance = webview.getAttribute('guestinstance') let destroyedInstance const destroyListener = () => { - webview.removeEventListener('destroyed', destroyListener, false) assert.equal(webContents, webview2.getWebContents()) assert.equal(null, getGuestWebContents(parseInt(destroyedInstance))) @@ -1327,67 +1287,67 @@ describe(' tag', function () { webview2.src = 'file://' + fixtures + '/pages/a.html' } - webview.addEventListener('destroyed', destroyListener, false) + webview.addEventListener('destroyed', destroyListener, {once: true}) const webview2 = new WebView() const load2Listener = () => { - webview2.removeEventListener('did-finish-load', load2Listener, false) destroyedInstance = webview2.getAttribute('guestinstance') assert.notEqual(instance, destroyedInstance) webview2.setAttribute('guestinstance', instance) } - webview2.addEventListener('did-finish-load', load2Listener, false) - webview2.src = 'file://' + fixtures + '/api/blank.html' - document.body.appendChild(webview2) + webview2.addEventListener('did-finish-load', load2Listener, {once: true}) + loadWebView(webview2, { + src: `file://${fixtures}/api/blank.html` + }) } - webview.addEventListener('did-finish-load', load1Listener, false) - webview.src = 'file://' + fixtures + '/api/blank.html' - document.body.appendChild(webview) + + webview.addEventListener('did-finish-load', load1Listener, {once: true}) + loadWebView(webview, { + src: `file://${fixtures}/api/blank.html` + }) }) it('moving a guest back to its original webview should work', (done) => { const loadListener = () => { - webview.removeEventListener('did-finish-load', loadListener, false) const webContents = webview.getWebContents() const instance = webview.getAttribute('guestinstance') const destroy1Listener = () => { - webview.removeEventListener('destroyed', destroy1Listener, false) assert.equal(webContents, webview2.getWebContents()) assert.equal(null, webview.getWebContents()) const destroy2Listener = () => { - webview2.removeEventListener('destroyed', destroy2Listener, false) assert.equal(webContents, webview.getWebContents()) assert.equal(null, webview2.getWebContents()) // Make sure that events are hooked up to the right webview now webview.addEventListener('console-message', (e) => { - assert.equal(e.message, 'a') document.body.removeChild(webview2) + assert.equal(e.message, 'a') done() }) webview.src = `file://${fixtures}/pages/a.html` } - webview2.addEventListener('destroyed', destroy2Listener, false) + webview2.addEventListener('destroyed', destroy2Listener, {once: true}) webview.setAttribute('guestinstance', instance) } - webview.addEventListener('destroyed', destroy1Listener, false) + webview.addEventListener('destroyed', destroy1Listener, {once: true}) const webview2 = new WebView() webview2.setAttribute('guestinstance', instance) document.body.appendChild(webview2) } - webview.addEventListener('did-finish-load', loadListener, false) - webview.src = `file://${fixtures}/api/blank.html` - document.body.appendChild(webview) + + webview.addEventListener('did-finish-load', loadListener, {once: true}) + loadWebView(webview, { + src: `file://${fixtures}/api/blank.html` + }) }) it('setting the attribute on a webview in a different window moves the contents', (done) => { const loadListener = () => { - webview.removeEventListener('did-finish-load', loadListener, false) const instance = webview.getAttribute('guestinstance') w = new BrowserWindow({ show: false }) @@ -1401,7 +1361,7 @@ describe(' tag', function () { }) w.loadURL(`file://${fixtures}/pages/webview-move-to-window.html`) } - webview.addEventListener('did-finish-load', loadListener, false) + webview.addEventListener('did-finish-load', loadListener, {once: true}) webview.src = `file://${fixtures}/api/blank.html` document.body.appendChild(webview) }) @@ -1712,8 +1672,9 @@ describe(' tag', function () { assert.equal(content, 'Hello') done() }) - webview.src = `file://${path.join(fixtures, 'api', 'native-window-open-blank.html')}` - document.body.appendChild(webview) + loadWebView(webview, { + src: `file://${path.join(fixtures, 'api', 'native-window-open-blank.html')}` + }) }) it('opens window of same domain with cross-scripting enabled', (done) => { @@ -1721,8 +1682,9 @@ describe(' tag', function () { assert.equal(content, 'Hello') done() }) - webview.src = `file://${path.join(fixtures, 'api', 'native-window-open-file.html')}` - document.body.appendChild(webview) + loadWebView(webview, { + src: `file://${path.join(fixtures, 'api', 'native-window-open-file.html')}` + }) }) it('returns null from window.open when allowpopups is not set', (done) => { @@ -1731,8 +1693,9 @@ describe(' tag', function () { assert.equal(windowOpenReturnedNull, true) done() }) - webview.src = `file://${path.join(fixtures, 'api', 'native-window-open-no-allowpopups.html')}` - document.body.appendChild(webview) + loadWebView(webview, { + src: `file://${path.join(fixtures, 'api', 'native-window-open-no-allowpopups.html')}` + }) }) it('blocks accessing cross-origin frames', (done) => { @@ -1740,18 +1703,19 @@ describe(' tag', function () { assert.equal(content, 'Blocked a frame with origin "file://" from accessing a cross-origin frame.') done() }) - webview.src = `file://${path.join(fixtures, 'api', 'native-window-open-cross-origin.html')}` - document.body.appendChild(webview) + loadWebView(webview, { + src: `file://${path.join(fixtures, 'api', 'native-window-open-cross-origin.html')}` + }) }) - it('emits a new-window event', (done) => { - webview.addEventListener('new-window', (e) => { - assert.equal(e.url, 'http://host/') - assert.equal(e.frameName, 'host') - done() + it('emits a new-window event', async () => { + loadWebView(webview, { + src: `file://${fixtures}/pages/window-open.html` }) - webview.src = `file://${fixtures}/pages/window-open.html` - document.body.appendChild(webview) + const event = await waitForEvent(webview, 'new-window') + + assert.equal(event.url, 'http://host/') + assert.equal(event.frameName, 'host') }) it('emits a browser-window-created event', (done) => { @@ -1767,8 +1731,9 @@ describe(' tag', function () { done() } }) - webview.src = `file://${fixtures}/pages/window-open.html` - document.body.appendChild(webview) + loadWebView(webview, { + src: `file://${fixtures}/pages/window-open.html` + }) }) }) })