2020-03-20 20:28:31 +00:00
import { expect } from 'chai' ;
2020-06-11 03:57:51 +00:00
import { app , session , BrowserWindow , ipcMain , WebContents , Extension } from 'electron/main' ;
2020-03-20 20:28:31 +00:00
import { closeAllWindows , closeWindow } from './window-helpers' ;
import * as http from 'http' ;
import { AddressInfo } from 'net' ;
import * as path from 'path' ;
import * as fs from 'fs' ;
import { emittedOnce , emittedNTimes } from './events-helpers' ;
const fixtures = path . join ( __dirname , 'fixtures' ) ;
2019-07-24 23:01:08 +00:00
2020-04-30 16:38:09 +00:00
describe ( 'chrome extensions' , ( ) = > {
2020-06-03 07:56:28 +00:00
const emptyPage = '<script>console.log("loaded")</script>' ;
2019-07-24 23:01:08 +00:00
// NB. extensions are only allowed on http://, https:// and ftp:// (!) urls by default.
2020-03-20 20:28:31 +00:00
let server : http.Server ;
let url : string ;
2019-07-24 23:01:08 +00:00
before ( async ( ) = > {
2020-08-03 23:56:18 +00:00
server = http . createServer ( ( req , res ) = > {
if ( req . url === '/cors' ) {
res . setHeader ( 'Access-Control-Allow-Origin' , 'http://example.com' ) ;
}
res . end ( emptyPage ) ;
} ) ;
2019-07-24 23:01:08 +00:00
await new Promise ( resolve = > server . listen ( 0 , '127.0.0.1' , ( ) = > {
2020-03-20 20:28:31 +00:00
url = ` http://127.0.0.1: ${ ( server . address ( ) as AddressInfo ) . port } ` ;
resolve ( ) ;
} ) ) ;
} ) ;
2019-07-24 23:01:08 +00:00
after ( ( ) = > {
2020-03-20 20:28:31 +00:00
server . close ( ) ;
} ) ;
afterEach ( closeAllWindows ) ;
2020-02-10 16:28:03 +00:00
afterEach ( ( ) = > {
session . defaultSession . getAllExtensions ( ) . forEach ( ( e : any ) = > {
2020-03-20 20:28:31 +00:00
session . defaultSession . removeExtension ( e . id ) ;
} ) ;
} ) ;
2020-02-10 16:28:03 +00:00
2020-08-19 00:41:47 +00:00
it ( 'can open WebSQLDatabase in a background page' , async ( ) = > {
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession , sandbox : true } } ) ;
w . loadURL ( 'about:blank' ) ;
await emittedOnce ( w . webContents , 'dom-ready' ) ;
await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'persistent-background-page' ) ) ;
const args : any = await emittedOnce ( app , 'web-contents-created' ) ;
const wc : Electron.WebContents = args [ 1 ] ;
await expect ( wc . executeJavaScript ( '(()=>{try{openDatabase("t", "1.0", "test", 2e5);return true;}catch(e){throw e}})()' ) ) . to . not . be . rejected ( ) ;
} ) ;
2020-08-03 23:56:18 +00:00
function fetch ( contents : WebContents , url : string ) {
return contents . executeJavaScript ( ` fetch( ${ JSON . stringify ( url ) } ) ` ) ;
}
it ( 'bypasses CORS in requests made from extensions' , async ( ) = > {
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession , sandbox : true } } ) ;
const extension = await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'ui-page' ) ) ;
w . loadURL ( ` ${ extension . url } bare-page.html ` ) ;
await emittedOnce ( w . webContents , 'dom-ready' ) ;
await expect ( fetch ( w . webContents , ` ${ url } /cors ` ) ) . to . not . be . rejectedWith ( TypeError ) ;
} ) ;
2019-07-24 23:01:08 +00:00
it ( 'loads an extension' , async ( ) = > {
// NB. we have to use a persist: session (i.e. non-OTR) because the
// extension registry is redirected to the main session. so installing an
// extension in an in-memory session results in it being installed in the
// default session.
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'red-bg' ) ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession } } ) ;
2020-06-03 07:56:28 +00:00
w . loadURL ( url ) ;
await emittedOnce ( w . webContents , 'dom-ready' ) ;
2020-03-20 20:28:31 +00:00
const bg = await w . webContents . executeJavaScript ( 'document.documentElement.style.backgroundColor' ) ;
expect ( bg ) . to . equal ( 'red' ) ;
} ) ;
2019-07-24 23:01:08 +00:00
2020-02-24 03:30:32 +00:00
it ( 'serializes a loaded extension' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const extensionPath = path . join ( fixtures , 'extensions' , 'red-bg' ) ;
const manifest = JSON . parse ( fs . readFileSync ( path . join ( extensionPath , 'manifest.json' ) , 'utf-8' ) ) ;
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
const extension = await customSession . loadExtension ( extensionPath ) ;
expect ( extension . id ) . to . be . a ( 'string' ) ;
expect ( extension . name ) . to . be . a ( 'string' ) ;
expect ( extension . path ) . to . be . a ( 'string' ) ;
expect ( extension . version ) . to . be . a ( 'string' ) ;
expect ( extension . url ) . to . be . a ( 'string' ) ;
expect ( extension . manifest ) . to . deep . equal ( manifest ) ;
} ) ;
2020-02-24 03:30:32 +00:00
2020-01-13 22:56:28 +00:00
it ( 'removes an extension' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
const { id } = await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'red-bg' ) ) ;
2020-01-13 22:56:28 +00:00
{
2020-03-20 20:28:31 +00:00
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession } } ) ;
await w . loadURL ( url ) ;
const bg = await w . webContents . executeJavaScript ( 'document.documentElement.style.backgroundColor' ) ;
expect ( bg ) . to . equal ( 'red' ) ;
2020-01-13 22:56:28 +00:00
}
2020-03-20 20:28:31 +00:00
customSession . removeExtension ( id ) ;
2020-01-13 22:56:28 +00:00
{
2020-03-20 20:28:31 +00:00
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession } } ) ;
await w . loadURL ( url ) ;
const bg = await w . webContents . executeJavaScript ( 'document.documentElement.style.backgroundColor' ) ;
expect ( bg ) . to . equal ( '' ) ;
2020-01-13 22:56:28 +00:00
}
2020-03-20 20:28:31 +00:00
} ) ;
2020-01-13 22:56:28 +00:00
it ( 'lists loaded extensions in getAllExtensions' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
const e = await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'red-bg' ) ) ;
expect ( customSession . getAllExtensions ( ) ) . to . deep . equal ( [ e ] ) ;
customSession . removeExtension ( e . id ) ;
expect ( customSession . getAllExtensions ( ) ) . to . deep . equal ( [ ] ) ;
} ) ;
2020-01-13 22:56:28 +00:00
it ( 'gets an extension by id' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
const e = await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'red-bg' ) ) ;
expect ( customSession . getExtension ( e . id ) ) . to . deep . equal ( e ) ;
} ) ;
2020-01-13 22:56:28 +00:00
2019-07-24 23:01:08 +00:00
it ( 'confines an extension to the session it was loaded in' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'red-bg' ) ) ;
const w = new BrowserWindow ( { show : false } ) ; // not in the session
2020-06-03 07:56:28 +00:00
w . loadURL ( url ) ;
await emittedOnce ( w . webContents , 'dom-ready' ) ;
2020-03-20 20:28:31 +00:00
const bg = await w . webContents . executeJavaScript ( 'document.documentElement.style.backgroundColor' ) ;
expect ( bg ) . to . equal ( '' ) ;
} ) ;
2019-07-24 23:01:08 +00:00
2020-02-10 16:28:03 +00:00
it ( 'loading an extension in a temporary session throws an error' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( require ( 'uuid' ) . v4 ( ) ) ;
await expect ( customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'red-bg' ) ) ) . to . eventually . be . rejectedWith ( 'Extensions cannot be loaded in a temporary session' ) ;
} ) ;
2020-02-10 16:28:03 +00:00
2020-03-05 14:56:21 +00:00
describe ( 'chrome.i18n' , ( ) = > {
2020-03-20 20:28:31 +00:00
let w : BrowserWindow ;
let extension : Extension ;
2020-03-05 14:56:21 +00:00
const exec = async ( name : string ) = > {
2020-03-20 20:28:31 +00:00
const p = emittedOnce ( ipcMain , 'success' ) ;
await w . webContents . executeJavaScript ( ` exec(' ${ name } ') ` ) ;
const [ , result ] = await p ;
return result ;
} ;
2020-03-05 14:56:21 +00:00
beforeEach ( async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
extension = await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'chrome-i18n' ) ) ;
w = new BrowserWindow ( { show : false , webPreferences : { session : customSession , nodeIntegration : true } } ) ;
2020-06-03 07:56:28 +00:00
w . loadURL ( url ) ;
await emittedOnce ( w . webContents , 'dom-ready' ) ;
2020-03-20 20:28:31 +00:00
} ) ;
2020-03-05 14:56:21 +00:00
it ( 'getAcceptLanguages()' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const result = await exec ( 'getAcceptLanguages' ) ;
expect ( result ) . to . be . an ( 'array' ) . and . deep . equal ( [ 'en-US' ] ) ;
} ) ;
2020-03-05 14:56:21 +00:00
it ( 'getMessage()' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const result = await exec ( 'getMessage' ) ;
expect ( result . id ) . to . be . a ( 'string' ) . and . equal ( extension . id ) ;
expect ( result . name ) . to . be . a ( 'string' ) . and . equal ( 'chrome-i18n' ) ;
} ) ;
} ) ;
2020-03-05 14:56:21 +00:00
2019-07-24 23:01:08 +00:00
describe ( 'chrome.runtime' , ( ) = > {
2020-03-20 20:28:31 +00:00
let content : any ;
2019-07-24 23:01:08 +00:00
before ( async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
2020-06-03 07:56:28 +00:00
await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'chrome-runtime' ) ) ;
2020-03-20 20:28:31 +00:00
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession } } ) ;
2019-07-24 23:01:08 +00:00
try {
2020-06-03 07:56:28 +00:00
w . loadURL ( url ) ;
await emittedOnce ( w . webContents , 'dom-ready' ) ;
2020-03-20 20:28:31 +00:00
content = JSON . parse ( await w . webContents . executeJavaScript ( 'document.documentElement.textContent' ) ) ;
expect ( content ) . to . be . an ( 'object' ) ;
2019-07-24 23:01:08 +00:00
} finally {
2020-03-20 20:28:31 +00:00
w . destroy ( ) ;
2019-07-24 23:01:08 +00:00
}
2020-03-20 20:28:31 +00:00
} ) ;
2019-07-24 23:01:08 +00:00
it ( 'getManifest()' , ( ) = > {
2020-03-20 20:28:31 +00:00
expect ( content . manifest ) . to . be . an ( 'object' ) . with . property ( 'name' , 'chrome-runtime' ) ;
} ) ;
2019-07-24 23:01:08 +00:00
it ( 'id' , ( ) = > {
2020-03-20 20:28:31 +00:00
expect ( content . id ) . to . be . a ( 'string' ) . with . lengthOf ( 32 ) ;
} ) ;
2019-07-24 23:01:08 +00:00
it ( 'getURL()' , ( ) = > {
2020-03-20 20:28:31 +00:00
expect ( content . url ) . to . be . a ( 'string' ) . and . match ( /^chrome-extension:\/\/.*main.js$/ ) ;
} ) ;
} ) ;
2019-07-24 23:01:08 +00:00
describe ( 'chrome.storage' , ( ) = > {
it ( 'stores and retrieves a key' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'chrome-storage' ) ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession , nodeIntegration : true } } ) ;
2019-07-24 23:01:08 +00:00
try {
2020-03-20 20:28:31 +00:00
const p = emittedOnce ( ipcMain , 'storage-success' ) ;
await w . loadURL ( url ) ;
const [ , v ] = await p ;
expect ( v ) . to . equal ( 'value' ) ;
2019-07-24 23:01:08 +00:00
} finally {
2020-03-20 20:28:31 +00:00
w . destroy ( ) ;
2019-07-24 23:01:08 +00:00
}
2020-03-20 20:28:31 +00:00
} ) ;
} ) ;
2020-01-13 22:55:58 +00:00
2020-01-15 23:11:51 +00:00
describe ( 'chrome.tabs' , ( ) = > {
it ( 'executeScript' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'chrome-api' ) ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession , nodeIntegration : true } } ) ;
await w . loadURL ( url ) ;
2020-01-15 23:11:51 +00:00
2020-03-20 20:28:31 +00:00
const message = { method : 'executeScript' , args : [ '1 + 2' ] } ;
w . webContents . executeJavaScript ( ` window.postMessage(' ${ JSON . stringify ( message ) } ', '*') ` ) ;
2020-01-15 23:11:51 +00:00
2020-03-20 20:28:31 +00:00
const [ , , responseString ] = await emittedOnce ( w . webContents , 'console-message' ) ;
const response = JSON . parse ( responseString ) ;
2020-01-15 23:11:51 +00:00
2020-03-20 20:28:31 +00:00
expect ( response ) . to . equal ( 3 ) ;
} ) ;
2020-01-15 23:11:51 +00:00
2020-03-05 14:59:32 +00:00
it ( 'connect' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'chrome-api' ) ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession , nodeIntegration : true } } ) ;
await w . loadURL ( url ) ;
2020-03-05 14:59:32 +00:00
2020-03-20 20:28:31 +00:00
const portName = require ( 'uuid' ) . v4 ( ) ;
const message = { method : 'connectTab' , args : [ portName ] } ;
w . webContents . executeJavaScript ( ` window.postMessage(' ${ JSON . stringify ( message ) } ', '*') ` ) ;
2020-03-05 14:59:32 +00:00
2020-03-20 20:28:31 +00:00
const [ , , responseString ] = await emittedOnce ( w . webContents , 'console-message' ) ;
const response = responseString . split ( ',' ) ;
expect ( response [ 0 ] ) . to . equal ( portName ) ;
expect ( response [ 1 ] ) . to . equal ( 'howdy' ) ;
} ) ;
2020-03-05 14:59:32 +00:00
2020-01-15 23:11:51 +00:00
it ( 'sendMessage receives the response' , async function ( ) {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'chrome-api' ) ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession , nodeIntegration : true } } ) ;
await w . loadURL ( url ) ;
2020-01-15 23:11:51 +00:00
2020-03-20 20:28:31 +00:00
const message = { method : 'sendMessage' , args : [ 'Hello World!' ] } ;
w . webContents . executeJavaScript ( ` window.postMessage(' ${ JSON . stringify ( message ) } ', '*') ` ) ;
2020-01-15 23:11:51 +00:00
2020-03-20 20:28:31 +00:00
const [ , , responseString ] = await emittedOnce ( w . webContents , 'console-message' ) ;
const response = JSON . parse ( responseString ) ;
2020-01-15 23:11:51 +00:00
2020-03-20 20:28:31 +00:00
expect ( response . message ) . to . equal ( 'Hello World!' ) ;
expect ( response . tabId ) . to . equal ( w . webContents . id ) ;
} ) ;
} ) ;
2020-01-15 23:11:51 +00:00
2020-01-13 22:55:58 +00:00
describe ( 'background pages' , ( ) = > {
it ( 'loads a lazy background page when sending a message' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'lazy-background-page' ) ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession , nodeIntegration : true } } ) ;
2020-01-13 22:55:58 +00:00
try {
2020-03-20 20:28:31 +00:00
w . loadURL ( url ) ;
const [ , resp ] = await emittedOnce ( ipcMain , 'bg-page-message-response' ) ;
expect ( resp . message ) . to . deep . equal ( { some : 'message' } ) ;
expect ( resp . sender . id ) . to . be . a ( 'string' ) ;
expect ( resp . sender . origin ) . to . equal ( url ) ;
expect ( resp . sender . url ) . to . equal ( url + '/' ) ;
2020-01-13 22:55:58 +00:00
} finally {
2020-03-20 20:28:31 +00:00
w . destroy ( ) ;
2020-01-13 22:55:58 +00:00
}
2020-03-20 20:28:31 +00:00
} ) ;
2020-02-06 21:42:34 +00:00
it ( 'can use extension.getBackgroundPage from a ui page' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
const { id } = await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'lazy-background-page' ) ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession } } ) ;
await w . loadURL ( ` chrome-extension:// ${ id } /page-get-background.html ` ) ;
const receivedMessage = await w . webContents . executeJavaScript ( 'window.completionPromise' ) ;
expect ( receivedMessage ) . to . deep . equal ( { some : 'message' } ) ;
} ) ;
2020-02-06 21:42:34 +00:00
it ( 'can use extension.getBackgroundPage from a ui page' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
const { id } = await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'lazy-background-page' ) ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession } } ) ;
await w . loadURL ( ` chrome-extension:// ${ id } /page-get-background.html ` ) ;
const receivedMessage = await w . webContents . executeJavaScript ( 'window.completionPromise' ) ;
expect ( receivedMessage ) . to . deep . equal ( { some : 'message' } ) ;
} ) ;
2020-02-06 21:42:34 +00:00
it ( 'can use runtime.getBackgroundPage from a ui page' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
const { id } = await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'lazy-background-page' ) ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession } } ) ;
await w . loadURL ( ` chrome-extension:// ${ id } /page-runtime-get-background.html ` ) ;
const receivedMessage = await w . webContents . executeJavaScript ( 'window.completionPromise' ) ;
expect ( receivedMessage ) . to . deep . equal ( { some : 'message' } ) ;
} ) ;
} ) ;
2020-01-15 00:20:30 +00:00
2020-06-11 03:57:51 +00:00
it ( 'has session in background page' , async ( ) = > {
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
await customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'persistent-background-page' ) ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { session : customSession } } ) ;
const promise = emittedOnce ( app , 'web-contents-created' ) ;
2020-07-09 17:18:49 +00:00
await w . loadURL ( 'about:blank' ) ;
2020-06-11 03:57:51 +00:00
const [ , bgPageContents ] = await promise ;
expect ( bgPageContents . session ) . to . not . equal ( undefined ) ;
} ) ;
2020-01-15 00:20:30 +00:00
describe ( 'devtools extensions' , ( ) = > {
2020-03-20 20:28:31 +00:00
let showPanelTimeoutId : any = null ;
2020-01-15 00:20:30 +00:00
afterEach ( ( ) = > {
2020-03-20 20:28:31 +00:00
if ( showPanelTimeoutId ) clearTimeout ( showPanelTimeoutId ) ;
} ) ;
2020-01-15 00:20:30 +00:00
const showLastDevToolsPanel = ( w : BrowserWindow ) = > {
w . webContents . once ( 'devtools-opened' , ( ) = > {
const show = ( ) = > {
2020-03-20 20:28:31 +00:00
if ( w == null || w . isDestroyed ( ) ) return ;
const { devToolsWebContents } = w as unknown as { devToolsWebContents : WebContents | undefined } ;
2020-01-15 00:20:30 +00:00
if ( devToolsWebContents == null || devToolsWebContents . isDestroyed ( ) ) {
2020-03-20 20:28:31 +00:00
return ;
2020-01-15 00:20:30 +00:00
}
const showLastPanel = ( ) = > {
// this is executed in the devtools context, where UI is a global
2020-03-20 20:28:31 +00:00
const { UI } = ( window as any ) ;
const lastPanelId = UI . inspectorView . _tabbedPane . _tabs . peekLast ( ) . id ;
UI . inspectorView . showPanel ( lastPanelId ) ;
} ;
2020-01-15 00:20:30 +00:00
devToolsWebContents . executeJavaScript ( ` ( ${ showLastPanel } )() ` , false ) . then ( ( ) = > {
2020-03-20 20:28:31 +00:00
showPanelTimeoutId = setTimeout ( show , 100 ) ;
} ) ;
} ;
showPanelTimeoutId = setTimeout ( show , 100 ) ;
} ) ;
} ;
2020-01-15 00:20:30 +00:00
it ( 'loads a devtools extension' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const customSession = session . fromPartition ( ` persist: ${ require ( 'uuid' ) . v4 ( ) } ` ) ;
customSession . loadExtension ( path . join ( fixtures , 'extensions' , 'devtools-extension' ) ) ;
2020-05-26 14:25:57 +00:00
const winningMessage = emittedOnce ( ipcMain , 'winning' ) ;
2020-03-20 20:28:31 +00:00
const w = new BrowserWindow ( { show : true , webPreferences : { session : customSession , nodeIntegration : true } } ) ;
2020-04-13 23:39:26 +00:00
await w . loadURL ( url ) ;
2020-03-20 20:28:31 +00:00
w . webContents . openDevTools ( ) ;
showLastDevToolsPanel ( w ) ;
2020-05-26 14:25:57 +00:00
await winningMessage ;
2020-03-20 20:28:31 +00:00
} ) ;
} ) ;
2020-01-21 17:42:55 +00:00
describe ( 'deprecation shims' , ( ) = > {
it ( 'loads an extension through BrowserWindow.addExtension' , async ( ) = > {
2020-03-20 20:28:31 +00:00
BrowserWindow . addExtension ( path . join ( fixtures , 'extensions' , 'red-bg' ) ) ;
const w = new BrowserWindow ( { show : false } ) ;
await w . loadURL ( url ) ;
const bg = await w . webContents . executeJavaScript ( 'document.documentElement.style.backgroundColor' ) ;
expect ( bg ) . to . equal ( 'red' ) ;
} ) ;
2020-01-21 17:42:55 +00:00
it ( 'loads an extension through BrowserWindow.addDevToolsExtension' , async ( ) = > {
2020-03-20 20:28:31 +00:00
BrowserWindow . addDevToolsExtension ( path . join ( fixtures , 'extensions' , 'red-bg' ) ) ;
const w = new BrowserWindow ( { show : false } ) ;
await w . loadURL ( url ) ;
const bg = await w . webContents . executeJavaScript ( 'document.documentElement.style.backgroundColor' ) ;
expect ( bg ) . to . equal ( 'red' ) ;
} ) ;
2020-01-21 17:42:55 +00:00
it ( 'removes an extension through BrowserWindow.removeExtension' , async ( ) = > {
2020-03-20 20:28:31 +00:00
await ( BrowserWindow . addExtension ( path . join ( fixtures , 'extensions' , 'red-bg' ) ) as any ) ;
BrowserWindow . removeExtension ( 'red-bg' ) ;
const w = new BrowserWindow ( { show : false } ) ;
await w . loadURL ( url ) ;
const bg = await w . webContents . executeJavaScript ( 'document.documentElement.style.backgroundColor' ) ;
expect ( bg ) . to . equal ( '' ) ;
} ) ;
} ) ;
2020-02-03 22:01:10 +00:00
describe ( 'chrome extension content scripts' , ( ) = > {
2020-03-20 20:28:31 +00:00
const fixtures = path . resolve ( __dirname , 'fixtures' ) ;
const extensionPath = path . resolve ( fixtures , 'extensions' ) ;
2020-02-03 22:01:10 +00:00
2020-03-20 20:28:31 +00:00
const addExtension = ( name : string ) = > session . defaultSession . loadExtension ( path . resolve ( extensionPath , name ) ) ;
2020-02-03 22:01:10 +00:00
const removeAllExtensions = ( ) = > {
Object . keys ( session . defaultSession . getAllExtensions ( ) ) . map ( extName = > {
2020-03-20 20:28:31 +00:00
session . defaultSession . removeExtension ( extName ) ;
} ) ;
} ;
2020-02-03 22:01:10 +00:00
2020-03-20 20:28:31 +00:00
let responseIdCounter = 0 ;
2020-02-03 22:01:10 +00:00
const executeJavaScriptInFrame = ( webContents : WebContents , frameRoutingId : number , code : string ) = > {
return new Promise ( resolve = > {
2020-03-20 20:28:31 +00:00
const responseId = responseIdCounter ++ ;
2020-02-03 22:01:10 +00:00
ipcMain . once ( ` executeJavaScriptInFrame_ ${ responseId } ` , ( event , result ) = > {
2020-03-20 20:28:31 +00:00
resolve ( result ) ;
} ) ;
webContents . send ( 'executeJavaScriptInFrame' , frameRoutingId , code , responseId ) ;
} ) ;
} ;
2020-02-03 22:01:10 +00:00
const generateTests = ( sandboxEnabled : boolean , contextIsolationEnabled : boolean ) = > {
describe ( ` with sandbox ${ sandboxEnabled ? 'enabled' : 'disabled' } and context isolation ${ contextIsolationEnabled ? 'enabled' : 'disabled' } ` , ( ) = > {
2020-03-20 20:28:31 +00:00
let w : BrowserWindow ;
2020-02-03 22:01:10 +00:00
describe ( 'supports "run_at" option' , ( ) = > {
beforeEach ( async ( ) = > {
2020-03-20 20:28:31 +00:00
await closeWindow ( w ) ;
2020-02-03 22:01:10 +00:00
w = new BrowserWindow ( {
show : false ,
width : 400 ,
height : 400 ,
webPreferences : {
contextIsolation : contextIsolationEnabled ,
sandbox : sandboxEnabled
}
2020-03-20 20:28:31 +00:00
} ) ;
} ) ;
2020-02-03 22:01:10 +00:00
afterEach ( ( ) = > {
2020-03-20 20:28:31 +00:00
removeAllExtensions ( ) ;
return closeWindow ( w ) . then ( ( ) = > { w = null as unknown as BrowserWindow ; } ) ;
} ) ;
2020-02-03 22:01:10 +00:00
it ( 'should run content script at document_start' , async ( ) = > {
2020-03-20 20:28:31 +00:00
await addExtension ( 'content-script-document-start' ) ;
2020-02-03 22:01:10 +00:00
w . webContents . once ( 'dom-ready' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const result = await w . webContents . executeJavaScript ( 'document.documentElement.style.backgroundColor' ) ;
expect ( result ) . to . equal ( 'red' ) ;
} ) ;
w . loadURL ( url ) ;
} ) ;
2020-02-03 22:01:10 +00:00
it ( 'should run content script at document_idle' , async ( ) = > {
2020-03-20 20:28:31 +00:00
await addExtension ( 'content-script-document-idle' ) ;
w . loadURL ( url ) ;
const result = await w . webContents . executeJavaScript ( 'document.body.style.backgroundColor' ) ;
expect ( result ) . to . equal ( 'red' ) ;
} ) ;
2020-02-03 22:01:10 +00:00
it ( 'should run content script at document_end' , async ( ) = > {
2020-03-20 20:28:31 +00:00
await addExtension ( 'content-script-document-end' ) ;
2020-02-03 22:01:10 +00:00
w . webContents . once ( 'did-finish-load' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const result = await w . webContents . executeJavaScript ( 'document.documentElement.style.backgroundColor' ) ;
expect ( result ) . to . equal ( 'red' ) ;
} ) ;
w . loadURL ( url ) ;
} ) ;
} ) ;
2020-02-03 22:01:10 +00:00
// TODO(nornagon): real extensions don't load on file: urls, so this
// test needs to be updated to serve its content over http.
describe . skip ( 'supports "all_frames" option' , ( ) = > {
2020-03-20 20:28:31 +00:00
const contentScript = path . resolve ( fixtures , 'extensions/content-script' ) ;
2020-02-03 22:01:10 +00:00
// Computed style values
2020-03-20 20:28:31 +00:00
const COLOR_RED = 'rgb(255, 0, 0)' ;
const COLOR_BLUE = 'rgb(0, 0, 255)' ;
const COLOR_TRANSPARENT = 'rgba(0, 0, 0, 0)' ;
2020-02-03 22:01:10 +00:00
before ( ( ) = > {
2020-03-20 20:28:31 +00:00
BrowserWindow . addExtension ( contentScript ) ;
} ) ;
2020-02-03 22:01:10 +00:00
after ( ( ) = > {
2020-03-20 20:28:31 +00:00
BrowserWindow . removeExtension ( 'content-script-test' ) ;
} ) ;
2020-02-03 22:01:10 +00:00
beforeEach ( ( ) = > {
w = new BrowserWindow ( {
show : false ,
webPreferences : {
// enable content script injection in subframes
nodeIntegrationInSubFrames : true ,
preload : path.join ( contentScript , 'all_frames-preload.js' )
}
2020-03-20 20:28:31 +00:00
} ) ;
} ) ;
2020-02-03 22:01:10 +00:00
afterEach ( ( ) = >
closeWindow ( w ) . then ( ( ) = > {
2020-03-20 20:28:31 +00:00
w = null as unknown as BrowserWindow ;
2020-02-03 22:01:10 +00:00
} )
2020-03-20 20:28:31 +00:00
) ;
2020-02-03 22:01:10 +00:00
it ( 'applies matching rules in subframes' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const detailsPromise = emittedNTimes ( w . webContents , 'did-frame-finish-load' , 2 ) ;
w . loadFile ( path . join ( contentScript , 'frame-with-frame.html' ) ) ;
const frameEvents = await detailsPromise ;
2020-02-03 22:01:10 +00:00
await Promise . all (
frameEvents . map ( async frameEvent = > {
2020-03-20 20:28:31 +00:00
const [ , isMainFrame , , frameRoutingId ] = frameEvent ;
2020-02-03 22:01:10 +00:00
const result : any = await executeJavaScriptInFrame (
w . webContents ,
frameRoutingId ,
` (() => {
const a = document . getElementById ( 'all_frames_enabled' )
const b = document . getElementById ( 'all_frames_disabled' )
return {
enabledColor : getComputedStyle ( a ) . backgroundColor ,
disabledColor : getComputedStyle ( b ) . backgroundColor
}
} ) ( ) `
2020-03-20 20:28:31 +00:00
) ;
expect ( result . enabledColor ) . to . equal ( COLOR_RED ) ;
2020-02-03 22:01:10 +00:00
if ( isMainFrame ) {
2020-03-20 20:28:31 +00:00
expect ( result . disabledColor ) . to . equal ( COLOR_BLUE ) ;
2020-02-03 22:01:10 +00:00
} else {
2020-03-20 20:28:31 +00:00
expect ( result . disabledColor ) . to . equal ( COLOR_TRANSPARENT ) ; // null color
2020-02-03 22:01:10 +00:00
}
} )
2020-03-20 20:28:31 +00:00
) ;
} ) ;
} ) ;
} ) ;
} ;
generateTests ( false , false ) ;
generateTests ( false , true ) ;
generateTests ( true , false ) ;
generateTests ( true , true ) ;
} ) ;
2020-02-06 21:42:34 +00:00
describe ( 'extension ui pages' , ( ) = > {
afterEach ( ( ) = > {
session . defaultSession . getAllExtensions ( ) . forEach ( e = > {
2020-03-20 20:28:31 +00:00
session . defaultSession . removeExtension ( e . id ) ;
} ) ;
} ) ;
2020-02-06 21:42:34 +00:00
it ( 'loads a ui page of an extension' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const { id } = await session . defaultSession . loadExtension ( path . join ( fixtures , 'extensions' , 'ui-page' ) ) ;
const w = new BrowserWindow ( { show : false } ) ;
2020-06-03 07:56:28 +00:00
w . loadURL ( ` chrome-extension:// ${ id } /bare-page.html ` ) ;
await emittedOnce ( w . webContents , 'dom-ready' ) ;
2020-03-20 20:28:31 +00:00
const textContent = await w . webContents . executeJavaScript ( 'document.body.textContent' ) ;
expect ( textContent ) . to . equal ( 'ui page loaded ok\n' ) ;
} ) ;
2020-02-06 21:42:34 +00:00
it ( 'can load resources' , async ( ) = > {
2020-03-20 20:28:31 +00:00
const { id } = await session . defaultSession . loadExtension ( path . join ( fixtures , 'extensions' , 'ui-page' ) ) ;
const w = new BrowserWindow ( { show : false } ) ;
2020-06-03 07:56:28 +00:00
w . loadURL ( ` chrome-extension:// ${ id } /page-script-load.html ` ) ;
await emittedOnce ( w . webContents , 'dom-ready' ) ;
2020-03-20 20:28:31 +00:00
const textContent = await w . webContents . executeJavaScript ( 'document.body.textContent' ) ;
expect ( textContent ) . to . equal ( 'script loaded ok\n' ) ;
} ) ;
} ) ;
} ) ;