2019-11-07 00:15:55 +00:00
import { expect } from 'chai' ;
2023-06-15 14:42:27 +00:00
import * as childProcess from 'node:child_process' ;
import * as path from 'node:path' ;
import * as fs from 'node:fs' ;
import * as qs from 'node:querystring' ;
import * as http from 'node:http' ;
import * as os from 'node:os' ;
import { AddressInfo } from 'node:net' ;
2023-03-28 14:55:41 +00:00
import { app , BrowserWindow , BrowserView , dialog , ipcMain , OnBeforeSendHeadersListenerDetails , protocol , screen , webContents , webFrameMain , session , WebContents , WebFrameMain } from 'electron/main' ;
2019-08-07 07:17:32 +00:00
2023-02-23 23:53:53 +00:00
import { emittedUntil , emittedNTimes } from './lib/events-helpers' ;
import { ifit , ifdescribe , defer , listen } from './lib/spec-helpers' ;
2023-01-25 21:01:25 +00:00
import { closeWindow , closeAllWindows } from './lib/window-helpers' ;
2024-02-28 03:54:20 +00:00
import { HexColors , hasCapturableScreen , ScreenCapture } from './lib/screen-helpers' ;
2023-06-15 14:42:27 +00:00
import { once } from 'node:events' ;
import { setTimeout } from 'node:timers/promises' ;
2024-01-26 18:53:07 +00:00
import { setTimeout as syncSetTimeout } from 'node:timers' ;
2019-06-03 22:10:58 +00:00
2022-08-16 19:23:13 +00:00
const fixtures = path . resolve ( __dirname , 'fixtures' ) ;
2022-01-06 17:28:03 +00:00
const mainFixtures = path . resolve ( __dirname , 'fixtures' ) ;
2019-06-03 22:10:58 +00:00
2019-06-19 23:38:21 +00:00
// Is the display's scale factor possibly causing rounding of pixel coordinate
// values?
const isScaleFactorRounding = ( ) = > {
const { scaleFactor } = screen . getPrimaryDisplay ( ) ;
// Return true if scale factor is non-integer value
if ( Math . round ( scaleFactor ) !== scaleFactor ) return true ;
// Return true if scale factor is odd number above 2
return scaleFactor > 2 && scaleFactor % 2 === 1 ;
} ;
const expectBoundsEqual = ( actual : any , expected : any ) = > {
if ( ! isScaleFactorRounding ( ) ) {
2024-04-08 17:30:23 +00:00
expect ( actual ) . to . deep . equal ( expected ) ;
2019-06-19 23:38:21 +00:00
} else if ( Array . isArray ( actual ) ) {
expect ( actual [ 0 ] ) . to . be . closeTo ( expected [ 0 ] , 1 ) ;
expect ( actual [ 1 ] ) . to . be . closeTo ( expected [ 1 ] , 1 ) ;
} else {
expect ( actual . x ) . to . be . closeTo ( expected . x , 1 ) ;
expect ( actual . y ) . to . be . closeTo ( expected . y , 1 ) ;
expect ( actual . width ) . to . be . closeTo ( expected . width , 1 ) ;
expect ( actual . height ) . to . be . closeTo ( expected . height , 1 ) ;
}
} ;
2020-05-26 13:21:38 +00:00
const isBeforeUnload = ( event : Event , level : number , message : string ) = > {
return ( message === 'beforeunload' ) ;
} ;
2019-06-03 22:10:58 +00:00
describe ( 'BrowserWindow module' , ( ) = > {
2023-07-10 09:49:20 +00:00
it ( 'sets the correct class name on the prototype' , ( ) = > {
expect ( BrowserWindow . prototype . constructor . name ) . to . equal ( 'BrowserWindow' ) ;
} ) ;
2019-06-03 22:10:58 +00:00
describe ( 'BrowserWindow constructor' , ( ) = > {
it ( 'allows passing void 0 as the webContents' , async ( ) = > {
expect ( ( ) = > {
const w = new BrowserWindow ( {
show : false ,
// apparently void 0 had different behaviour from undefined in the
// issue that this test is supposed to catch.
2020-03-20 15:12:18 +00:00
webContents : void 0 // eslint-disable-line no-void
2019-06-03 22:10:58 +00:00
} as any ) ;
w . destroy ( ) ;
} ) . not . to . throw ( ) ;
} ) ;
2020-06-01 20:34:34 +00:00
ifit ( process . platform === 'linux' ) ( 'does not crash when setting large window icons' , async ( ) = > {
2022-08-16 19:23:13 +00:00
const appPath = path . join ( fixtures , 'apps' , 'xwindow-icon' ) ;
2020-06-01 20:34:34 +00:00
const appProcess = childProcess . spawn ( process . execPath , [ appPath ] ) ;
2023-02-23 23:53:53 +00:00
await once ( appProcess , 'exit' ) ;
2020-06-01 20:34:34 +00:00
} ) ;
2021-01-25 01:24:10 +00:00
it ( 'does not crash or throw when passed an invalid icon' , async ( ) = > {
expect ( ( ) = > {
const w = new BrowserWindow ( {
icon : undefined
} as any ) ;
w . destroy ( ) ;
} ) . not . to . throw ( ) ;
} ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-02-11 00:37:46 +00:00
describe ( 'garbage collection' , ( ) = > {
2020-06-23 03:32:45 +00:00
const v8Util = process . _linkedBinding ( 'electron_common_v8_util' ) ;
2020-02-11 00:37:46 +00:00
afterEach ( closeAllWindows ) ;
2020-06-30 22:10:36 +00:00
it ( 'window does not get garbage collected when opened' , async ( ) = > {
2020-02-11 00:37:46 +00:00
const w = new BrowserWindow ( { show : false } ) ;
// Keep a weak reference to the window.
2021-01-22 19:25:47 +00:00
const wr = new WeakRef ( w ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2020-06-30 22:10:36 +00:00
// Do garbage collection, since |w| is not referenced in this closure
// it would be gone after next call if there is no other reference.
v8Util . requestGarbageCollectionForTesting ( ) ;
2020-02-11 00:37:46 +00:00
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2020-06-30 22:10:36 +00:00
expect ( wr . deref ( ) ) . to . not . be . undefined ( ) ;
2020-02-11 00:37:46 +00:00
} ) ;
} ) ;
2019-06-03 22:10:58 +00:00
describe ( 'BrowserWindow.close()' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-06-03 22:10:58 +00:00
beforeEach ( ( ) = > {
2021-03-01 21:52:29 +00:00
w = new BrowserWindow ( { show : false , webPreferences : { nodeIntegration : true , contextIsolation : false } } ) ;
2019-06-03 22:10:58 +00:00
} ) ;
afterEach ( async ( ) = > {
await closeWindow ( w ) ;
w = null as unknown as BrowserWindow ;
} ) ;
2021-05-04 10:11:16 +00:00
it ( 'should work if called when a messageBox is showing' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const closed = once ( w , 'closed' ) ;
2021-05-04 10:11:16 +00:00
dialog . showMessageBox ( w , { message : 'Hello Error' } ) ;
w . close ( ) ;
await closed ;
} ) ;
2022-01-25 14:51:53 +00:00
it ( 'closes window without rounded corners' , async ( ) = > {
await closeWindow ( w ) ;
w = new BrowserWindow ( { show : false , frame : false , roundedCorners : false } ) ;
2023-02-23 23:53:53 +00:00
const closed = once ( w , 'closed' ) ;
2022-01-25 14:51:53 +00:00
w . close ( ) ;
await closed ;
} ) ;
2021-11-01 04:32:54 +00:00
it ( 'should not crash if called after webContents is destroyed' , ( ) = > {
w . webContents . destroy ( ) ;
w . webContents . on ( 'destroyed' , ( ) = > w . close ( ) ) ;
} ) ;
2023-05-16 07:29:00 +00:00
it ( 'should allow access to id after destruction' , async ( ) = > {
const closed = once ( w , 'closed' ) ;
w . destroy ( ) ;
await closed ;
expect ( w . id ) . to . be . a ( 'number' ) ;
} ) ;
2019-06-03 22:10:58 +00:00
it ( 'should emit unload handler' , async ( ) = > {
await w . loadFile ( path . join ( fixtures , 'api' , 'unload.html' ) ) ;
2023-02-23 23:53:53 +00:00
const closed = once ( w , 'closed' ) ;
2019-06-03 22:10:58 +00:00
w . close ( ) ;
await closed ;
const test = path . join ( fixtures , 'api' , 'unload' ) ;
const content = fs . readFileSync ( test ) ;
fs . unlinkSync ( test ) ;
expect ( String ( content ) ) . to . equal ( 'unload' ) ;
} ) ;
2020-05-26 13:21:38 +00:00
2019-06-03 22:10:58 +00:00
it ( 'should emit beforeunload handler' , async ( ) = > {
2020-06-02 02:32:39 +00:00
await w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'beforeunload-false.html' ) ) ;
2019-06-03 22:10:58 +00:00
w . close ( ) ;
2023-12-13 21:01:03 +00:00
await once ( w . webContents , '-before-unload-fired' ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2021-01-19 02:37:21 +00:00
it ( 'should not crash when keyboard event is sent before closing' , async ( ) = > {
await w . loadURL ( 'data:text/html,pls no crash' ) ;
2023-02-23 23:53:53 +00:00
const closed = once ( w , 'closed' ) ;
2021-01-19 02:37:21 +00:00
w . webContents . sendInputEvent ( { type : 'keyDown' , keyCode : 'Escape' } ) ;
w . close ( ) ;
await closed ;
} ) ;
2019-06-03 22:10:58 +00:00
describe ( 'when invoked synchronously inside navigation observer' , ( ) = > {
2023-02-19 09:24:24 +00:00
let server : http.Server ;
let url : string ;
2019-06-03 22:10:58 +00:00
2023-02-20 11:30:57 +00:00
before ( async ( ) = > {
2019-06-03 22:10:58 +00:00
server = http . createServer ( ( request , response ) = > {
switch ( request . url ) {
case '/net-error' :
response . destroy ( ) ;
break ;
case '/301' :
response . statusCode = 301 ;
response . setHeader ( 'Location' , '/200' ) ;
response . end ( ) ;
break ;
case '/200' :
response . statusCode = 200 ;
response . end ( 'hello' ) ;
break ;
case '/title' :
response . statusCode = 200 ;
response . end ( '<title>Hello</title>' ) ;
break ;
default :
throw new Error ( ` unsupported endpoint: ${ request . url } ` ) ;
}
} ) ;
2023-02-20 11:30:57 +00:00
url = ( await listen ( server ) ) . url ;
2019-06-03 22:10:58 +00:00
} ) ;
after ( ( ) = > {
server . close ( ) ;
} ) ;
const events = [
{ name : 'did-start-loading' , path : '/200' } ,
{ name : 'dom-ready' , path : '/200' } ,
{ name : 'page-title-updated' , path : '/title' } ,
{ name : 'did-stop-loading' , path : '/200' } ,
{ name : 'did-finish-load' , path : '/200' } ,
{ name : 'did-frame-finish-load' , path : '/200' } ,
{ name : 'did-fail-load' , path : '/net-error' }
] ;
2019-11-01 20:37:02 +00:00
for ( const { name , path } of events ) {
2019-06-03 22:10:58 +00:00
it ( ` should not crash when closed during ${ name } ` , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . webContents . once ( ( name as any ) , ( ) = > {
w . close ( ) ;
} ) ;
2023-02-23 23:53:53 +00:00
const destroyed = once ( w . webContents , 'destroyed' ) ;
2019-06-03 22:10:58 +00:00
w . webContents . loadURL ( url + path ) ;
await destroyed ;
} ) ;
}
} ) ;
} ) ;
describe ( 'window.close()' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-06-03 22:10:58 +00:00
beforeEach ( ( ) = > {
2021-03-01 21:52:29 +00:00
w = new BrowserWindow ( { show : false , webPreferences : { nodeIntegration : true , contextIsolation : false } } ) ;
2019-06-03 22:10:58 +00:00
} ) ;
afterEach ( async ( ) = > {
await closeWindow ( w ) ;
w = null as unknown as BrowserWindow ;
} ) ;
it ( 'should emit unload event' , async ( ) = > {
w . loadFile ( path . join ( fixtures , 'api' , 'close.html' ) ) ;
2023-02-23 23:53:53 +00:00
await once ( w , 'closed' ) ;
2019-06-03 22:10:58 +00:00
const test = path . join ( fixtures , 'api' , 'close' ) ;
const content = fs . readFileSync ( test ) . toString ( ) ;
fs . unlinkSync ( test ) ;
expect ( content ) . to . equal ( 'close' ) ;
} ) ;
2020-05-26 13:21:38 +00:00
2020-05-19 02:06:19 +00:00
it ( 'should emit beforeunload event' , async function ( ) {
2020-06-02 02:32:39 +00:00
await w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'beforeunload-false.html' ) ) ;
2020-05-26 13:21:38 +00:00
w . webContents . executeJavaScript ( 'window.close()' , true ) ;
2023-12-13 21:01:03 +00:00
await once ( w . webContents , '-before-unload-fired' ) ;
2019-06-03 22:10:58 +00:00
} ) ;
} ) ;
describe ( 'BrowserWindow.destroy()' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-06-03 22:10:58 +00:00
beforeEach ( ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false , webPreferences : { nodeIntegration : true } } ) ;
2019-06-03 22:10:58 +00:00
} ) ;
afterEach ( async ( ) = > {
await closeWindow ( w ) ;
w = null as unknown as BrowserWindow ;
} ) ;
it ( 'prevents users to access methods of webContents' , async ( ) = > {
const contents = w . webContents ;
w . destroy ( ) ;
await new Promise ( setImmediate ) ;
expect ( ( ) = > {
contents . getProcessId ( ) ;
} ) . to . throw ( 'Object has been destroyed' ) ;
} ) ;
it ( 'should not crash when destroying windows with pending events' , ( ) = > {
2020-03-05 22:22:12 +00:00
const focusListener = ( ) = > { } ;
2019-06-03 22:10:58 +00:00
app . on ( 'browser-window-focus' , focusListener ) ;
const windowCount = 3 ;
const windowOptions = {
show : false ,
width : 400 ,
height : 400 ,
webPreferences : {
backgroundThrottling : false
}
} ;
2019-11-01 20:37:02 +00:00
const windows = Array . from ( Array ( windowCount ) ) . map ( ( ) = > new BrowserWindow ( windowOptions ) ) ;
2023-08-31 14:36:43 +00:00
for ( const win of windows ) win . show ( ) ;
for ( const win of windows ) win . focus ( ) ;
for ( const win of windows ) win . destroy ( ) ;
2019-06-03 22:10:58 +00:00
app . removeListener ( 'browser-window-focus' , focusListener ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.loadURL(url)' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-07-03 01:22:09 +00:00
const scheme = 'other' ;
const srcPath = path . join ( fixtures , 'api' , 'loaded-from-dataurl.js' ) ;
2020-06-02 16:46:18 +00:00
before ( ( ) = > {
2019-07-03 01:22:09 +00:00
protocol . registerFileProtocol ( scheme , ( request , callback ) = > {
callback ( srcPath ) ;
2020-06-02 16:46:18 +00:00
} ) ;
2019-07-03 01:22:09 +00:00
} ) ;
after ( ( ) = > {
protocol . unregisterProtocol ( scheme ) ;
} ) ;
2019-06-03 22:10:58 +00:00
beforeEach ( ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false , webPreferences : { nodeIntegration : true } } ) ;
2019-06-03 22:10:58 +00:00
} ) ;
afterEach ( async ( ) = > {
await closeWindow ( w ) ;
w = null as unknown as BrowserWindow ;
} ) ;
2023-02-19 09:24:24 +00:00
let server : http.Server ;
let url : string ;
2019-06-03 22:10:58 +00:00
let postData = null as any ;
2023-02-20 11:30:57 +00:00
before ( async ( ) = > {
2019-06-03 22:10:58 +00:00
const filePath = path . join ( fixtures , 'pages' , 'a.html' ) ;
const fileStats = fs . statSync ( filePath ) ;
postData = [
{
type : 'rawData' ,
bytes : Buffer.from ( 'username=test&file=' )
} ,
{
type : 'file' ,
filePath : filePath ,
offset : 0 ,
length : fileStats.size ,
modificationTime : fileStats.mtime.getTime ( ) / 1000
}
] ;
server = http . createServer ( ( req , res ) = > {
function respond ( ) {
if ( req . method === 'POST' ) {
let body = '' ;
req . on ( 'data' , ( data ) = > {
if ( data ) body += data ;
} ) ;
req . on ( 'end' , ( ) = > {
const parsedData = qs . parse ( body ) ;
fs . readFile ( filePath , ( err , data ) = > {
if ( err ) return ;
if ( parsedData . username === 'test' &&
2020-03-05 22:22:12 +00:00
parsedData . file === data . toString ( ) ) {
2019-06-03 22:10:58 +00:00
res . end ( ) ;
}
} ) ;
} ) ;
} else if ( req . url === '/302' ) {
res . setHeader ( 'Location' , '/200' ) ;
res . statusCode = 302 ;
res . end ( ) ;
} else {
res . end ( ) ;
}
}
2023-02-23 23:53:53 +00:00
setTimeout ( req . url && req . url . includes ( 'slow' ) ? 200 : 0 ) . then ( respond ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2023-02-20 11:30:57 +00:00
url = ( await listen ( server ) ) . url ;
2019-06-03 22:10:58 +00:00
} ) ;
after ( ( ) = > {
server . close ( ) ;
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'should emit did-start-loading event' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const didStartLoading = once ( w . webContents , 'did-start-loading' ) ;
2019-06-03 22:10:58 +00:00
w . loadURL ( 'about:blank' ) ;
2020-07-01 19:14:38 +00:00
await didStartLoading ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'should emit ready-to-show event' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const readyToShow = once ( w , 'ready-to-show' ) ;
2019-06-03 22:10:58 +00:00
w . loadURL ( 'about:blank' ) ;
2020-07-01 19:14:38 +00:00
await readyToShow ;
2019-06-03 22:10:58 +00:00
} ) ;
2023-04-04 13:48:51 +00:00
// DISABLED-FIXME(deepak1556): The error code now seems to be `ERR_FAILED`, verify what
2019-12-11 00:22:35 +00:00
// changed and adjust the test.
2023-04-04 13:48:51 +00:00
it ( 'should emit did-fail-load event for files that do not exist' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const didFailLoad = once ( w . webContents , 'did-fail-load' ) ;
2019-06-03 22:10:58 +00:00
w . loadURL ( 'file://a.txt' ) ;
2020-06-30 22:10:36 +00:00
const [ , code , desc , , isMainFrame ] = await didFailLoad ;
expect ( code ) . to . equal ( - 6 ) ;
expect ( desc ) . to . equal ( 'ERR_FILE_NOT_FOUND' ) ;
expect ( isMainFrame ) . to . equal ( true ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'should emit did-fail-load event for invalid URL' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const didFailLoad = once ( w . webContents , 'did-fail-load' ) ;
2019-06-03 22:10:58 +00:00
w . loadURL ( 'http://example:port' ) ;
2020-06-30 22:10:36 +00:00
const [ , code , desc , , isMainFrame ] = await didFailLoad ;
expect ( desc ) . to . equal ( 'ERR_INVALID_URL' ) ;
expect ( code ) . to . equal ( - 300 ) ;
expect ( isMainFrame ) . to . equal ( true ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2023-04-06 08:23:34 +00:00
it ( 'should not emit did-fail-load for a successfully loaded media file' , async ( ) = > {
w . webContents . on ( 'did-fail-load' , ( ) = > {
expect . fail ( 'did-fail-load should not emit on media file loads' ) ;
} ) ;
const mediaStarted = once ( w . webContents , 'media-started-playing' ) ;
w . loadFile ( path . join ( fixtures , 'cat-spin.mp4' ) ) ;
await mediaStarted ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'should set `mainFrame = false` on did-fail-load events in iframes' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const didFailLoad = once ( w . webContents , 'did-fail-load' ) ;
2019-06-03 22:10:58 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'did-fail-load-iframe.html' ) ) ;
2020-06-30 22:10:36 +00:00
const [ , , , , isMainFrame ] = await didFailLoad ;
expect ( isMainFrame ) . to . equal ( false ) ;
2019-06-03 22:10:58 +00:00
} ) ;
it ( 'does not crash in did-fail-provisional-load handler' , ( done ) = > {
w . webContents . once ( 'did-fail-provisional-load' , ( ) = > {
w . loadURL ( 'http://127.0.0.1:11111' ) ;
done ( ) ;
} ) ;
w . loadURL ( 'http://127.0.0.1:11111' ) ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'should emit did-fail-load event for URL exceeding character limit' , async ( ) = > {
2019-06-03 22:10:58 +00:00
const data = Buffer . alloc ( 2 * 1024 * 1024 ) . toString ( 'base64' ) ;
2023-02-23 23:53:53 +00:00
const didFailLoad = once ( w . webContents , 'did-fail-load' ) ;
2019-06-03 22:10:58 +00:00
w . loadURL ( ` data:image/png;base64, ${ data } ` ) ;
2020-06-30 22:10:36 +00:00
const [ , code , desc , , isMainFrame ] = await didFailLoad ;
expect ( desc ) . to . equal ( 'ERR_INVALID_URL' ) ;
expect ( code ) . to . equal ( - 300 ) ;
expect ( isMainFrame ) . to . equal ( true ) ;
2019-06-03 22:10:58 +00:00
} ) ;
it ( 'should return a promise' , ( ) = > {
const p = w . loadURL ( 'about:blank' ) ;
expect ( p ) . to . have . property ( 'then' ) ;
} ) ;
it ( 'should return a promise that resolves' , async ( ) = > {
2019-10-18 23:23:33 +00:00
await expect ( w . loadURL ( 'about:blank' ) ) . to . eventually . be . fulfilled ( ) ;
2019-06-03 22:10:58 +00:00
} ) ;
it ( 'should return a promise that rejects on a load failure' , async ( ) = > {
const data = Buffer . alloc ( 2 * 1024 * 1024 ) . toString ( 'base64' ) ;
const p = w . loadURL ( ` data:image/png;base64, ${ data } ` ) ;
await expect ( p ) . to . eventually . be . rejected ;
} ) ;
it ( 'should return a promise that resolves even if pushState occurs during navigation' , async ( ) = > {
const p = w . loadURL ( 'data:text/html,<script>window.history.pushState({}, "/foo")</script>' ) ;
await expect ( p ) . to . eventually . be . fulfilled ;
} ) ;
2021-06-15 01:55:08 +00:00
describe ( 'POST navigations' , ( ) = > {
2019-06-03 22:10:58 +00:00
afterEach ( ( ) = > { w . webContents . session . webRequest . onBeforeSendHeaders ( null ) ; } ) ;
it ( 'supports specifying POST data' , async ( ) = > {
await w . loadURL ( url , { postData } ) ;
} ) ;
it ( 'sets the content type header on URL encoded forms' , async ( ) = > {
await w . loadURL ( url ) ;
const requestDetails : Promise < OnBeforeSendHeadersListenerDetails > = new Promise ( resolve = > {
2019-11-01 20:37:02 +00:00
w . webContents . session . webRequest . onBeforeSendHeaders ( ( details ) = > {
2019-06-03 22:10:58 +00:00
resolve ( details ) ;
} ) ;
} ) ;
w . webContents . executeJavaScript ( `
form = document . createElement ( 'form' )
document . body . appendChild ( form )
form . method = 'POST'
form . submit ( )
` );
const details = await requestDetails ;
expect ( details . requestHeaders [ 'Content-Type' ] ) . to . equal ( 'application/x-www-form-urlencoded' ) ;
} ) ;
it ( 'sets the content type header on multi part forms' , async ( ) = > {
await w . loadURL ( url ) ;
const requestDetails : Promise < OnBeforeSendHeadersListenerDetails > = new Promise ( resolve = > {
2019-11-01 20:37:02 +00:00
w . webContents . session . webRequest . onBeforeSendHeaders ( ( details ) = > {
2019-06-03 22:10:58 +00:00
resolve ( details ) ;
} ) ;
} ) ;
w . webContents . executeJavaScript ( `
form = document . createElement ( 'form' )
document . body . appendChild ( form )
form . method = 'POST'
form . enctype = 'multipart/form-data'
file = document . createElement ( 'input' )
file . type = 'file'
file . name = 'file'
form . appendChild ( file )
form . submit ( )
` );
const details = await requestDetails ;
expect ( details . requestHeaders [ 'Content-Type' ] . startsWith ( 'multipart/form-data; boundary=----WebKitFormBoundary' ) ) . to . equal ( true ) ;
} ) ;
} ) ;
2021-03-01 21:52:29 +00:00
it ( 'should support base url for data urls' , async ( ) = > {
await w . loadURL ( 'data:text/html,<script src="loaded-from-dataurl.js"></script>' , { baseURLForDataURL : ` other:// ${ path . join ( fixtures , 'api' ) } ${ path . sep } ` } ) ;
expect ( await w . webContents . executeJavaScript ( 'window.ping' ) ) . to . equal ( 'pong' ) ;
2019-06-03 22:10:58 +00:00
} ) ;
} ) ;
2020-02-21 19:08:26 +00:00
for ( const sandbox of [ false , true ] ) {
describe ( ` navigation events ${ sandbox ? ' with sandbox' : '' } ` , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2020-02-21 19:08:26 +00:00
beforeEach ( ( ) = > {
w = new BrowserWindow ( { show : false , webPreferences : { nodeIntegration : false , sandbox } } ) ;
} ) ;
afterEach ( async ( ) = > {
await closeWindow ( w ) ;
w = null as unknown as BrowserWindow ;
} ) ;
2019-06-03 22:10:58 +00:00
2020-02-21 19:08:26 +00:00
describe ( 'will-navigate event' , ( ) = > {
2023-02-19 09:24:24 +00:00
let server : http.Server ;
let url : string ;
2023-02-20 11:30:57 +00:00
before ( async ( ) = > {
2020-08-21 19:34:09 +00:00
server = http . createServer ( ( req , res ) = > {
if ( req . url === '/navigate-top' ) {
res . end ( '<a target=_top href="/">navigate _top</a>' ) ;
} else {
res . end ( '' ) ;
}
} ) ;
2023-02-20 11:30:57 +00:00
url = ( await listen ( server ) ) . url ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-02-21 19:08:26 +00:00
after ( ( ) = > {
server . close ( ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-02-21 19:08:26 +00:00
2023-02-20 11:30:57 +00:00
it ( 'allows the window to be closed from the event listener' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const event = once ( w . webContents , 'will-navigate' ) ;
2020-02-21 19:08:26 +00:00
w . loadFile ( path . join ( fixtures , 'pages' , 'will-navigate.html' ) ) ;
2023-02-20 11:30:57 +00:00
await event ;
w . close ( ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-02-21 19:08:26 +00:00
it ( 'can be prevented' , ( done ) = > {
let willNavigate = false ;
w . webContents . once ( 'will-navigate' , ( e ) = > {
willNavigate = true ;
e . preventDefault ( ) ;
} ) ;
w . webContents . on ( 'did-stop-loading' , ( ) = > {
if ( willNavigate ) {
// i.e. it shouldn't have had '?navigated' appended to it.
2020-06-30 22:10:36 +00:00
try {
expect ( w . webContents . getURL ( ) . endsWith ( 'will-navigate.html' ) ) . to . be . true ( ) ;
done ( ) ;
} catch ( e ) {
done ( e ) ;
}
2020-02-21 19:08:26 +00:00
}
} ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'will-navigate.html' ) ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-02-21 19:08:26 +00:00
it ( 'is triggered when navigating from file: to http:' , async ( ) = > {
await w . loadFile ( path . join ( fixtures , 'api' , 'blank.html' ) ) ;
w . webContents . executeJavaScript ( ` location.href = ${ JSON . stringify ( url ) } ` ) ;
const navigatedTo = await new Promise ( resolve = > {
w . webContents . once ( 'will-navigate' , ( e , url ) = > {
e . preventDefault ( ) ;
resolve ( url ) ;
} ) ;
} ) ;
2023-02-20 11:30:57 +00:00
expect ( navigatedTo ) . to . equal ( url + '/' ) ;
2020-02-21 19:08:26 +00:00
expect ( w . webContents . getURL ( ) ) . to . match ( /^file:/ ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-02-21 19:08:26 +00:00
it ( 'is triggered when navigating from about:blank to http:' , async ( ) = > {
await w . loadURL ( 'about:blank' ) ;
w . webContents . executeJavaScript ( ` location.href = ${ JSON . stringify ( url ) } ` ) ;
const navigatedTo = await new Promise ( resolve = > {
w . webContents . once ( 'will-navigate' , ( e , url ) = > {
e . preventDefault ( ) ;
resolve ( url ) ;
} ) ;
} ) ;
2023-02-20 11:30:57 +00:00
expect ( navigatedTo ) . to . equal ( url + '/' ) ;
2020-02-21 19:08:26 +00:00
expect ( w . webContents . getURL ( ) ) . to . equal ( 'about:blank' ) ;
} ) ;
2020-08-21 19:34:09 +00:00
it ( 'is triggered when a cross-origin iframe navigates _top' , async ( ) = > {
2023-02-28 19:08:22 +00:00
w . loadURL ( ` data:text/html,<iframe src="http://127.0.0.1: ${ ( server . address ( ) as AddressInfo ) . port } /navigate-top"></iframe> ` ) ;
await emittedUntil ( w . webContents , 'did-frame-finish-load' , ( e : any , isMainFrame : boolean ) = > ! isMainFrame ) ;
let initiator : WebFrameMain | undefined ;
w . webContents . on ( 'will-navigate' , ( e ) = > {
initiator = e . initiator ;
2020-08-21 19:34:09 +00:00
} ) ;
2023-02-28 19:08:22 +00:00
const subframe = w . webContents . mainFrame . frames [ 0 ] ;
subframe . executeJavaScript ( 'document.getElementsByTagName("a")[0].click()' , true ) ;
2023-02-23 23:53:53 +00:00
await once ( w . webContents , 'did-navigate' ) ;
2023-02-28 19:08:22 +00:00
expect ( initiator ) . not . to . be . undefined ( ) ;
expect ( initiator ) . to . equal ( subframe ) ;
2020-08-21 19:34:09 +00:00
} ) ;
2023-11-14 22:09:44 +00:00
it ( 'is triggered when navigating from chrome: to http:' , async ( ) = > {
let hasEmittedWillNavigate = false ;
const willNavigatePromise = new Promise ( ( resolve ) = > {
w . webContents . once ( 'will-navigate' , e = > {
e . preventDefault ( ) ;
hasEmittedWillNavigate = true ;
resolve ( e . url ) ;
} ) ;
} ) ;
await w . loadURL ( 'chrome://gpu' ) ;
// shouldn't emit for browser-initiated request via loadURL
expect ( hasEmittedWillNavigate ) . to . equal ( false ) ;
w . webContents . executeJavaScript ( ` location.href = ${ JSON . stringify ( url ) } ` ) ;
const navigatedTo = await willNavigatePromise ;
expect ( navigatedTo ) . to . equal ( url + '/' ) ;
expect ( w . webContents . getURL ( ) ) . to . equal ( 'chrome://gpu/' ) ;
} ) ;
2020-02-21 19:08:26 +00:00
} ) ;
2023-03-28 14:55:41 +00:00
describe ( 'will-frame-navigate event' , ( ) = > {
let server = null as unknown as http . Server ;
let url = null as unknown as string ;
2023-09-04 10:33:29 +00:00
before ( async ( ) = > {
2023-03-28 14:55:41 +00:00
server = http . createServer ( ( req , res ) = > {
if ( req . url === '/navigate-top' ) {
res . end ( '<a target=_top href="/">navigate _top</a>' ) ;
} else if ( req . url === '/navigate-iframe' ) {
res . end ( '<a href="/test">navigate iframe</a>' ) ;
} else if ( req . url === '/navigate-iframe?navigated' ) {
res . end ( 'Successfully navigated' ) ;
} else if ( req . url === '/navigate-iframe-immediately' ) {
res . end ( `
< script type = "text/javascript" charset = "utf-8" >
location . href += '?navigated'
< / script >
` );
} else if ( req . url === '/navigate-iframe-immediately?navigated' ) {
res . end ( 'Successfully navigated' ) ;
} else {
res . end ( '' ) ;
}
} ) ;
2023-09-04 10:33:29 +00:00
url = ( await listen ( server ) ) . url ;
2023-03-28 14:55:41 +00:00
} ) ;
after ( ( ) = > {
server . close ( ) ;
} ) ;
it ( 'allows the window to be closed from the event listener' , ( done ) = > {
w . webContents . once ( 'will-frame-navigate' , ( ) = > {
w . close ( ) ;
done ( ) ;
} ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'will-navigate.html' ) ) ;
} ) ;
it ( 'can be prevented' , ( done ) = > {
let willNavigate = false ;
w . webContents . once ( 'will-frame-navigate' , ( e ) = > {
willNavigate = true ;
e . preventDefault ( ) ;
} ) ;
w . webContents . on ( 'did-stop-loading' , ( ) = > {
if ( willNavigate ) {
// i.e. it shouldn't have had '?navigated' appended to it.
try {
expect ( w . webContents . getURL ( ) . endsWith ( 'will-navigate.html' ) ) . to . be . true ( ) ;
done ( ) ;
} catch ( e ) {
done ( e ) ;
}
}
} ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'will-navigate.html' ) ) ;
} ) ;
it ( 'can be prevented when navigating subframe' , ( done ) = > {
let willNavigate = false ;
w . webContents . on ( 'did-frame-navigate' , ( _event , _url , _httpResponseCode , _httpStatusText , isMainFrame , frameProcessId , frameRoutingId ) = > {
if ( isMainFrame ) return ;
w . webContents . once ( 'will-frame-navigate' , ( e ) = > {
willNavigate = true ;
e . preventDefault ( ) ;
} ) ;
w . webContents . on ( 'did-stop-loading' , ( ) = > {
const frame = webFrameMain . fromId ( frameProcessId , frameRoutingId ) ;
expect ( frame ) . to . not . be . undefined ( ) ;
if ( willNavigate ) {
// i.e. it shouldn't have had '?navigated' appended to it.
try {
expect ( frame ! . url . endsWith ( '/navigate-iframe-immediately' ) ) . to . be . true ( ) ;
done ( ) ;
} catch ( e ) {
done ( e ) ;
}
}
} ) ;
} ) ;
w . loadURL ( ` data:text/html,<iframe src="http://127.0.0.1: ${ ( server . address ( ) as AddressInfo ) . port } /navigate-iframe-immediately"></iframe> ` ) ;
} ) ;
it ( 'is triggered when navigating from file: to http:' , async ( ) = > {
await w . loadFile ( path . join ( fixtures , 'api' , 'blank.html' ) ) ;
w . webContents . executeJavaScript ( ` location.href = ${ JSON . stringify ( url ) } ` ) ;
const navigatedTo = await new Promise ( resolve = > {
w . webContents . once ( 'will-frame-navigate' , ( e ) = > {
e . preventDefault ( ) ;
resolve ( e . url ) ;
} ) ;
} ) ;
2023-09-04 10:33:29 +00:00
expect ( navigatedTo ) . to . equal ( url + '/' ) ;
2023-03-28 14:55:41 +00:00
expect ( w . webContents . getURL ( ) ) . to . match ( /^file:/ ) ;
} ) ;
it ( 'is triggered when navigating from about:blank to http:' , async ( ) = > {
await w . loadURL ( 'about:blank' ) ;
w . webContents . executeJavaScript ( ` location.href = ${ JSON . stringify ( url ) } ` ) ;
const navigatedTo = await new Promise ( resolve = > {
w . webContents . once ( 'will-frame-navigate' , ( e ) = > {
e . preventDefault ( ) ;
resolve ( e . url ) ;
} ) ;
} ) ;
2023-09-04 10:33:29 +00:00
expect ( navigatedTo ) . to . equal ( url + '/' ) ;
2023-03-28 14:55:41 +00:00
expect ( w . webContents . getURL ( ) ) . to . equal ( 'about:blank' ) ;
} ) ;
it ( 'is triggered when a cross-origin iframe navigates _top' , async ( ) = > {
await w . loadURL ( ` data:text/html,<iframe src="http://127.0.0.1: ${ ( server . address ( ) as AddressInfo ) . port } /navigate-top"></iframe> ` ) ;
await setTimeout ( 1000 ) ;
let willFrameNavigateEmitted = false ;
let isMainFrameValue ;
w . webContents . on ( 'will-frame-navigate' , ( event ) = > {
willFrameNavigateEmitted = true ;
isMainFrameValue = event . isMainFrame ;
} ) ;
const didNavigatePromise = once ( w . webContents , 'did-navigate' ) ;
w . webContents . debugger . attach ( '1.1' ) ;
const targets = await w . webContents . debugger . sendCommand ( 'Target.getTargets' ) ;
const iframeTarget = targets . targetInfos . find ( ( t : any ) = > t . type === 'iframe' ) ;
const { sessionId } = await w . webContents . debugger . sendCommand ( 'Target.attachToTarget' , {
targetId : iframeTarget.targetId ,
flatten : true
} ) ;
await w . webContents . debugger . sendCommand ( 'Input.dispatchMouseEvent' , {
type : 'mousePressed' ,
x : 10 ,
y : 10 ,
clickCount : 1 ,
button : 'left'
} , sessionId ) ;
await w . webContents . debugger . sendCommand ( 'Input.dispatchMouseEvent' , {
type : 'mouseReleased' ,
x : 10 ,
y : 10 ,
clickCount : 1 ,
button : 'left'
} , sessionId ) ;
await didNavigatePromise ;
expect ( willFrameNavigateEmitted ) . to . be . true ( ) ;
expect ( isMainFrameValue ) . to . be . true ( ) ;
} ) ;
it ( 'is triggered when a cross-origin iframe navigates itself' , async ( ) = > {
await w . loadURL ( ` data:text/html,<iframe src="http://127.0.0.1: ${ ( server . address ( ) as AddressInfo ) . port } /navigate-iframe"></iframe> ` ) ;
await setTimeout ( 1000 ) ;
let willNavigateEmitted = false ;
let isMainFrameValue ;
w . webContents . on ( 'will-frame-navigate' , ( event ) = > {
willNavigateEmitted = true ;
isMainFrameValue = event . isMainFrame ;
} ) ;
const didNavigatePromise = once ( w . webContents , 'did-frame-navigate' ) ;
w . webContents . debugger . attach ( '1.1' ) ;
const targets = await w . webContents . debugger . sendCommand ( 'Target.getTargets' ) ;
const iframeTarget = targets . targetInfos . find ( ( t : any ) = > t . type === 'iframe' ) ;
const { sessionId } = await w . webContents . debugger . sendCommand ( 'Target.attachToTarget' , {
targetId : iframeTarget.targetId ,
flatten : true
} ) ;
await w . webContents . debugger . sendCommand ( 'Input.dispatchMouseEvent' , {
type : 'mousePressed' ,
x : 10 ,
y : 10 ,
clickCount : 1 ,
button : 'left'
} , sessionId ) ;
await w . webContents . debugger . sendCommand ( 'Input.dispatchMouseEvent' , {
type : 'mouseReleased' ,
x : 10 ,
y : 10 ,
clickCount : 1 ,
button : 'left'
} , sessionId ) ;
await didNavigatePromise ;
expect ( willNavigateEmitted ) . to . be . true ( ) ;
expect ( isMainFrameValue ) . to . be . false ( ) ;
} ) ;
it ( 'can cancel when a cross-origin iframe navigates itself' , async ( ) = > {
} ) ;
} ) ;
2020-02-21 19:08:26 +00:00
describe ( 'will-redirect event' , ( ) = > {
2023-02-19 09:24:24 +00:00
let server : http.Server ;
let url : string ;
2023-02-20 11:30:57 +00:00
before ( async ( ) = > {
2020-02-21 19:08:26 +00:00
server = http . createServer ( ( req , res ) = > {
if ( req . url === '/302' ) {
res . setHeader ( 'Location' , '/200' ) ;
res . statusCode = 302 ;
res . end ( ) ;
} else if ( req . url === '/navigate-302' ) {
res . end ( ` <html><body><script>window.location=' ${ url } /302'</script></body></html> ` ) ;
} else {
res . end ( ) ;
}
} ) ;
2023-02-20 11:30:57 +00:00
url = ( await listen ( server ) ) . url ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-02-21 19:08:26 +00:00
after ( ( ) = > {
server . close ( ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'is emitted on redirects' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const willRedirect = once ( w . webContents , 'will-redirect' ) ;
2020-02-21 19:08:26 +00:00
w . loadURL ( ` ${ url } /302 ` ) ;
2020-07-01 19:14:38 +00:00
await willRedirect ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'is emitted after will-navigate on redirects' , async ( ) = > {
2020-02-21 19:08:26 +00:00
let navigateCalled = false ;
w . webContents . on ( 'will-navigate' , ( ) = > {
navigateCalled = true ;
} ) ;
2023-02-23 23:53:53 +00:00
const willRedirect = once ( w . webContents , 'will-redirect' ) ;
2020-02-21 19:08:26 +00:00
w . loadURL ( ` ${ url } /navigate-302 ` ) ;
2020-06-30 22:10:36 +00:00
await willRedirect ;
expect ( navigateCalled ) . to . equal ( true , 'should have called will-navigate first' ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'is emitted before did-stop-loading on redirects' , async ( ) = > {
2020-02-21 19:08:26 +00:00
let stopCalled = false ;
w . webContents . on ( 'did-stop-loading' , ( ) = > {
stopCalled = true ;
} ) ;
2023-02-23 23:53:53 +00:00
const willRedirect = once ( w . webContents , 'will-redirect' ) ;
2020-02-21 19:08:26 +00:00
w . loadURL ( ` ${ url } /302 ` ) ;
2020-06-30 22:10:36 +00:00
await willRedirect ;
expect ( stopCalled ) . to . equal ( false , 'should not have called did-stop-loading first' ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-02-21 19:08:26 +00:00
2023-02-20 11:30:57 +00:00
it ( 'allows the window to be closed from the event listener' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const event = once ( w . webContents , 'will-redirect' ) ;
2020-02-21 19:08:26 +00:00
w . loadURL ( ` ${ url } /302 ` ) ;
2023-02-20 11:30:57 +00:00
await event ;
w . close ( ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-02-21 19:08:26 +00:00
it ( 'can be prevented' , ( done ) = > {
w . webContents . once ( 'will-redirect' , ( event ) = > {
event . preventDefault ( ) ;
} ) ;
w . webContents . on ( 'will-navigate' , ( e , u ) = > {
expect ( u ) . to . equal ( ` ${ url } /302 ` ) ;
} ) ;
w . webContents . on ( 'did-stop-loading' , ( ) = > {
2020-06-30 22:10:36 +00:00
try {
expect ( w . webContents . getURL ( ) ) . to . equal (
` ${ url } /navigate-302 ` ,
'url should not have changed after navigation event'
) ;
done ( ) ;
} catch ( e ) {
done ( e ) ;
}
2020-02-21 19:08:26 +00:00
} ) ;
w . webContents . on ( 'will-redirect' , ( e , u ) = > {
2020-06-30 22:10:36 +00:00
try {
expect ( u ) . to . equal ( ` ${ url } /200 ` ) ;
} catch ( e ) {
done ( e ) ;
}
2020-02-21 19:08:26 +00:00
} ) ;
w . loadURL ( ` ${ url } /navigate-302 ` ) ;
2019-06-03 22:10:58 +00:00
} ) ;
} ) ;
2023-03-28 14:55:41 +00:00
describe ( 'ordering' , ( ) = > {
let server = null as unknown as http . Server ;
let url = null as unknown as string ;
const navigationEvents = [
'did-start-navigation' ,
'did-navigate-in-page' ,
'will-frame-navigate' ,
'will-navigate' ,
'will-redirect' ,
'did-redirect-navigation' ,
'did-frame-navigate' ,
'did-navigate'
] ;
2023-09-04 10:33:29 +00:00
before ( async ( ) = > {
2023-03-28 14:55:41 +00:00
server = http . createServer ( ( req , res ) = > {
if ( req . url === '/navigate' ) {
res . end ( '<a href="/">navigate</a>' ) ;
} else if ( req . url === '/redirect' ) {
res . end ( '<a href="/redirect2">redirect</a>' ) ;
} else if ( req . url === '/redirect2' ) {
res . statusCode = 302 ;
res . setHeader ( 'location' , url ) ;
res . end ( ) ;
} else if ( req . url === '/in-page' ) {
res . end ( '<a href="#in-page">redirect</a><div id="in-page"></div>' ) ;
} else {
res . end ( '' ) ;
}
} ) ;
2023-09-04 10:33:29 +00:00
url = ( await listen ( server ) ) . url ;
2023-03-28 14:55:41 +00:00
} ) ;
it ( 'for initial navigation, event order is consistent' , async ( ) = > {
const firedEvents : string [ ] = [ ] ;
const expectedEventOrder = [
'did-start-navigation' ,
'did-frame-navigate' ,
'did-navigate'
] ;
const allEvents = Promise . all ( navigationEvents . map ( event = >
once ( w . webContents , event ) . then ( ( ) = > firedEvents . push ( event ) )
) ) ;
const timeout = setTimeout ( 1000 ) ;
w . loadURL ( url ) ;
await Promise . race ( [ allEvents , timeout ] ) ;
expect ( firedEvents ) . to . deep . equal ( expectedEventOrder ) ;
} ) ;
it ( 'for second navigation, event order is consistent' , async ( ) = > {
const firedEvents : string [ ] = [ ] ;
const expectedEventOrder = [
'did-start-navigation' ,
'will-frame-navigate' ,
'will-navigate' ,
'did-frame-navigate' ,
'did-navigate'
] ;
2023-09-04 10:33:29 +00:00
w . loadURL ( url + '/navigate' ) ;
2023-03-28 14:55:41 +00:00
await once ( w . webContents , 'did-navigate' ) ;
2023-06-09 23:08:36 +00:00
await setTimeout ( 2000 ) ;
Promise . all ( navigationEvents . map ( event = >
2023-03-28 14:55:41 +00:00
once ( w . webContents , event ) . then ( ( ) = > firedEvents . push ( event ) )
2023-06-09 23:08:36 +00:00
) ) ;
2023-03-28 14:55:41 +00:00
const navigationFinished = once ( w . webContents , 'did-navigate' ) ;
w . webContents . debugger . attach ( '1.1' ) ;
const targets = await w . webContents . debugger . sendCommand ( 'Target.getTargets' ) ;
const pageTarget = targets . targetInfos . find ( ( t : any ) = > t . type === 'page' ) ;
const { sessionId } = await w . webContents . debugger . sendCommand ( 'Target.attachToTarget' , {
targetId : pageTarget.targetId ,
flatten : true
} ) ;
await w . webContents . debugger . sendCommand ( 'Input.dispatchMouseEvent' , {
type : 'mousePressed' ,
x : 10 ,
y : 10 ,
clickCount : 1 ,
button : 'left'
} , sessionId ) ;
await w . webContents . debugger . sendCommand ( 'Input.dispatchMouseEvent' , {
type : 'mouseReleased' ,
x : 10 ,
y : 10 ,
clickCount : 1 ,
button : 'left'
} , sessionId ) ;
await navigationFinished ;
expect ( firedEvents ) . to . deep . equal ( expectedEventOrder ) ;
} ) ;
it ( 'when navigating with redirection, event order is consistent' , async ( ) = > {
const firedEvents : string [ ] = [ ] ;
const expectedEventOrder = [
'did-start-navigation' ,
'will-frame-navigate' ,
'will-navigate' ,
'will-redirect' ,
'did-redirect-navigation' ,
'did-frame-navigate' ,
'did-navigate'
] ;
2023-09-04 10:33:29 +00:00
w . loadURL ( url + '/redirect' ) ;
2023-03-28 14:55:41 +00:00
await once ( w . webContents , 'did-navigate' ) ;
2023-06-09 23:08:36 +00:00
await setTimeout ( 2000 ) ;
Promise . all ( navigationEvents . map ( event = >
2023-03-28 14:55:41 +00:00
once ( w . webContents , event ) . then ( ( ) = > firedEvents . push ( event ) )
2023-06-09 23:08:36 +00:00
) ) ;
2023-03-28 14:55:41 +00:00
const navigationFinished = once ( w . webContents , 'did-navigate' ) ;
w . webContents . debugger . attach ( '1.1' ) ;
const targets = await w . webContents . debugger . sendCommand ( 'Target.getTargets' ) ;
const pageTarget = targets . targetInfos . find ( ( t : any ) = > t . type === 'page' ) ;
const { sessionId } = await w . webContents . debugger . sendCommand ( 'Target.attachToTarget' , {
targetId : pageTarget.targetId ,
flatten : true
} ) ;
await w . webContents . debugger . sendCommand ( 'Input.dispatchMouseEvent' , {
type : 'mousePressed' ,
x : 10 ,
y : 10 ,
clickCount : 1 ,
button : 'left'
} , sessionId ) ;
await w . webContents . debugger . sendCommand ( 'Input.dispatchMouseEvent' , {
type : 'mouseReleased' ,
x : 10 ,
y : 10 ,
clickCount : 1 ,
button : 'left'
} , sessionId ) ;
await navigationFinished ;
expect ( firedEvents ) . to . deep . equal ( expectedEventOrder ) ;
} ) ;
it ( 'when navigating in-page, event order is consistent' , async ( ) = > {
const firedEvents : string [ ] = [ ] ;
const expectedEventOrder = [
'did-start-navigation' ,
'did-navigate-in-page'
] ;
2023-09-04 10:33:29 +00:00
w . loadURL ( url + '/in-page' ) ;
2023-03-28 14:55:41 +00:00
await once ( w . webContents , 'did-navigate' ) ;
2023-06-09 23:08:36 +00:00
await setTimeout ( 2000 ) ;
Promise . all ( navigationEvents . map ( event = >
2023-03-28 14:55:41 +00:00
once ( w . webContents , event ) . then ( ( ) = > firedEvents . push ( event ) )
2023-06-09 23:08:36 +00:00
) ) ;
2023-03-28 14:55:41 +00:00
const navigationFinished = once ( w . webContents , 'did-navigate-in-page' ) ;
w . webContents . debugger . attach ( '1.1' ) ;
const targets = await w . webContents . debugger . sendCommand ( 'Target.getTargets' ) ;
const pageTarget = targets . targetInfos . find ( ( t : any ) = > t . type === 'page' ) ;
const { sessionId } = await w . webContents . debugger . sendCommand ( 'Target.attachToTarget' , {
targetId : pageTarget.targetId ,
flatten : true
} ) ;
await w . webContents . debugger . sendCommand ( 'Input.dispatchMouseEvent' , {
type : 'mousePressed' ,
x : 10 ,
y : 10 ,
clickCount : 1 ,
button : 'left'
} , sessionId ) ;
await w . webContents . debugger . sendCommand ( 'Input.dispatchMouseEvent' , {
type : 'mouseReleased' ,
x : 10 ,
y : 10 ,
clickCount : 1 ,
button : 'left'
} , sessionId ) ;
await navigationFinished ;
expect ( firedEvents ) . to . deep . equal ( expectedEventOrder ) ;
} ) ;
} ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-02-21 19:08:26 +00:00
}
2019-06-03 22:10:58 +00:00
2019-06-19 23:38:21 +00:00
describe ( 'focus and visibility' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-06-03 22:10:58 +00:00
beforeEach ( ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false } ) ;
2019-06-03 22:10:58 +00:00
} ) ;
afterEach ( async ( ) = > {
await closeWindow ( w ) ;
w = null as unknown as BrowserWindow ;
} ) ;
2019-06-19 23:38:21 +00:00
describe ( 'BrowserWindow.show()' , ( ) = > {
2022-05-04 08:29:30 +00:00
it ( 'should focus on window' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const p = once ( w , 'focus' ) ;
w . show ( ) ;
await p ;
2019-10-30 23:38:21 +00:00
expect ( w . isFocused ( ) ) . to . equal ( true ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2022-05-04 08:29:30 +00:00
it ( 'should make the window visible' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const p = once ( w , 'focus' ) ;
w . show ( ) ;
await p ;
2019-06-19 23:38:21 +00:00
expect ( w . isVisible ( ) ) . to . equal ( true ) ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'emits when window is shown' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const show = once ( w , 'show' ) ;
2019-06-19 23:38:21 +00:00
w . show ( ) ;
2020-06-30 22:10:36 +00:00
await show ;
expect ( w . isVisible ( ) ) . to . equal ( true ) ;
2019-06-19 23:38:21 +00:00
} ) ;
} ) ;
describe ( 'BrowserWindow.hide()' , ( ) = > {
it ( 'should defocus on window' , ( ) = > {
w . hide ( ) ;
expect ( w . isFocused ( ) ) . to . equal ( false ) ;
} ) ;
it ( 'should make the window not visible' , ( ) = > {
w . show ( ) ;
w . hide ( ) ;
expect ( w . isVisible ( ) ) . to . equal ( false ) ;
} ) ;
it ( 'emits when window is hidden' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const shown = once ( w , 'show' ) ;
2019-06-19 23:38:21 +00:00
w . show ( ) ;
await shown ;
2023-02-23 23:53:53 +00:00
const hidden = once ( w , 'hide' ) ;
2019-06-19 23:38:21 +00:00
w . hide ( ) ;
await hidden ;
expect ( w . isVisible ( ) ) . to . equal ( false ) ;
} ) ;
} ) ;
2023-05-16 09:46:45 +00:00
describe ( 'BrowserWindow.minimize()' , ( ) = > {
// TODO(codebytere): Enable for Linux once maximize/minimize events work in CI.
ifit ( process . platform !== 'linux' ) ( 'should not be visible when the window is minimized' , async ( ) = > {
const minimize = once ( w , 'minimize' ) ;
w . minimize ( ) ;
await minimize ;
expect ( w . isMinimized ( ) ) . to . equal ( true ) ;
expect ( w . isVisible ( ) ) . to . equal ( false ) ;
} ) ;
} ) ;
2019-06-19 23:38:21 +00:00
describe ( 'BrowserWindow.showInactive()' , ( ) = > {
it ( 'should not focus on window' , ( ) = > {
w . showInactive ( ) ;
expect ( w . isFocused ( ) ) . to . equal ( false ) ;
} ) ;
2022-02-21 09:23:55 +00:00
// TODO(dsanders11): Enable for Linux once CI plays nice with these kinds of tests
ifit ( process . platform !== 'linux' ) ( 'should not restore maximized windows' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
const shown = once ( w , 'show' ) ;
2022-02-21 09:23:55 +00:00
w . maximize ( ) ;
// TODO(dsanders11): The maximize event isn't firing on macOS for a window initially hidden
if ( process . platform !== 'darwin' ) {
await maximize ;
} else {
2023-02-23 23:53:53 +00:00
await setTimeout ( 1000 ) ;
2022-02-21 09:23:55 +00:00
}
w . showInactive ( ) ;
await shown ;
expect ( w . isMaximized ( ) ) . to . equal ( true ) ;
} ) ;
2023-11-30 11:43:22 +00:00
ifit ( process . platform === 'darwin' ) ( 'should attach child window to parent' , async ( ) = > {
const wShow = once ( w , 'show' ) ;
w . show ( ) ;
await wShow ;
const c = new BrowserWindow ( { show : false , parent : w } ) ;
const cShow = once ( c , 'show' ) ;
c . showInactive ( ) ;
await cShow ;
// verifying by checking that the child tracks the parent's visibility
const minimized = once ( w , 'minimize' ) ;
w . minimize ( ) ;
await minimized ;
expect ( w . isVisible ( ) ) . to . be . false ( 'parent is visible' ) ;
expect ( c . isVisible ( ) ) . to . be . false ( 'child is visible' ) ;
const restored = once ( w , 'restore' ) ;
w . restore ( ) ;
await restored ;
expect ( w . isVisible ( ) ) . to . be . true ( 'parent is visible' ) ;
expect ( c . isVisible ( ) ) . to . be . true ( 'child is visible' ) ;
closeWindow ( c ) ;
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
describe ( 'BrowserWindow.focus()' , ( ) = > {
it ( 'does not make the window become visible' , ( ) = > {
expect ( w . isVisible ( ) ) . to . equal ( false ) ;
w . focus ( ) ;
expect ( w . isVisible ( ) ) . to . equal ( false ) ;
} ) ;
2022-05-03 07:39:18 +00:00
ifit ( process . platform !== 'win32' ) ( 'focuses a blurred window' , async ( ) = > {
{
2023-02-23 23:53:53 +00:00
const isBlurred = once ( w , 'blur' ) ;
const isShown = once ( w , 'show' ) ;
2022-05-03 07:39:18 +00:00
w . show ( ) ;
w . blur ( ) ;
await isShown ;
await isBlurred ;
}
expect ( w . isFocused ( ) ) . to . equal ( false ) ;
w . focus ( ) ;
expect ( w . isFocused ( ) ) . to . equal ( true ) ;
} ) ;
ifit ( process . platform !== 'linux' ) ( 'acquires focus status from the other windows' , async ( ) = > {
const w1 = new BrowserWindow ( { show : false } ) ;
const w2 = new BrowserWindow ( { show : false } ) ;
const w3 = new BrowserWindow ( { show : false } ) ;
{
2023-02-23 23:53:53 +00:00
const isFocused3 = once ( w3 , 'focus' ) ;
const isShown1 = once ( w1 , 'show' ) ;
const isShown2 = once ( w2 , 'show' ) ;
const isShown3 = once ( w3 , 'show' ) ;
2022-05-03 07:39:18 +00:00
w1 . show ( ) ;
w2 . show ( ) ;
w3 . show ( ) ;
await isShown1 ;
await isShown2 ;
await isShown3 ;
await isFocused3 ;
}
// TODO(RaisinTen): Investigate why this assertion fails only on Linux.
expect ( w1 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w2 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w3 . isFocused ( ) ) . to . equal ( true ) ;
w1 . focus ( ) ;
expect ( w1 . isFocused ( ) ) . to . equal ( true ) ;
expect ( w2 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w3 . isFocused ( ) ) . to . equal ( false ) ;
w2 . focus ( ) ;
expect ( w1 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w2 . isFocused ( ) ) . to . equal ( true ) ;
expect ( w3 . isFocused ( ) ) . to . equal ( false ) ;
w3 . focus ( ) ;
expect ( w1 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w2 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w3 . isFocused ( ) ) . to . equal ( true ) ;
{
2023-02-23 23:53:53 +00:00
const isClosed1 = once ( w1 , 'closed' ) ;
const isClosed2 = once ( w2 , 'closed' ) ;
const isClosed3 = once ( w3 , 'closed' ) ;
2022-05-03 07:39:18 +00:00
w1 . destroy ( ) ;
w2 . destroy ( ) ;
w3 . destroy ( ) ;
await isClosed1 ;
await isClosed2 ;
await isClosed3 ;
}
} ) ;
2023-11-06 21:38:12 +00:00
ifit ( process . platform === 'darwin' ) ( 'it does not activate the app if focusing an inactive panel' , async ( ) = > {
// Show to focus app, then remove existing window
w . show ( ) ;
w . destroy ( ) ;
// We first need to resign app focus for this test to work
const isInactive = once ( app , 'did-resign-active' ) ;
childProcess . execSync ( 'osascript -e \'tell application "Finder" to activate\'' ) ;
await isInactive ;
// Create new window
w = new BrowserWindow ( {
type : 'panel' ,
height : 200 ,
width : 200 ,
center : true ,
show : false
} ) ;
const isShow = once ( w , 'show' ) ;
const isFocus = once ( w , 'focus' ) ;
2024-04-12 12:27:59 +00:00
w . show ( ) ;
2023-11-06 21:38:12 +00:00
w . focus ( ) ;
await isShow ;
await isFocus ;
const getActiveAppOsa = 'tell application "System Events" to get the name of the first process whose frontmost is true' ;
const activeApp = childProcess . execSync ( ` osascript -e ' ${ getActiveAppOsa } ' ` ) . toString ( ) . trim ( ) ;
expect ( activeApp ) . to . equal ( 'Finder' ) ;
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2022-05-03 07:39:18 +00:00
// TODO(RaisinTen): Make this work on Windows too.
// Refs: https://github.com/electron/electron/issues/20464.
ifdescribe ( process . platform !== 'win32' ) ( 'BrowserWindow.blur()' , ( ) = > {
it ( 'removes focus from window' , async ( ) = > {
{
2023-02-23 23:53:53 +00:00
const isFocused = once ( w , 'focus' ) ;
const isShown = once ( w , 'show' ) ;
2022-05-03 07:39:18 +00:00
w . show ( ) ;
await isShown ;
await isFocused ;
}
expect ( w . isFocused ( ) ) . to . equal ( true ) ;
2019-06-19 23:38:21 +00:00
w . blur ( ) ;
expect ( w . isFocused ( ) ) . to . equal ( false ) ;
} ) ;
2022-05-03 07:39:18 +00:00
ifit ( process . platform !== 'linux' ) ( 'transfers focus status to the next window' , async ( ) = > {
const w1 = new BrowserWindow ( { show : false } ) ;
const w2 = new BrowserWindow ( { show : false } ) ;
const w3 = new BrowserWindow ( { show : false } ) ;
{
2023-02-23 23:53:53 +00:00
const isFocused3 = once ( w3 , 'focus' ) ;
const isShown1 = once ( w1 , 'show' ) ;
const isShown2 = once ( w2 , 'show' ) ;
const isShown3 = once ( w3 , 'show' ) ;
2022-05-03 07:39:18 +00:00
w1 . show ( ) ;
w2 . show ( ) ;
w3 . show ( ) ;
await isShown1 ;
await isShown2 ;
await isShown3 ;
await isFocused3 ;
}
// TODO(RaisinTen): Investigate why this assertion fails only on Linux.
expect ( w1 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w2 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w3 . isFocused ( ) ) . to . equal ( true ) ;
w3 . blur ( ) ;
expect ( w1 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w2 . isFocused ( ) ) . to . equal ( true ) ;
expect ( w3 . isFocused ( ) ) . to . equal ( false ) ;
w2 . blur ( ) ;
expect ( w1 . isFocused ( ) ) . to . equal ( true ) ;
expect ( w2 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w3 . isFocused ( ) ) . to . equal ( false ) ;
w1 . blur ( ) ;
expect ( w1 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w2 . isFocused ( ) ) . to . equal ( false ) ;
expect ( w3 . isFocused ( ) ) . to . equal ( true ) ;
{
2023-02-23 23:53:53 +00:00
const isClosed1 = once ( w1 , 'closed' ) ;
const isClosed2 = once ( w2 , 'closed' ) ;
const isClosed3 = once ( w3 , 'closed' ) ;
2022-05-03 07:39:18 +00:00
w1 . destroy ( ) ;
w2 . destroy ( ) ;
w3 . destroy ( ) ;
await isClosed1 ;
await isClosed2 ;
await isClosed3 ;
}
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
describe ( 'BrowserWindow.getFocusedWindow()' , ( ) = > {
2019-12-17 19:35:28 +00:00
it ( 'returns the opener window when dev tools window is focused' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const p = once ( w , 'focus' ) ;
w . show ( ) ;
await p ;
2019-06-19 23:38:21 +00:00
w . webContents . openDevTools ( { mode : 'undocked' } ) ;
2023-02-23 23:53:53 +00:00
await once ( w . webContents , 'devtools-focused' ) ;
2019-12-17 19:35:28 +00:00
expect ( BrowserWindow . getFocusedWindow ( ) ) . to . equal ( w ) ;
2019-06-19 23:38:21 +00:00
} ) ;
} ) ;
describe ( 'BrowserWindow.moveTop()' , ( ) = > {
2023-08-16 11:28:29 +00:00
afterEach ( closeAllWindows ) ;
2019-06-19 23:38:21 +00:00
it ( 'should not steal focus' , async ( ) = > {
const posDelta = 50 ;
2023-02-23 23:53:53 +00:00
const wShownInactive = once ( w , 'show' ) ;
2019-06-19 23:38:21 +00:00
w . showInactive ( ) ;
await wShownInactive ;
expect ( w . isFocused ( ) ) . to . equal ( false ) ;
2020-03-20 20:28:31 +00:00
2019-06-19 23:38:21 +00:00
const otherWindow = new BrowserWindow ( { show : false , title : 'otherWindow' } ) ;
2023-02-23 23:53:53 +00:00
const otherWindowShown = once ( otherWindow , 'show' ) ;
const otherWindowFocused = once ( otherWindow , 'focus' ) ;
2019-06-19 23:38:21 +00:00
otherWindow . show ( ) ;
await otherWindowShown ;
2019-06-24 20:41:42 +00:00
await otherWindowFocused ;
2019-06-19 23:38:21 +00:00
expect ( otherWindow . isFocused ( ) ) . to . equal ( true ) ;
2020-03-20 20:28:31 +00:00
2019-06-19 23:38:21 +00:00
w . moveTop ( ) ;
const wPos = w . getPosition ( ) ;
2023-02-23 23:53:53 +00:00
const wMoving = once ( w , 'move' ) ;
2019-06-19 23:38:21 +00:00
w . setPosition ( wPos [ 0 ] + posDelta , wPos [ 1 ] + posDelta ) ;
await wMoving ;
2019-06-03 22:10:58 +00:00
expect ( w . isFocused ( ) ) . to . equal ( false ) ;
2019-06-19 23:38:21 +00:00
expect ( otherWindow . isFocused ( ) ) . to . equal ( true ) ;
2020-03-20 20:28:31 +00:00
2023-02-23 23:53:53 +00:00
const wFocused = once ( w , 'focus' ) ;
const otherWindowBlurred = once ( otherWindow , 'blur' ) ;
2019-06-19 23:38:21 +00:00
w . focus ( ) ;
await wFocused ;
2021-06-03 08:05:04 +00:00
await otherWindowBlurred ;
2019-06-03 22:10:58 +00:00
expect ( w . isFocused ( ) ) . to . equal ( true ) ;
2020-03-20 20:28:31 +00:00
2019-06-19 23:38:21 +00:00
otherWindow . moveTop ( ) ;
const otherWindowPos = otherWindow . getPosition ( ) ;
2023-02-23 23:53:53 +00:00
const otherWindowMoving = once ( otherWindow , 'move' ) ;
2019-06-19 23:38:21 +00:00
otherWindow . setPosition ( otherWindowPos [ 0 ] + posDelta , otherWindowPos [ 1 ] + posDelta ) ;
await otherWindowMoving ;
expect ( otherWindow . isFocused ( ) ) . to . equal ( false ) ;
expect ( w . isFocused ( ) ) . to . equal ( true ) ;
2020-03-20 20:28:31 +00:00
2019-06-19 23:38:21 +00:00
await closeWindow ( otherWindow , { assertNotWindows : false } ) ;
expect ( BrowserWindow . getAllWindows ( ) ) . to . have . lengthOf ( 1 ) ;
} ) ;
2023-08-16 11:28:29 +00:00
it ( 'should not crash when called on a modal child window' , async ( ) = > {
const shown = once ( w , 'show' ) ;
w . show ( ) ;
await shown ;
const child = new BrowserWindow ( { modal : true , parent : w } ) ;
expect ( ( ) = > { child . moveTop ( ) ; } ) . to . not . throw ( ) ;
} ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2019-06-19 23:38:21 +00:00
2023-05-24 19:32:31 +00:00
describe ( 'BrowserWindow.moveAbove(mediaSourceId)' , ( ) = > {
2019-08-15 06:51:15 +00:00
it ( 'should throw an exception if wrong formatting' , async ( ) = > {
const fakeSourceIds = [
'none' , 'screen:0' , 'window:fake' , 'window:1234' , 'foobar:1:2'
] ;
2023-08-31 14:36:43 +00:00
for ( const sourceId of fakeSourceIds ) {
2019-08-15 06:51:15 +00:00
expect ( ( ) = > {
w . moveAbove ( sourceId ) ;
} ) . to . throw ( /Invalid media source id/ ) ;
2023-08-31 14:36:43 +00:00
}
2019-08-15 06:51:15 +00:00
} ) ;
2020-05-11 01:46:45 +00:00
2019-08-15 06:51:15 +00:00
it ( 'should throw an exception if wrong type' , async ( ) = > {
const fakeSourceIds = [ null as any , 123 as any ] ;
2023-08-31 14:36:43 +00:00
for ( const sourceId of fakeSourceIds ) {
2019-08-15 06:51:15 +00:00
expect ( ( ) = > {
w . moveAbove ( sourceId ) ;
} ) . to . throw ( /Error processing argument at index 0 */ ) ;
2023-08-31 14:36:43 +00:00
}
2019-08-15 06:51:15 +00:00
} ) ;
2020-05-11 01:46:45 +00:00
2019-08-15 06:51:15 +00:00
it ( 'should throw an exception if invalid window' , async ( ) = > {
// It is very unlikely that these window id exist.
const fakeSourceIds = [ 'window:99999999:0' , 'window:123456:1' ,
'window:123456:9' ] ;
2023-08-31 14:36:43 +00:00
for ( const sourceId of fakeSourceIds ) {
2019-08-15 06:51:15 +00:00
expect ( ( ) = > {
w . moveAbove ( sourceId ) ;
} ) . to . throw ( /Invalid media source id/ ) ;
2023-08-31 14:36:43 +00:00
}
2019-08-15 06:51:15 +00:00
} ) ;
2020-05-11 01:46:45 +00:00
2019-08-15 06:51:15 +00:00
it ( 'should not throw an exception' , async ( ) = > {
const w2 = new BrowserWindow ( { show : false , title : 'window2' } ) ;
2023-02-23 23:53:53 +00:00
const w2Shown = once ( w2 , 'show' ) ;
2019-08-15 06:51:15 +00:00
w2 . show ( ) ;
await w2Shown ;
expect ( ( ) = > {
w . moveAbove ( w2 . getMediaSourceId ( ) ) ;
} ) . to . not . throw ( ) ;
await closeWindow ( w2 , { assertNotWindows : false } ) ;
} ) ;
} ) ;
2020-01-22 01:13:48 +00:00
describe ( 'BrowserWindow.setFocusable()' , ( ) = > {
it ( 'can set unfocusable window to focusable' , async ( ) = > {
const w2 = new BrowserWindow ( { focusable : false } ) ;
2023-02-23 23:53:53 +00:00
const w2Focused = once ( w2 , 'focus' ) ;
2020-01-22 01:13:48 +00:00
w2 . setFocusable ( true ) ;
w2 . focus ( ) ;
await w2Focused ;
await closeWindow ( w2 , { assertNotWindows : false } ) ;
} ) ;
} ) ;
2021-04-21 10:32:19 +00:00
describe ( 'BrowserWindow.isFocusable()' , ( ) = > {
it ( 'correctly returns whether a window is focusable' , async ( ) = > {
const w2 = new BrowserWindow ( { focusable : false } ) ;
expect ( w2 . isFocusable ( ) ) . to . be . false ( ) ;
w2 . setFocusable ( true ) ;
expect ( w2 . isFocusable ( ) ) . to . be . true ( ) ;
await closeWindow ( w2 , { assertNotWindows : false } ) ;
} ) ;
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
describe ( 'sizing' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2020-05-11 01:46:45 +00:00
2019-06-19 23:38:21 +00:00
beforeEach ( ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false , width : 400 , height : 400 } ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2020-05-11 01:46:45 +00:00
2019-06-19 23:38:21 +00:00
afterEach ( async ( ) = > {
await closeWindow ( w ) ;
w = null as unknown as BrowserWindow ;
} ) ;
describe ( 'BrowserWindow.setBounds(bounds[, animate])' , ( ) = > {
it ( 'sets the window bounds with full bounds' , ( ) = > {
const fullBounds = { x : 440 , y : 225 , width : 500 , height : 400 } ;
w . setBounds ( fullBounds ) ;
expectBoundsEqual ( w . getBounds ( ) , fullBounds ) ;
} ) ;
2024-05-13 08:27:01 +00:00
it ( 'rounds non-integer bounds' , ( ) = > {
w . setBounds ( { x : 440.5 , y : 225.1 , width : 500.4 , height : 400.9 } ) ;
const bounds = w . getBounds ( ) ;
expect ( bounds ) . to . deep . equal ( { x : 441 , y : 225 , width : 500 , height : 401 } ) ;
} ) ;
2019-06-19 23:38:21 +00:00
it ( 'sets the window bounds with partial bounds' , ( ) = > {
const fullBounds = { x : 440 , y : 225 , width : 500 , height : 400 } ;
w . setBounds ( fullBounds ) ;
const boundsUpdate = { width : 200 } ;
w . setBounds ( boundsUpdate as any ) ;
2022-06-27 08:29:18 +00:00
const expectedBounds = { . . . fullBounds , . . . boundsUpdate } ;
2019-06-19 23:38:21 +00:00
expectBoundsEqual ( w . getBounds ( ) , expectedBounds ) ;
} ) ;
2020-11-12 00:27:24 +00:00
ifit ( process . platform === 'darwin' ) ( 'on macOS' , ( ) = > {
it ( 'emits \'resized\' event after animating' , async ( ) = > {
const fullBounds = { x : 440 , y : 225 , width : 500 , height : 400 } ;
w . setBounds ( fullBounds , true ) ;
2023-02-23 23:53:53 +00:00
await expect ( once ( w , 'resized' ) ) . to . eventually . be . fulfilled ( ) ;
2020-11-12 00:27:24 +00:00
} ) ;
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
describe ( 'BrowserWindow.setSize(width, height)' , ( ) = > {
it ( 'sets the window size' , async ( ) = > {
const size = [ 300 , 400 ] ;
2023-02-23 23:53:53 +00:00
const resized = once ( w , 'resize' ) ;
2019-06-19 23:38:21 +00:00
w . setSize ( size [ 0 ] , size [ 1 ] ) ;
await resized ;
expectBoundsEqual ( w . getSize ( ) , size ) ;
} ) ;
2020-11-12 00:27:24 +00:00
ifit ( process . platform === 'darwin' ) ( 'on macOS' , ( ) = > {
it ( 'emits \'resized\' event after animating' , async ( ) = > {
const size = [ 300 , 400 ] ;
w . setSize ( size [ 0 ] , size [ 1 ] , true ) ;
2023-02-23 23:53:53 +00:00
await expect ( once ( w , 'resized' ) ) . to . eventually . be . fulfilled ( ) ;
2020-11-12 00:27:24 +00:00
} ) ;
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
describe ( 'BrowserWindow.setMinimum/MaximumSize(width, height)' , ( ) = > {
it ( 'sets the maximum and minimum size of the window' , ( ) = > {
expect ( w . getMinimumSize ( ) ) . to . deep . equal ( [ 0 , 0 ] ) ;
expect ( w . getMaximumSize ( ) ) . to . deep . equal ( [ 0 , 0 ] ) ;
w . setMinimumSize ( 100 , 100 ) ;
expectBoundsEqual ( w . getMinimumSize ( ) , [ 100 , 100 ] ) ;
expectBoundsEqual ( w . getMaximumSize ( ) , [ 0 , 0 ] ) ;
w . setMaximumSize ( 900 , 600 ) ;
expectBoundsEqual ( w . getMinimumSize ( ) , [ 100 , 100 ] ) ;
expectBoundsEqual ( w . getMaximumSize ( ) , [ 900 , 600 ] ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.setAspectRatio(ratio)' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'resets the behaviour when passing in 0' , async ( ) = > {
2019-06-19 23:38:21 +00:00
const size = [ 300 , 400 ] ;
w . setAspectRatio ( 1 / 2 ) ;
w . setAspectRatio ( 0 ) ;
2023-02-23 23:53:53 +00:00
const resize = once ( w , 'resize' ) ;
2019-06-19 23:38:21 +00:00
w . setSize ( size [ 0 ] , size [ 1 ] ) ;
2020-06-30 22:10:36 +00:00
await resize ;
expectBoundsEqual ( w . getSize ( ) , size ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2021-11-22 09:31:21 +00:00
it ( 'doesn\'t change bounds when maximum size is set' , ( ) = > {
w . setMenu ( null ) ;
w . setMaximumSize ( 400 , 400 ) ;
// Without https://github.com/electron/electron/pull/29101
// following call would shrink the window to 384x361.
// There would be also DCHECK in resize_utils.cc on
// debug build.
w . setAspectRatio ( 1.0 ) ;
expectBoundsEqual ( w . getSize ( ) , [ 400 , 400 ] ) ;
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
describe ( 'BrowserWindow.setPosition(x, y)' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'sets the window position' , async ( ) = > {
2019-06-19 23:38:21 +00:00
const pos = [ 10 , 10 ] ;
2023-02-23 23:53:53 +00:00
const move = once ( w , 'move' ) ;
2019-06-19 23:38:21 +00:00
w . setPosition ( pos [ 0 ] , pos [ 1 ] ) ;
2020-06-30 22:10:36 +00:00
await move ;
expect ( w . getPosition ( ) ) . to . deep . equal ( pos ) ;
2019-06-19 23:38:21 +00:00
} ) ;
} ) ;
describe ( 'BrowserWindow.setContentSize(width, height)' , ( ) = > {
2020-05-20 20:18:48 +00:00
it ( 'sets the content size' , async ( ) = > {
2019-06-19 23:38:21 +00:00
// NB. The CI server has a very small screen. Attempting to size the window
// larger than the screen will limit the window's size to the screen and
// cause the test to fail.
const size = [ 456 , 567 ] ;
w . setContentSize ( size [ 0 ] , size [ 1 ] ) ;
2020-05-20 20:18:48 +00:00
await new Promise ( setImmediate ) ;
const after = w . getContentSize ( ) ;
expect ( after ) . to . deep . equal ( size ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2020-05-20 20:18:48 +00:00
it ( 'works for a frameless window' , async ( ) = > {
2019-06-19 23:38:21 +00:00
w . destroy ( ) ;
w = new BrowserWindow ( {
show : false ,
frame : false ,
width : 400 ,
height : 400
} ) ;
const size = [ 456 , 567 ] ;
w . setContentSize ( size [ 0 ] , size [ 1 ] ) ;
2020-05-20 20:18:48 +00:00
await new Promise ( setImmediate ) ;
const after = w . getContentSize ( ) ;
expect ( after ) . to . deep . equal ( size ) ;
2019-06-19 23:38:21 +00:00
} ) ;
} ) ;
describe ( 'BrowserWindow.setContentBounds(bounds)' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'sets the content size and position' , async ( ) = > {
2019-06-19 23:38:21 +00:00
const bounds = { x : 10 , y : 10 , width : 250 , height : 250 } ;
2023-02-23 23:53:53 +00:00
const resize = once ( w , 'resize' ) ;
2019-06-19 23:38:21 +00:00
w . setContentBounds ( bounds ) ;
2020-06-30 22:10:36 +00:00
await resize ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2020-06-30 22:10:36 +00:00
expectBoundsEqual ( w . getContentBounds ( ) , bounds ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'works for a frameless window' , async ( ) = > {
2019-06-19 23:38:21 +00:00
w . destroy ( ) ;
w = new BrowserWindow ( {
show : false ,
frame : false ,
width : 300 ,
height : 300
} ) ;
const bounds = { x : 10 , y : 10 , width : 250 , height : 250 } ;
2023-02-23 23:53:53 +00:00
const resize = once ( w , 'resize' ) ;
2019-06-19 23:38:21 +00:00
w . setContentBounds ( bounds ) ;
2020-06-30 22:10:36 +00:00
await resize ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2020-06-30 22:10:36 +00:00
expectBoundsEqual ( w . getContentBounds ( ) , bounds ) ;
2019-06-19 23:38:21 +00:00
} ) ;
} ) ;
2019-12-13 16:08:30 +00:00
describe ( 'BrowserWindow.getBackgroundColor()' , ( ) = > {
it ( 'returns default value if no backgroundColor is set' , ( ) = > {
w . destroy ( ) ;
w = new BrowserWindow ( { } ) ;
expect ( w . getBackgroundColor ( ) ) . to . equal ( '#FFFFFF' ) ;
} ) ;
2024-07-16 18:11:49 +00:00
2019-12-13 16:08:30 +00:00
it ( 'returns correct value if backgroundColor is set' , ( ) = > {
const backgroundColor = '#BBAAFF' ;
w . destroy ( ) ;
w = new BrowserWindow ( {
backgroundColor : backgroundColor
} ) ;
expect ( w . getBackgroundColor ( ) ) . to . equal ( backgroundColor ) ;
} ) ;
2024-07-16 18:11:49 +00:00
2019-12-13 16:08:30 +00:00
it ( 'returns correct value from setBackgroundColor()' , ( ) = > {
const backgroundColor = '#AABBFF' ;
w . destroy ( ) ;
w = new BrowserWindow ( { } ) ;
w . setBackgroundColor ( backgroundColor ) ;
expect ( w . getBackgroundColor ( ) ) . to . equal ( backgroundColor ) ;
} ) ;
2024-07-16 18:11:49 +00:00
it ( 'returns correct color with multiple passed formats' , async ( ) = > {
2022-03-21 17:35:54 +00:00
w . destroy ( ) ;
w = new BrowserWindow ( { } ) ;
2024-07-16 18:11:49 +00:00
await w . loadURL ( 'about:blank' ) ;
const colors = new Map ( [
[ 'blueviolet' , '#8A2BE2' ] ,
[ 'rgb(255, 0, 185)' , '#FF00B9' ] ,
[ 'hsl(155, 100%, 50%)' , '#00FF95' ] ,
[ '#355E3B' , '#355E3B' ]
] ) ;
for ( const [ color , hex ] of colors ) {
w . setBackgroundColor ( color ) ;
expect ( w . getBackgroundColor ( ) ) . to . equal ( hex ) ;
}
} ) ;
2022-03-21 17:35:54 +00:00
2024-07-16 18:11:49 +00:00
it ( 'can set the background color with transparency' , async ( ) = > {
w . destroy ( ) ;
w = new BrowserWindow ( { } ) ;
2022-03-21 17:35:54 +00:00
2024-07-16 18:11:49 +00:00
await w . loadURL ( 'about:blank' ) ;
2022-03-21 17:35:54 +00:00
2024-07-16 18:11:49 +00:00
const colors = new Map ( [
[ 'hsl(155, 100%, 50%)' , '#00FF95' ] ,
[ 'rgba(245, 40, 145, 0.8)' , '#F52891' ] ,
[ '#1D1F21d9' , '#1F21D9' ]
] ) ;
2022-03-21 17:35:54 +00:00
2024-07-16 18:11:49 +00:00
for ( const [ color , hex ] of colors ) {
w . setBackgroundColor ( color ) ;
expect ( w . getBackgroundColor ( ) ) . to . equal ( hex ) ;
}
2022-03-21 17:35:54 +00:00
} ) ;
2019-12-13 16:08:30 +00:00
} ) ;
2020-03-20 15:12:18 +00:00
describe ( 'BrowserWindow.getNormalBounds()' , ( ) = > {
describe ( 'Normal state' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'checks normal bounds after resize' , async ( ) = > {
2019-06-19 23:38:21 +00:00
const size = [ 300 , 400 ] ;
2023-02-23 23:53:53 +00:00
const resize = once ( w , 'resize' ) ;
2019-06-19 23:38:21 +00:00
w . setSize ( size [ 0 ] , size [ 1 ] ) ;
2020-06-30 22:10:36 +00:00
await resize ;
expectBoundsEqual ( w . getNormalBounds ( ) , w . getBounds ( ) ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2022-06-09 08:48:50 +00:00
2020-06-30 22:10:36 +00:00
it ( 'checks normal bounds after move' , async ( ) = > {
2019-06-19 23:38:21 +00:00
const pos = [ 10 , 10 ] ;
2023-02-23 23:53:53 +00:00
const move = once ( w , 'move' ) ;
2019-06-19 23:38:21 +00:00
w . setPosition ( pos [ 0 ] , pos [ 1 ] ) ;
2020-06-30 22:10:36 +00:00
await move ;
expectBoundsEqual ( w . getNormalBounds ( ) , w . getBounds ( ) ) ;
2019-06-19 23:38:21 +00:00
} ) ;
} ) ;
2020-04-01 15:22:32 +00:00
2020-03-20 15:12:18 +00:00
ifdescribe ( process . platform !== 'linux' ) ( 'Maximized state' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'checks normal bounds when maximized' , async ( ) = > {
2019-06-19 23:38:21 +00:00
const bounds = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
2019-06-19 23:38:21 +00:00
w . show ( ) ;
w . maximize ( ) ;
2020-06-30 22:10:36 +00:00
await maximize ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2022-06-09 08:48:50 +00:00
it ( 'updates normal bounds after resize and maximize' , async ( ) = > {
const size = [ 300 , 400 ] ;
2023-02-23 23:53:53 +00:00
const resize = once ( w , 'resize' ) ;
2022-06-09 08:48:50 +00:00
w . setSize ( size [ 0 ] , size [ 1 ] ) ;
await resize ;
const original = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
2022-06-09 08:48:50 +00:00
w . maximize ( ) ;
await maximize ;
const normal = w . getNormalBounds ( ) ;
const bounds = w . getBounds ( ) ;
expect ( normal ) . to . deep . equal ( original ) ;
expect ( normal ) . to . not . deep . equal ( bounds ) ;
2023-02-23 23:53:53 +00:00
const close = once ( w , 'close' ) ;
2022-06-09 08:48:50 +00:00
w . close ( ) ;
await close ;
} ) ;
it ( 'updates normal bounds after move and maximize' , async ( ) = > {
const pos = [ 10 , 10 ] ;
2023-02-23 23:53:53 +00:00
const move = once ( w , 'move' ) ;
2022-06-09 08:48:50 +00:00
w . setPosition ( pos [ 0 ] , pos [ 1 ] ) ;
await move ;
const original = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
2022-06-09 08:48:50 +00:00
w . maximize ( ) ;
await maximize ;
const normal = w . getNormalBounds ( ) ;
const bounds = w . getBounds ( ) ;
expect ( normal ) . to . deep . equal ( original ) ;
expect ( normal ) . to . not . deep . equal ( bounds ) ;
2023-02-23 23:53:53 +00:00
const close = once ( w , 'close' ) ;
2022-06-09 08:48:50 +00:00
w . close ( ) ;
await close ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'checks normal bounds when unmaximized' , async ( ) = > {
2019-06-19 23:38:21 +00:00
const bounds = w . getBounds ( ) ;
w . once ( 'maximize' , ( ) = > {
w . unmaximize ( ) ;
} ) ;
2023-02-23 23:53:53 +00:00
const unmaximize = once ( w , 'unmaximize' ) ;
2019-06-19 23:38:21 +00:00
w . show ( ) ;
w . maximize ( ) ;
2020-06-30 22:10:36 +00:00
await unmaximize ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2022-06-09 08:48:50 +00:00
2023-05-16 07:26:41 +00:00
it ( 'correctly reports maximized state after maximizing then minimizing' , async ( ) = > {
w . destroy ( ) ;
w = new BrowserWindow ( { show : false } ) ;
w . show ( ) ;
const maximize = once ( w , 'maximize' ) ;
w . maximize ( ) ;
await maximize ;
const minimize = once ( w , 'minimize' ) ;
w . minimize ( ) ;
await minimize ;
expect ( w . isMaximized ( ) ) . to . equal ( false ) ;
expect ( w . isMinimized ( ) ) . to . equal ( true ) ;
} ) ;
it ( 'correctly reports maximized state after maximizing then fullscreening' , async ( ) = > {
w . destroy ( ) ;
w = new BrowserWindow ( { show : false } ) ;
w . show ( ) ;
const maximize = once ( w , 'maximize' ) ;
w . maximize ( ) ;
await maximize ;
const enterFS = once ( w , 'enter-full-screen' ) ;
w . setFullScreen ( true ) ;
await enterFS ;
expect ( w . isMaximized ( ) ) . to . equal ( false ) ;
expect ( w . isFullScreen ( ) ) . to . equal ( true ) ;
} ) ;
2024-01-26 18:53:07 +00:00
it ( 'does not crash if maximized, minimized, then restored to maximized state' , ( done ) = > {
w . destroy ( ) ;
w = new BrowserWindow ( { show : false } ) ;
w . show ( ) ;
let count = 0 ;
w . on ( 'maximize' , ( ) = > {
if ( count === 0 ) syncSetTimeout ( ( ) = > { w . minimize ( ) ; } ) ;
count ++ ;
} ) ;
w . on ( 'minimize' , ( ) = > {
if ( count === 1 ) syncSetTimeout ( ( ) = > { w . restore ( ) ; } ) ;
count ++ ;
} ) ;
w . on ( 'restore' , ( ) = > {
try {
throw new Error ( 'hey!' ) ;
} catch ( e : any ) {
expect ( e . message ) . to . equal ( 'hey!' ) ;
done ( ) ;
}
} ) ;
w . maximize ( ) ;
} ) ;
2023-05-17 11:11:43 +00:00
it ( 'checks normal bounds for maximized transparent window' , async ( ) = > {
w . destroy ( ) ;
w = new BrowserWindow ( {
transparent : true ,
show : false
} ) ;
w . show ( ) ;
const bounds = w . getNormalBounds ( ) ;
const maximize = once ( w , 'maximize' ) ;
w . maximize ( ) ;
await maximize ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
} ) ;
2020-08-24 20:32:08 +00:00
it ( 'does not change size for a frameless window with min size' , async ( ) = > {
w . destroy ( ) ;
w = new BrowserWindow ( {
show : false ,
frame : false ,
width : 300 ,
height : 300 ,
minWidth : 300 ,
minHeight : 300
} ) ;
const bounds = w . getBounds ( ) ;
w . once ( 'maximize' , ( ) = > {
w . unmaximize ( ) ;
} ) ;
2023-02-23 23:53:53 +00:00
const unmaximize = once ( w , 'unmaximize' ) ;
2020-08-24 20:32:08 +00:00
w . show ( ) ;
w . maximize ( ) ;
await unmaximize ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
} ) ;
2022-06-09 08:48:50 +00:00
2022-01-31 21:10:57 +00:00
it ( 'correctly checks transparent window maximization state' , async ( ) = > {
2020-12-01 06:27:58 +00:00
w . destroy ( ) ;
w = new BrowserWindow ( {
show : false ,
width : 300 ,
height : 300 ,
transparent : true
} ) ;
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
2020-12-01 06:27:58 +00:00
w . show ( ) ;
w . maximize ( ) ;
await maximize ;
expect ( w . isMaximized ( ) ) . to . equal ( true ) ;
2023-02-23 23:53:53 +00:00
const unmaximize = once ( w , 'unmaximize' ) ;
2020-12-01 06:27:58 +00:00
w . unmaximize ( ) ;
await unmaximize ;
expect ( w . isMaximized ( ) ) . to . equal ( false ) ;
} ) ;
2022-06-09 08:48:50 +00:00
2021-09-21 10:04:32 +00:00
it ( 'returns the correct value for windows with an aspect ratio' , async ( ) = > {
w . destroy ( ) ;
w = new BrowserWindow ( {
show : false ,
fullscreenable : false
} ) ;
w . setAspectRatio ( 16 / 11 ) ;
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
2021-09-21 10:04:32 +00:00
w . show ( ) ;
w . maximize ( ) ;
await maximize ;
expect ( w . isMaximized ( ) ) . to . equal ( true ) ;
w . resizable = false ;
expect ( w . isMaximized ( ) ) . to . equal ( true ) ;
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2020-04-01 15:22:32 +00:00
2020-03-20 15:12:18 +00:00
ifdescribe ( process . platform !== 'linux' ) ( 'Minimized state' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'checks normal bounds when minimized' , async ( ) = > {
2019-06-19 23:38:21 +00:00
const bounds = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const minimize = once ( w , 'minimize' ) ;
2019-06-19 23:38:21 +00:00
w . show ( ) ;
w . minimize ( ) ;
2020-06-30 22:10:36 +00:00
await minimize ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2022-06-09 08:48:50 +00:00
it ( 'updates normal bounds after move and minimize' , async ( ) = > {
const pos = [ 10 , 10 ] ;
2023-02-23 23:53:53 +00:00
const move = once ( w , 'move' ) ;
2022-06-09 08:48:50 +00:00
w . setPosition ( pos [ 0 ] , pos [ 1 ] ) ;
await move ;
const original = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const minimize = once ( w , 'minimize' ) ;
2022-06-09 08:48:50 +00:00
w . minimize ( ) ;
await minimize ;
const normal = w . getNormalBounds ( ) ;
expect ( original ) . to . deep . equal ( normal ) ;
expectBoundsEqual ( normal , w . getBounds ( ) ) ;
} ) ;
it ( 'updates normal bounds after resize and minimize' , async ( ) = > {
const size = [ 300 , 400 ] ;
2023-02-23 23:53:53 +00:00
const resize = once ( w , 'resize' ) ;
2022-06-09 08:48:50 +00:00
w . setSize ( size [ 0 ] , size [ 1 ] ) ;
await resize ;
const original = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const minimize = once ( w , 'minimize' ) ;
2022-06-09 08:48:50 +00:00
w . minimize ( ) ;
await minimize ;
const normal = w . getNormalBounds ( ) ;
expect ( original ) . to . deep . equal ( normal ) ;
expectBoundsEqual ( normal , w . getBounds ( ) ) ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'checks normal bounds when restored' , async ( ) = > {
2019-06-19 23:38:21 +00:00
const bounds = w . getBounds ( ) ;
w . once ( 'minimize' , ( ) = > {
w . restore ( ) ;
} ) ;
2023-02-23 23:53:53 +00:00
const restore = once ( w , 'restore' ) ;
2019-06-19 23:38:21 +00:00
w . show ( ) ;
w . minimize ( ) ;
2020-06-30 22:10:36 +00:00
await restore ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2022-06-09 08:48:50 +00:00
2020-08-19 19:34:15 +00:00
it ( 'does not change size for a frameless window with min size' , async ( ) = > {
w . destroy ( ) ;
w = new BrowserWindow ( {
show : false ,
frame : false ,
width : 300 ,
height : 300 ,
minWidth : 300 ,
minHeight : 300
} ) ;
const bounds = w . getBounds ( ) ;
w . once ( 'minimize' , ( ) = > {
w . restore ( ) ;
} ) ;
2023-02-23 23:53:53 +00:00
const restore = once ( w , 'restore' ) ;
2020-08-19 19:34:15 +00:00
w . show ( ) ;
w . minimize ( ) ;
await restore ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2020-04-01 15:22:32 +00:00
2020-07-09 17:18:49 +00:00
ifdescribe ( process . platform === 'win32' ) ( 'Fullscreen state' , ( ) = > {
2020-04-21 03:25:18 +00:00
it ( 'with properties' , ( ) = > {
it ( 'can be set with the fullscreen constructor option' , ( ) = > {
w = new BrowserWindow ( { fullscreen : true } ) ;
expect ( w . fullScreen ) . to . be . true ( ) ;
} ) ;
2022-08-25 11:39:01 +00:00
it ( 'does not go fullscreen if roundedCorners are enabled' , async ( ) = > {
w = new BrowserWindow ( { frame : false , roundedCorners : false , fullscreen : true } ) ;
expect ( w . fullScreen ) . to . be . false ( ) ;
} ) ;
2020-04-21 03:25:18 +00:00
it ( 'can be changed' , ( ) = > {
w . fullScreen = false ;
expect ( w . fullScreen ) . to . be . false ( ) ;
w . fullScreen = true ;
expect ( w . fullScreen ) . to . be . true ( ) ;
} ) ;
2020-07-09 17:18:49 +00:00
it ( 'checks normal bounds when fullscreen\'ed' , async ( ) = > {
2020-04-21 03:25:18 +00:00
const bounds = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2020-04-21 03:25:18 +00:00
w . show ( ) ;
w . fullScreen = true ;
2020-06-30 22:10:36 +00:00
await enterFullScreen ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
2020-04-21 03:25:18 +00:00
} ) ;
2022-06-09 08:48:50 +00:00
it ( 'updates normal bounds after resize and fullscreen' , async ( ) = > {
const size = [ 300 , 400 ] ;
2023-02-23 23:53:53 +00:00
const resize = once ( w , 'resize' ) ;
2022-06-09 08:48:50 +00:00
w . setSize ( size [ 0 ] , size [ 1 ] ) ;
await resize ;
const original = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const fsc = once ( w , 'enter-full-screen' ) ;
2022-06-09 08:48:50 +00:00
w . fullScreen = true ;
await fsc ;
const normal = w . getNormalBounds ( ) ;
const bounds = w . getBounds ( ) ;
expect ( normal ) . to . deep . equal ( original ) ;
expect ( normal ) . to . not . deep . equal ( bounds ) ;
2023-02-23 23:53:53 +00:00
const close = once ( w , 'close' ) ;
2022-06-09 08:48:50 +00:00
w . close ( ) ;
await close ;
} ) ;
it ( 'updates normal bounds after move and fullscreen' , async ( ) = > {
const pos = [ 10 , 10 ] ;
2023-02-23 23:53:53 +00:00
const move = once ( w , 'move' ) ;
2022-06-09 08:48:50 +00:00
w . setPosition ( pos [ 0 ] , pos [ 1 ] ) ;
await move ;
const original = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const fsc = once ( w , 'enter-full-screen' ) ;
2022-06-09 08:48:50 +00:00
w . fullScreen = true ;
await fsc ;
const normal = w . getNormalBounds ( ) ;
const bounds = w . getBounds ( ) ;
expect ( normal ) . to . deep . equal ( original ) ;
expect ( normal ) . to . not . deep . equal ( bounds ) ;
2023-02-23 23:53:53 +00:00
const close = once ( w , 'close' ) ;
2022-06-09 08:48:50 +00:00
w . close ( ) ;
await close ;
} ) ;
2020-07-09 17:18:49 +00:00
it ( 'checks normal bounds when unfullscreen\'ed' , async ( ) = > {
2020-04-21 03:25:18 +00:00
const bounds = w . getBounds ( ) ;
w . once ( 'enter-full-screen' , ( ) = > {
w . fullScreen = false ;
} ) ;
2023-02-23 23:53:53 +00:00
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2020-04-21 03:25:18 +00:00
w . show ( ) ;
w . fullScreen = true ;
2020-06-30 22:10:36 +00:00
await leaveFullScreen ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
2019-06-19 23:38:21 +00:00
} ) ;
} ) ;
2020-04-01 15:22:32 +00:00
2020-04-21 03:25:18 +00:00
it ( 'with functions' , ( ) = > {
it ( 'can be set with the fullscreen constructor option' , ( ) = > {
w = new BrowserWindow ( { fullscreen : true } ) ;
expect ( w . isFullScreen ( ) ) . to . be . true ( ) ;
} ) ;
it ( 'can be changed' , ( ) = > {
2019-06-19 23:38:21 +00:00
w . setFullScreen ( false ) ;
2020-04-21 03:25:18 +00:00
expect ( w . isFullScreen ( ) ) . to . be . false ( ) ;
w . setFullScreen ( true ) ;
expect ( w . isFullScreen ( ) ) . to . be . true ( ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2020-04-21 03:25:18 +00:00
2020-07-09 17:18:49 +00:00
it ( 'checks normal bounds when fullscreen\'ed' , async ( ) = > {
2020-04-21 03:25:18 +00:00
const bounds = w . getBounds ( ) ;
w . show ( ) ;
2020-06-30 22:10:36 +00:00
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2020-04-21 03:25:18 +00:00
w . setFullScreen ( true ) ;
2020-06-30 22:10:36 +00:00
await enterFullScreen ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
2020-04-21 03:25:18 +00:00
} ) ;
2022-06-09 08:48:50 +00:00
it ( 'updates normal bounds after resize and fullscreen' , async ( ) = > {
const size = [ 300 , 400 ] ;
2023-02-23 23:53:53 +00:00
const resize = once ( w , 'resize' ) ;
2022-06-09 08:48:50 +00:00
w . setSize ( size [ 0 ] , size [ 1 ] ) ;
await resize ;
const original = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const fsc = once ( w , 'enter-full-screen' ) ;
2022-06-09 08:48:50 +00:00
w . setFullScreen ( true ) ;
await fsc ;
const normal = w . getNormalBounds ( ) ;
const bounds = w . getBounds ( ) ;
expect ( normal ) . to . deep . equal ( original ) ;
expect ( normal ) . to . not . deep . equal ( bounds ) ;
2023-02-23 23:53:53 +00:00
const close = once ( w , 'close' ) ;
2022-06-09 08:48:50 +00:00
w . close ( ) ;
await close ;
} ) ;
it ( 'updates normal bounds after move and fullscreen' , async ( ) = > {
const pos = [ 10 , 10 ] ;
2023-02-23 23:53:53 +00:00
const move = once ( w , 'move' ) ;
2022-06-09 08:48:50 +00:00
w . setPosition ( pos [ 0 ] , pos [ 1 ] ) ;
await move ;
const original = w . getBounds ( ) ;
2023-02-23 23:53:53 +00:00
const fsc = once ( w , 'enter-full-screen' ) ;
2022-06-09 08:48:50 +00:00
w . setFullScreen ( true ) ;
await fsc ;
const normal = w . getNormalBounds ( ) ;
const bounds = w . getBounds ( ) ;
expect ( normal ) . to . deep . equal ( original ) ;
expect ( normal ) . to . not . deep . equal ( bounds ) ;
2023-02-23 23:53:53 +00:00
const close = once ( w , 'close' ) ;
2022-06-09 08:48:50 +00:00
w . close ( ) ;
await close ;
} ) ;
2020-07-09 17:18:49 +00:00
it ( 'checks normal bounds when unfullscreen\'ed' , async ( ) = > {
2020-04-21 03:25:18 +00:00
const bounds = w . getBounds ( ) ;
w . show ( ) ;
2020-06-30 22:10:36 +00:00
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2020-04-21 03:25:18 +00:00
w . setFullScreen ( true ) ;
2020-06-30 22:10:36 +00:00
await enterFullScreen ;
2023-02-23 23:53:53 +00:00
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2020-06-30 22:10:36 +00:00
w . setFullScreen ( false ) ;
await leaveFullScreen ;
expectBoundsEqual ( w . getNormalBounds ( ) , bounds ) ;
2019-06-19 23:38:21 +00:00
} ) ;
} ) ;
2019-06-03 22:10:58 +00:00
} ) ;
} ) ;
} ) ;
2019-06-19 23:38:21 +00:00
ifdescribe ( process . platform === 'darwin' ) ( 'tabbed windows' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-06-03 22:10:58 +00:00
beforeEach ( ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false } ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2023-10-03 19:27:40 +00:00
afterEach ( closeAllWindows ) ;
2019-06-19 23:38:21 +00:00
describe ( 'BrowserWindow.selectPreviousTab()' , ( ) = > {
it ( 'does not throw' , ( ) = > {
expect ( ( ) = > {
w . selectPreviousTab ( ) ;
} ) . to . not . throw ( ) ;
} ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2019-06-19 23:38:21 +00:00
describe ( 'BrowserWindow.selectNextTab()' , ( ) = > {
it ( 'does not throw' , ( ) = > {
expect ( ( ) = > {
w . selectNextTab ( ) ;
} ) . to . not . throw ( ) ;
} ) ;
} ) ;
2023-07-10 08:43:37 +00:00
describe ( 'BrowserWindow.showAllTabs()' , ( ) = > {
it ( 'does not throw' , ( ) = > {
expect ( ( ) = > {
w . showAllTabs ( ) ;
} ) . to . not . throw ( ) ;
} ) ;
} ) ;
2019-06-19 23:38:21 +00:00
describe ( 'BrowserWindow.mergeAllWindows()' , ( ) = > {
it ( 'does not throw' , ( ) = > {
expect ( ( ) = > {
w . mergeAllWindows ( ) ;
} ) . to . not . throw ( ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.moveTabToNewWindow()' , ( ) = > {
it ( 'does not throw' , ( ) = > {
expect ( ( ) = > {
w . moveTabToNewWindow ( ) ;
} ) . to . not . throw ( ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.toggleTabBar()' , ( ) = > {
it ( 'does not throw' , ( ) = > {
expect ( ( ) = > {
w . toggleTabBar ( ) ;
} ) . to . not . throw ( ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.addTabbedWindow()' , ( ) = > {
it ( 'does not throw' , async ( ) = > {
const tabbedWindow = new BrowserWindow ( { } ) ;
expect ( ( ) = > {
w . addTabbedWindow ( tabbedWindow ) ;
} ) . to . not . throw ( ) ;
expect ( BrowserWindow . getAllWindows ( ) ) . to . have . lengthOf ( 2 ) ; // w + tabbedWindow
await closeWindow ( tabbedWindow , { assertNotWindows : false } ) ;
expect ( BrowserWindow . getAllWindows ( ) ) . to . have . lengthOf ( 1 ) ; // w
} ) ;
it ( 'throws when called on itself' , ( ) = > {
expect ( ( ) = > {
w . addTabbedWindow ( w ) ;
} ) . to . throw ( 'AddTabbedWindow cannot be called by a window on itself.' ) ;
} ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2023-10-03 19:27:40 +00:00
describe ( 'BrowserWindow.tabbingIdentifier' , ( ) = > {
it ( 'is undefined if no tabbingIdentifier was set' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . tabbingIdentifier ) . to . be . undefined ( 'tabbingIdentifier' ) ;
} ) ;
it ( 'returns the window tabbingIdentifier' , ( ) = > {
const w = new BrowserWindow ( { show : false , tabbingIdentifier : 'group1' } ) ;
expect ( w . tabbingIdentifier ) . to . equal ( 'group1' ) ;
} ) ;
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2020-03-16 21:03:35 +00:00
describe ( 'autoHideMenuBar state' , ( ) = > {
2019-06-19 23:38:21 +00:00
afterEach ( closeAllWindows ) ;
2020-03-16 21:03:35 +00:00
it ( 'for properties' , ( ) = > {
it ( 'can be set with autoHideMenuBar constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , autoHideMenuBar : true } ) ;
expect ( w . autoHideMenuBar ) . to . be . true ( 'autoHideMenuBar' ) ;
} ) ;
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . autoHideMenuBar ) . to . be . false ( 'autoHideMenuBar' ) ;
w . autoHideMenuBar = true ;
expect ( w . autoHideMenuBar ) . to . be . true ( 'autoHideMenuBar' ) ;
w . autoHideMenuBar = false ;
expect ( w . autoHideMenuBar ) . to . be . false ( 'autoHideMenuBar' ) ;
} ) ;
} ) ;
it ( 'for functions' , ( ) = > {
it ( 'can be set with autoHideMenuBar constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , autoHideMenuBar : true } ) ;
expect ( w . isMenuBarAutoHide ( ) ) . to . be . true ( 'autoHideMenuBar' ) ;
} ) ;
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isMenuBarAutoHide ( ) ) . to . be . false ( 'autoHideMenuBar' ) ;
w . setAutoHideMenuBar ( true ) ;
expect ( w . isMenuBarAutoHide ( ) ) . to . be . true ( 'autoHideMenuBar' ) ;
w . setAutoHideMenuBar ( false ) ;
expect ( w . isMenuBarAutoHide ( ) ) . to . be . false ( 'autoHideMenuBar' ) ;
} ) ;
2019-06-19 23:38:21 +00:00
} ) ;
} ) ;
describe ( 'BrowserWindow.capturePage(rect)' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'returns a Promise with a Buffer' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-06-19 23:38:21 +00:00
const image = await w . capturePage ( {
x : 0 ,
y : 0 ,
width : 100 ,
height : 100
} ) ;
expect ( image . isEmpty ( ) ) . to . equal ( true ) ;
} ) ;
2022-10-05 17:51:33 +00:00
ifit ( process . platform === 'darwin' ) ( 'honors the stayHidden argument' , async ( ) = > {
const w = new BrowserWindow ( {
webPreferences : {
nodeIntegration : true ,
contextIsolation : false
}
} ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'visibilitychange.html' ) ) ;
{
2023-02-23 23:53:53 +00:00
const [ , visibilityState , hidden ] = await once ( ipcMain , 'pong' ) ;
2022-10-05 17:51:33 +00:00
expect ( visibilityState ) . to . equal ( 'visible' ) ;
expect ( hidden ) . to . be . false ( 'hidden' ) ;
}
w . hide ( ) ;
{
2023-02-23 23:53:53 +00:00
const [ , visibilityState , hidden ] = await once ( ipcMain , 'pong' ) ;
2022-10-05 17:51:33 +00:00
expect ( visibilityState ) . to . equal ( 'hidden' ) ;
expect ( hidden ) . to . be . true ( 'hidden' ) ;
}
await w . capturePage ( { x : 0 , y : 0 , width : 0 , height : 0 } , { stayHidden : true } ) ;
const visible = await w . webContents . executeJavaScript ( 'document.visibilityState' ) ;
expect ( visible ) . to . equal ( 'hidden' ) ;
} ) ;
2023-10-12 07:35:23 +00:00
it ( 'resolves when the window is occluded' , async ( ) = > {
const w1 = new BrowserWindow ( { show : false } ) ;
w1 . loadFile ( path . join ( fixtures , 'pages' , 'a.html' ) ) ;
await once ( w1 , 'ready-to-show' ) ;
w1 . show ( ) ;
const w2 = new BrowserWindow ( { show : false } ) ;
w2 . loadFile ( path . join ( fixtures , 'pages' , 'a.html' ) ) ;
await once ( w2 , 'ready-to-show' ) ;
w2 . show ( ) ;
const visibleImage = await w1 . capturePage ( ) ;
expect ( visibleImage . isEmpty ( ) ) . to . equal ( false ) ;
} ) ;
it ( 'resolves when the window is not visible' , async ( ) = > {
2021-03-09 13:51:44 +00:00
const w = new BrowserWindow ( { show : false } ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'a.html' ) ) ;
2023-02-23 23:53:53 +00:00
await once ( w , 'ready-to-show' ) ;
2021-03-09 13:51:44 +00:00
w . show ( ) ;
const visibleImage = await w . capturePage ( ) ;
expect ( visibleImage . isEmpty ( ) ) . to . equal ( false ) ;
2023-10-12 07:35:23 +00:00
w . minimize ( ) ;
2021-03-09 13:51:44 +00:00
const hiddenImage = await w . capturePage ( ) ;
2023-10-12 07:35:23 +00:00
expect ( hiddenImage . isEmpty ( ) ) . to . equal ( false ) ;
2022-03-21 23:38:03 +00:00
} ) ;
2019-06-19 23:38:21 +00:00
it ( 'preserves transparency' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false , transparent : true } ) ;
2020-09-15 18:48:39 +00:00
w . loadFile ( path . join ( fixtures , 'pages' , 'theme-color.html' ) ) ;
2023-02-23 23:53:53 +00:00
await once ( w , 'ready-to-show' ) ;
2019-06-03 22:10:58 +00:00
w . show ( ) ;
2019-06-19 23:38:21 +00:00
const image = await w . capturePage ( ) ;
const imgBuffer = image . toPNG ( ) ;
// Check the 25th byte in the PNG.
// Values can be 0,2,3,4, or 6. We want 6, which is RGB + Alpha
expect ( imgBuffer [ 25 ] ) . to . equal ( 6 ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.setProgressBar(progress)' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-06-19 23:38:21 +00:00
before ( ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false } ) ;
2019-06-19 23:38:21 +00:00
} ) ;
after ( async ( ) = > {
await closeWindow ( w ) ;
w = null as unknown as BrowserWindow ;
} ) ;
it ( 'sets the progress' , ( ) = > {
expect ( ( ) = > {
if ( process . platform === 'darwin' ) {
app . dock . setIcon ( path . join ( fixtures , 'assets' , 'logo.png' ) ) ;
}
w . setProgressBar ( 0.5 ) ;
if ( process . platform === 'darwin' ) {
app . dock . setIcon ( null as any ) ;
}
w . setProgressBar ( - 1 ) ;
} ) . to . not . throw ( ) ;
} ) ;
it ( 'sets the progress using "paused" mode' , ( ) = > {
expect ( ( ) = > {
w . setProgressBar ( 0.5 , { mode : 'paused' } ) ;
} ) . to . not . throw ( ) ;
} ) ;
it ( 'sets the progress using "error" mode' , ( ) = > {
expect ( ( ) = > {
w . setProgressBar ( 0.5 , { mode : 'error' } ) ;
} ) . to . not . throw ( ) ;
} ) ;
it ( 'sets the progress using "normal" mode' , ( ) = > {
expect ( ( ) = > {
w . setProgressBar ( 0.5 , { mode : 'normal' } ) ;
} ) . to . not . throw ( ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.setAlwaysOnTop(flag, level)' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-07-26 22:53:31 +00:00
2021-06-23 06:09:09 +00:00
afterEach ( closeAllWindows ) ;
2019-06-19 23:38:21 +00:00
beforeEach ( ( ) = > {
2020-07-14 01:13:34 +00:00
w = new BrowserWindow ( { show : true } ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2019-07-26 22:53:31 +00:00
2019-06-19 23:38:21 +00:00
it ( 'sets the window as always on top' , ( ) = > {
2019-07-26 22:53:31 +00:00
expect ( w . isAlwaysOnTop ( ) ) . to . be . false ( 'is alwaysOnTop' ) ;
2019-06-19 23:38:21 +00:00
w . setAlwaysOnTop ( true , 'screen-saver' ) ;
2019-07-26 22:53:31 +00:00
expect ( w . isAlwaysOnTop ( ) ) . to . be . true ( 'is not alwaysOnTop' ) ;
2019-06-19 23:38:21 +00:00
w . setAlwaysOnTop ( false ) ;
2019-07-26 22:53:31 +00:00
expect ( w . isAlwaysOnTop ( ) ) . to . be . false ( 'is alwaysOnTop' ) ;
2019-06-19 23:38:21 +00:00
w . setAlwaysOnTop ( true ) ;
2019-07-26 22:53:31 +00:00
expect ( w . isAlwaysOnTop ( ) ) . to . be . true ( 'is not alwaysOnTop' ) ;
2019-06-19 23:38:21 +00:00
} ) ;
2023-05-10 14:47:48 +00:00
ifit ( process . platform === 'darwin' ) ( 'resets the windows level on minimize' , async ( ) = > {
2019-07-26 22:53:31 +00:00
expect ( w . isAlwaysOnTop ( ) ) . to . be . false ( 'is alwaysOnTop' ) ;
2019-06-19 23:38:21 +00:00
w . setAlwaysOnTop ( true , 'screen-saver' ) ;
2019-07-26 22:53:31 +00:00
expect ( w . isAlwaysOnTop ( ) ) . to . be . true ( 'is not alwaysOnTop' ) ;
2023-05-10 14:47:48 +00:00
const minimized = once ( w , 'minimize' ) ;
2019-06-19 23:38:21 +00:00
w . minimize ( ) ;
2023-05-10 14:47:48 +00:00
await minimized ;
2019-07-26 22:53:31 +00:00
expect ( w . isAlwaysOnTop ( ) ) . to . be . false ( 'is alwaysOnTop' ) ;
2023-05-10 14:47:48 +00:00
const restored = once ( w , 'restore' ) ;
2019-06-19 23:38:21 +00:00
w . restore ( ) ;
2023-05-10 14:47:48 +00:00
await restored ;
2019-07-26 22:53:31 +00:00
expect ( w . isAlwaysOnTop ( ) ) . to . be . true ( 'is not alwaysOnTop' ) ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'causes the right value to be emitted on `always-on-top-changed`' , async ( ) = > {
2023-06-22 18:38:52 +00:00
const alwaysOnTopChanged = once ( w , 'always-on-top-changed' ) as Promise < [ any , boolean ] > ;
2019-07-26 22:53:31 +00:00
expect ( w . isAlwaysOnTop ( ) ) . to . be . false ( 'is alwaysOnTop' ) ;
w . setAlwaysOnTop ( true ) ;
2020-06-30 22:10:36 +00:00
const [ , alwaysOnTop ] = await alwaysOnTopChanged ;
expect ( alwaysOnTop ) . to . be . true ( 'is not alwaysOnTop' ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2021-06-23 06:09:09 +00:00
ifit ( process . platform === 'darwin' ) ( 'honors the alwaysOnTop level of a child window' , ( ) = > {
w = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { parent : w } ) ;
c . setAlwaysOnTop ( true , 'screen-saver' ) ;
expect ( w . isAlwaysOnTop ( ) ) . to . be . false ( ) ;
expect ( c . isAlwaysOnTop ( ) ) . to . be . true ( 'child is not always on top' ) ;
2023-09-05 02:22:41 +00:00
expect ( c . _getAlwaysOnTopLevel ( ) ) . to . equal ( 'screen-saver' ) ;
2021-06-23 06:09:09 +00:00
} ) ;
2019-06-03 22:10:58 +00:00
} ) ;
2019-08-26 16:47:32 +00:00
describe ( 'preconnect feature' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-08-26 16:47:32 +00:00
2023-02-19 09:24:24 +00:00
let server : http.Server ;
let url : string ;
2019-08-26 16:47:32 +00:00
let connections = 0 ;
beforeEach ( async ( ) = > {
connections = 0 ;
server = http . createServer ( ( req , res ) = > {
if ( req . url === '/link' ) {
res . setHeader ( 'Content-type' , 'text/html' ) ;
2020-03-20 15:12:18 +00:00
res . end ( '<head><link rel="preconnect" href="//example.com" /></head><body>foo</body>' ) ;
2019-08-26 16:47:32 +00:00
return ;
}
res . end ( ) ;
} ) ;
2019-11-01 20:37:02 +00:00
server . on ( 'connection' , ( ) = > { connections ++ ; } ) ;
2023-02-20 11:30:57 +00:00
url = ( await listen ( server ) ) . url ;
2019-08-26 16:47:32 +00:00
} ) ;
afterEach ( async ( ) = > {
server . close ( ) ;
await closeWindow ( w ) ;
w = null as unknown as BrowserWindow ;
server = null as unknown as http . Server ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'calling preconnect() connects to the server' , async ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false } ) ;
w . webContents . on ( 'did-start-navigation' , ( event , url ) = > {
w . webContents . session . preconnect ( { url , numSockets : 4 } ) ;
2019-08-26 16:47:32 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
await w . loadURL ( url ) ;
expect ( connections ) . to . equal ( 4 ) ;
2019-08-26 16:47:32 +00:00
} ) ;
it ( 'does not preconnect unless requested' , async ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false } ) ;
2019-08-26 16:47:32 +00:00
await w . loadURL ( url ) ;
expect ( connections ) . to . equal ( 1 ) ;
} ) ;
it ( 'parses <link rel=preconnect>' , async ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : true } ) ;
2023-02-23 23:53:53 +00:00
const p = once ( w . webContents . session , 'preconnect' ) ;
2019-08-26 16:47:32 +00:00
w . loadURL ( url + '/link' ) ;
const [ , preconnectUrl , allowCredentials ] = await p ;
expect ( preconnectUrl ) . to . equal ( 'http://example.com/' ) ;
expect ( allowCredentials ) . to . be . true ( 'allowCredentials' ) ;
} ) ;
} ) ;
2019-07-08 22:44:37 +00:00
describe ( 'BrowserWindow.setAutoHideCursor(autoHide)' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-07-08 22:44:37 +00:00
beforeEach ( ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false } ) ;
2019-07-08 22:44:37 +00:00
} ) ;
afterEach ( async ( ) = > {
await closeWindow ( w ) ;
w = null as unknown as BrowserWindow ;
} ) ;
ifit ( process . platform === 'darwin' ) ( 'on macOS' , ( ) = > {
it ( 'allows changing cursor auto-hiding' , ( ) = > {
expect ( ( ) = > {
w . setAutoHideCursor ( false ) ;
w . setAutoHideCursor ( true ) ;
} ) . to . not . throw ( ) ;
} ) ;
} ) ;
ifit ( process . platform !== 'darwin' ) ( 'on non-macOS platforms' , ( ) = > {
it ( 'is not available' , ( ) = > {
expect ( w . setAutoHideCursor ) . to . be . undefined ( 'setAutoHideCursor function' ) ;
} ) ;
} ) ;
} ) ;
ifdescribe ( process . platform === 'darwin' ) ( 'BrowserWindow.setWindowButtonVisibility()' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'does not throw' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-08 22:44:37 +00:00
expect ( ( ) = > {
w . setWindowButtonVisibility ( true ) ;
w . setWindowButtonVisibility ( false ) ;
} ) . to . not . throw ( ) ;
} ) ;
2021-01-19 10:12:09 +00:00
it ( 'changes window button visibility for normal window' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( true ) ;
w . setWindowButtonVisibility ( false ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( false ) ;
w . setWindowButtonVisibility ( true ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( true ) ;
} ) ;
it ( 'changes window button visibility for frameless window' , ( ) = > {
const w = new BrowserWindow ( { show : false , frame : false } ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( false ) ;
w . setWindowButtonVisibility ( true ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( true ) ;
w . setWindowButtonVisibility ( false ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( false ) ;
} ) ;
it ( 'changes window button visibility for hiddenInset window' , ( ) = > {
const w = new BrowserWindow ( { show : false , frame : false , titleBarStyle : 'hiddenInset' } ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( true ) ;
w . setWindowButtonVisibility ( false ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( false ) ;
w . setWindowButtonVisibility ( true ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( true ) ;
} ) ;
2021-08-04 00:31:12 +00:00
// Buttons of customButtonsOnHover are always hidden unless hovered.
it ( 'does not change window button visibility for customButtonsOnHover window' , ( ) = > {
2021-01-19 10:12:09 +00:00
const w = new BrowserWindow ( { show : false , frame : false , titleBarStyle : 'customButtonsOnHover' } ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( false ) ;
w . setWindowButtonVisibility ( true ) ;
2021-08-04 00:31:12 +00:00
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( false ) ;
w . setWindowButtonVisibility ( false ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( false ) ;
2019-07-08 22:44:37 +00:00
} ) ;
2022-06-21 07:35:53 +00:00
it ( 'correctly updates when entering/exiting fullscreen for hidden style' , async ( ) = > {
const w = new BrowserWindow ( { show : false , frame : false , titleBarStyle : 'hidden' } ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( true ) ;
w . setWindowButtonVisibility ( false ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( false ) ;
2023-02-23 23:53:53 +00:00
const enterFS = once ( w , 'enter-full-screen' ) ;
2022-06-21 07:35:53 +00:00
w . setFullScreen ( true ) ;
await enterFS ;
2023-02-23 23:53:53 +00:00
const leaveFS = once ( w , 'leave-full-screen' ) ;
2022-06-21 07:35:53 +00:00
w . setFullScreen ( false ) ;
await leaveFS ;
w . setWindowButtonVisibility ( true ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( true ) ;
} ) ;
it ( 'correctly updates when entering/exiting fullscreen for hiddenInset style' , async ( ) = > {
const w = new BrowserWindow ( { show : false , frame : false , titleBarStyle : 'hiddenInset' } ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( true ) ;
w . setWindowButtonVisibility ( false ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( false ) ;
2023-02-23 23:53:53 +00:00
const enterFS = once ( w , 'enter-full-screen' ) ;
2022-06-21 07:35:53 +00:00
w . setFullScreen ( true ) ;
await enterFS ;
2023-02-23 23:53:53 +00:00
const leaveFS = once ( w , 'leave-full-screen' ) ;
2022-06-21 07:35:53 +00:00
w . setFullScreen ( false ) ;
await leaveFS ;
w . setWindowButtonVisibility ( true ) ;
expect ( w . _getWindowButtonVisibility ( ) ) . to . equal ( true ) ;
} ) ;
2019-07-08 22:44:37 +00:00
} ) ;
ifdescribe ( process . platform === 'darwin' ) ( 'BrowserWindow.setVibrancy(type)' , ( ) = > {
2022-10-11 17:11:58 +00:00
afterEach ( closeAllWindows ) ;
2019-07-08 22:44:37 +00:00
it ( 'allows setting, changing, and removing the vibrancy' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-08 22:44:37 +00:00
expect ( ( ) = > {
2023-07-01 20:22:55 +00:00
w . setVibrancy ( 'titlebar' ) ;
w . setVibrancy ( 'selection' ) ;
2019-07-08 22:44:37 +00:00
w . setVibrancy ( null ) ;
2023-07-01 20:22:55 +00:00
w . setVibrancy ( 'menu' ) ;
2019-07-08 22:44:37 +00:00
w . setVibrancy ( '' as any ) ;
} ) . to . not . throw ( ) ;
} ) ;
2021-06-16 06:39:20 +00:00
it ( 'does not crash if vibrancy is set to an invalid value' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( ( ) = > {
w . setVibrancy ( 'i-am-not-a-valid-vibrancy-type' as any ) ;
} ) . to . not . throw ( ) ;
} ) ;
2019-07-08 22:44:37 +00:00
} ) ;
2020-12-16 05:30:39 +00:00
ifdescribe ( process . platform === 'darwin' ) ( 'trafficLightPosition' , ( ) = > {
const pos = { x : 10 , y : 10 } ;
2020-03-05 22:22:12 +00:00
afterEach ( closeAllWindows ) ;
2023-02-17 10:06:32 +00:00
describe ( 'BrowserWindow.getWindowButtonPosition(pos)' , ( ) = > {
it ( 'returns null when there is no custom position' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . getWindowButtonPosition ( ) ) . to . be . null ( 'getWindowButtonPosition' ) ;
} ) ;
it ( 'gets position property for "hidden" titleBarStyle' , ( ) = > {
const w = new BrowserWindow ( { show : false , titleBarStyle : 'hidden' , trafficLightPosition : pos } ) ;
expect ( w . getWindowButtonPosition ( ) ) . to . deep . equal ( pos ) ;
} ) ;
it ( 'gets position property for "customButtonsOnHover" titleBarStyle' , ( ) = > {
const w = new BrowserWindow ( { show : false , titleBarStyle : 'customButtonsOnHover' , trafficLightPosition : pos } ) ;
expect ( w . getWindowButtonPosition ( ) ) . to . deep . equal ( pos ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.setWindowButtonPosition(pos)' , ( ) = > {
it ( 'resets the position when null is passed' , ( ) = > {
const w = new BrowserWindow ( { show : false , titleBarStyle : 'hidden' , trafficLightPosition : pos } ) ;
w . setWindowButtonPosition ( null ) ;
expect ( w . getWindowButtonPosition ( ) ) . to . be . null ( 'setWindowButtonPosition' ) ;
} ) ;
it ( 'sets position property for "hidden" titleBarStyle' , ( ) = > {
const w = new BrowserWindow ( { show : false , titleBarStyle : 'hidden' , trafficLightPosition : pos } ) ;
const newPos = { x : 20 , y : 20 } ;
w . setWindowButtonPosition ( newPos ) ;
expect ( w . getWindowButtonPosition ( ) ) . to . deep . equal ( newPos ) ;
} ) ;
it ( 'sets position property for "customButtonsOnHover" titleBarStyle' , ( ) = > {
const w = new BrowserWindow ( { show : false , titleBarStyle : 'customButtonsOnHover' , trafficLightPosition : pos } ) ;
const newPos = { x : 20 , y : 20 } ;
w . setWindowButtonPosition ( newPos ) ;
expect ( w . getWindowButtonPosition ( ) ) . to . deep . equal ( newPos ) ;
} ) ;
} ) ;
2020-03-05 22:22:12 +00:00
} ) ;
2019-07-08 22:44:37 +00:00
ifdescribe ( process . platform === 'win32' ) ( 'BrowserWindow.setAppDetails(options)' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'supports setting the app details' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-08 22:44:37 +00:00
const iconPath = path . join ( fixtures , 'assets' , 'icon.ico' ) ;
expect ( ( ) = > {
w . setAppDetails ( { appId : 'my.app.id' } ) ;
w . setAppDetails ( { appIconPath : iconPath , appIconIndex : 0 } ) ;
w . setAppDetails ( { appIconPath : iconPath } ) ;
w . setAppDetails ( { relaunchCommand : 'my-app.exe arg1 arg2' , relaunchDisplayName : 'My app name' } ) ;
w . setAppDetails ( { relaunchCommand : 'my-app.exe arg1 arg2' } ) ;
w . setAppDetails ( { relaunchDisplayName : 'My app name' } ) ;
w . setAppDetails ( {
appId : 'my.app.id' ,
appIconPath : iconPath ,
appIconIndex : 0 ,
relaunchCommand : 'my-app.exe arg1 arg2' ,
relaunchDisplayName : 'My app name'
} ) ;
w . setAppDetails ( { } ) ;
} ) . to . not . throw ( ) ;
expect ( ( ) = > {
( w . setAppDetails as any ) ( ) ;
} ) . to . throw ( 'Insufficient number of arguments.' ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.fromId(id)' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'returns the window with id' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2020-06-29 01:22:55 +00:00
expect ( BrowserWindow . fromId ( w . id ) ! . id ) . to . equal ( w . id ) ;
2019-07-08 22:44:37 +00:00
} ) ;
} ) ;
2022-05-11 18:34:33 +00:00
describe ( 'Opening a BrowserWindow from a link' , ( ) = > {
let appProcess : childProcess.ChildProcessWithoutNullStreams | undefined ;
afterEach ( ( ) = > {
if ( appProcess && ! appProcess . killed ) {
appProcess . kill ( ) ;
appProcess = undefined ;
}
} ) ;
it ( 'can properly open and load a new window from a link' , async ( ) = > {
const appPath = path . join ( __dirname , 'fixtures' , 'apps' , 'open-new-window-from-link' ) ;
appProcess = childProcess . spawn ( process . execPath , [ appPath ] ) ;
2023-02-23 23:53:53 +00:00
const [ code ] = await once ( appProcess , 'exit' ) ;
2022-05-11 18:34:33 +00:00
expect ( code ) . to . equal ( 0 ) ;
} ) ;
} ) ;
2019-07-08 22:44:37 +00:00
describe ( 'BrowserWindow.fromWebContents(webContents)' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'returns the window with the webContents' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-08 22:44:37 +00:00
const found = BrowserWindow . fromWebContents ( w . webContents ) ;
2019-09-27 11:07:55 +00:00
expect ( found ! . id ) . to . equal ( w . id ) ;
2019-07-08 22:44:37 +00:00
} ) ;
2019-09-27 11:07:55 +00:00
it ( 'returns null for webContents without a BrowserWindow' , ( ) = > {
2023-02-16 14:41:41 +00:00
const contents = ( webContents as typeof ElectronInternal . WebContents ) . create ( ) ;
2019-07-08 22:44:37 +00:00
try {
2019-09-27 11:07:55 +00:00
expect ( BrowserWindow . fromWebContents ( contents ) ) . to . be . null ( 'BrowserWindow.fromWebContents(contents)' ) ;
2019-07-08 22:44:37 +00:00
} finally {
contents . destroy ( ) ;
}
} ) ;
2020-09-14 20:49:57 +00:00
it ( 'returns the correct window for a BrowserView webcontents' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
const bv = new BrowserView ( ) ;
w . setBrowserView ( bv ) ;
defer ( ( ) = > {
w . removeBrowserView ( bv ) ;
2022-12-14 21:07:38 +00:00
bv . webContents . destroy ( ) ;
2020-09-14 20:49:57 +00:00
} ) ;
await bv . webContents . loadURL ( 'about:blank' ) ;
expect ( BrowserWindow . fromWebContents ( bv . webContents ) ! . id ) . to . equal ( w . id ) ;
} ) ;
it ( 'returns the correct window for a WebView webcontents' , async ( ) = > {
const w = new BrowserWindow ( { show : false , webPreferences : { webviewTag : true } } ) ;
w . loadURL ( 'data:text/html,<webview src="data:text/html,hi"></webview>' ) ;
// NOTE(nornagon): Waiting for 'did-attach-webview' is a workaround for
// https://github.com/electron/electron/issues/25413, and is not integral
// to the test.
2023-02-23 23:53:53 +00:00
const p = once ( w . webContents , 'did-attach-webview' ) ;
2023-06-22 18:38:52 +00:00
const [ , webviewContents ] = await once ( app , 'web-contents-created' ) as [ any , WebContents ] ;
2020-09-14 20:49:57 +00:00
expect ( BrowserWindow . fromWebContents ( webviewContents ) ! . id ) . to . equal ( w . id ) ;
await p ;
} ) ;
2022-03-16 23:23:14 +00:00
it ( 'is usable immediately on browser-window-created' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . loadURL ( 'about:blank' ) ;
w . webContents . executeJavaScript ( 'window.open(""); null' ) ;
2023-02-23 23:53:53 +00:00
const [ win , winFromWebContents ] = await new Promise < any > ( ( resolve ) = > {
2022-03-16 23:23:14 +00:00
app . once ( 'browser-window-created' , ( e , win ) = > {
resolve ( [ win , BrowserWindow . fromWebContents ( win . webContents ) ] ) ;
} ) ;
} ) ;
expect ( winFromWebContents ) . to . equal ( win ) ;
} ) ;
2019-07-08 22:44:37 +00:00
} ) ;
describe ( 'BrowserWindow.openDevTools()' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'does not crash for frameless window' , ( ) = > {
const w = new BrowserWindow ( { show : false , frame : false } ) ;
w . webContents . openDevTools ( ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.fromBrowserView(browserView)' , ( ) = > {
afterEach ( closeAllWindows ) ;
2020-11-17 19:12:02 +00:00
it ( 'returns the window with the BrowserView' , ( ) = > {
2019-07-08 22:44:37 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-11-01 20:37:02 +00:00
const bv = new BrowserView ( ) ;
2019-07-08 22:44:37 +00:00
w . setBrowserView ( bv ) ;
2020-07-09 15:48:39 +00:00
defer ( ( ) = > {
w . removeBrowserView ( bv ) ;
2022-12-14 21:07:38 +00:00
bv . webContents . destroy ( ) ;
2020-07-09 15:48:39 +00:00
} ) ;
2019-07-08 22:44:37 +00:00
expect ( BrowserWindow . fromBrowserView ( bv ) ! . id ) . to . equal ( w . id ) ;
} ) ;
2020-11-17 19:12:02 +00:00
it ( 'returns the window when there are multiple BrowserViews' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
const bv1 = new BrowserView ( ) ;
w . addBrowserView ( bv1 ) ;
const bv2 = new BrowserView ( ) ;
w . addBrowserView ( bv2 ) ;
defer ( ( ) = > {
w . removeBrowserView ( bv1 ) ;
w . removeBrowserView ( bv2 ) ;
2022-12-14 21:07:38 +00:00
bv1 . webContents . destroy ( ) ;
bv2 . webContents . destroy ( ) ;
2020-11-17 19:12:02 +00:00
} ) ;
expect ( BrowserWindow . fromBrowserView ( bv1 ) ! . id ) . to . equal ( w . id ) ;
expect ( BrowserWindow . fromBrowserView ( bv2 ) ! . id ) . to . equal ( w . id ) ;
} ) ;
2019-07-08 22:44:37 +00:00
it ( 'returns undefined if not attached' , ( ) = > {
2019-11-01 20:37:02 +00:00
const bv = new BrowserView ( ) ;
2020-07-09 15:48:39 +00:00
defer ( ( ) = > {
2022-12-14 21:07:38 +00:00
bv . webContents . destroy ( ) ;
2020-07-09 15:48:39 +00:00
} ) ;
2019-07-08 22:44:37 +00:00
expect ( BrowserWindow . fromBrowserView ( bv ) ) . to . be . null ( 'BrowserWindow associated with bv' ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.setOpacity(opacity)' , ( ) = > {
afterEach ( closeAllWindows ) ;
2019-08-07 07:17:32 +00:00
ifdescribe ( process . platform !== 'linux' ) ( ( 'Windows and Mac' ) , ( ) = > {
it ( 'make window with initial opacity' , ( ) = > {
const w = new BrowserWindow ( { show : false , opacity : 0.5 } ) ;
expect ( w . getOpacity ( ) ) . to . equal ( 0.5 ) ;
} ) ;
it ( 'allows setting the opacity' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( ( ) = > {
w . setOpacity ( 0.0 ) ;
expect ( w . getOpacity ( ) ) . to . equal ( 0.0 ) ;
w . setOpacity ( 0.5 ) ;
expect ( w . getOpacity ( ) ) . to . equal ( 0.5 ) ;
w . setOpacity ( 1.0 ) ;
expect ( w . getOpacity ( ) ) . to . equal ( 1.0 ) ;
} ) . to . not . throw ( ) ;
} ) ;
it ( 'clamps opacity to [0.0...1.0]' , ( ) = > {
const w = new BrowserWindow ( { show : false , opacity : 0.5 } ) ;
w . setOpacity ( 100 ) ;
expect ( w . getOpacity ( ) ) . to . equal ( 1.0 ) ;
w . setOpacity ( - 100 ) ;
2019-07-08 22:44:37 +00:00
expect ( w . getOpacity ( ) ) . to . equal ( 0.0 ) ;
2019-08-07 07:17:32 +00:00
} ) ;
} ) ;
ifdescribe ( process . platform === 'linux' ) ( ( 'Linux' ) , ( ) = > {
it ( 'sets 1 regardless of parameter' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . setOpacity ( 0 ) ;
expect ( w . getOpacity ( ) ) . to . equal ( 1.0 ) ;
2019-07-08 22:44:37 +00:00
w . setOpacity ( 0.5 ) ;
expect ( w . getOpacity ( ) ) . to . equal ( 1.0 ) ;
2019-08-07 07:17:32 +00:00
} ) ;
2019-07-08 22:44:37 +00:00
} ) ;
} ) ;
describe ( 'BrowserWindow.setShape(rects)' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'allows setting shape' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( ( ) = > {
w . setShape ( [ ] ) ;
w . setShape ( [ { x : 0 , y : 0 , width : 100 , height : 100 } ] ) ;
w . setShape ( [ { x : 0 , y : 0 , width : 100 , height : 100 } , { x : 0 , y : 200 , width : 1000 , height : 100 } ] ) ;
w . setShape ( [ ] ) ;
} ) . to . not . throw ( ) ;
} ) ;
} ) ;
describe ( '"useContentSize" option' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'make window created with content size when used' , ( ) = > {
const w = new BrowserWindow ( {
show : false ,
width : 400 ,
height : 400 ,
useContentSize : true
} ) ;
const contentSize = w . getContentSize ( ) ;
expect ( contentSize ) . to . deep . equal ( [ 400 , 400 ] ) ;
} ) ;
it ( 'make window created with window size when not used' , ( ) = > {
const w = new BrowserWindow ( {
show : false ,
width : 400 ,
2019-11-01 20:37:02 +00:00
height : 400
2019-07-08 22:44:37 +00:00
} ) ;
const size = w . getSize ( ) ;
expect ( size ) . to . deep . equal ( [ 400 , 400 ] ) ;
} ) ;
it ( 'works for a frameless window' , ( ) = > {
const w = new BrowserWindow ( {
show : false ,
frame : false ,
width : 400 ,
height : 400 ,
useContentSize : true
} ) ;
const contentSize = w . getContentSize ( ) ;
expect ( contentSize ) . to . deep . equal ( [ 400 , 400 ] ) ;
const size = w . getSize ( ) ;
expect ( size ) . to . deep . equal ( [ 400 , 400 ] ) ;
} ) ;
} ) ;
2024-06-27 12:56:36 +00:00
describe ( '"titleBarStyle" option' , ( ) = > {
2021-07-01 19:25:40 +00:00
const testWindowsOverlay = async ( style : any ) = > {
const w = new BrowserWindow ( {
show : false ,
width : 400 ,
height : 400 ,
titleBarStyle : style ,
webPreferences : {
nodeIntegration : true ,
contextIsolation : false
} ,
titleBarOverlay : true
} ) ;
const overlayHTML = path . join ( __dirname , 'fixtures' , 'pages' , 'overlay.html' ) ;
2021-08-11 18:07:36 +00:00
if ( process . platform === 'darwin' ) {
await w . loadFile ( overlayHTML ) ;
} else {
2023-02-23 23:53:53 +00:00
const overlayReady = once ( ipcMain , 'geometrychange' ) ;
2021-08-11 18:07:36 +00:00
await w . loadFile ( overlayHTML ) ;
await overlayReady ;
}
2021-07-01 19:25:40 +00:00
const overlayEnabled = await w . webContents . executeJavaScript ( 'navigator.windowControlsOverlay.visible' ) ;
expect ( overlayEnabled ) . to . be . true ( 'overlayEnabled' ) ;
const overlayRect = await w . webContents . executeJavaScript ( 'getJSOverlayProperties()' ) ;
expect ( overlayRect . y ) . to . equal ( 0 ) ;
2021-08-11 18:07:36 +00:00
if ( process . platform === 'darwin' ) {
expect ( overlayRect . x ) . to . be . greaterThan ( 0 ) ;
} else {
expect ( overlayRect . x ) . to . equal ( 0 ) ;
}
2021-07-01 19:25:40 +00:00
expect ( overlayRect . width ) . to . be . greaterThan ( 0 ) ;
expect ( overlayRect . height ) . to . be . greaterThan ( 0 ) ;
const cssOverlayRect = await w . webContents . executeJavaScript ( 'getCssOverlayProperties();' ) ;
expect ( cssOverlayRect ) . to . deep . equal ( overlayRect ) ;
2023-02-23 23:53:53 +00:00
const geometryChange = once ( ipcMain , 'geometrychange' ) ;
2021-07-01 19:25:40 +00:00
w . setBounds ( { width : 800 } ) ;
const [ , newOverlayRect ] = await geometryChange ;
expect ( newOverlayRect . width ) . to . equal ( overlayRect . width + 400 ) ;
} ;
2024-06-27 12:56:36 +00:00
2022-05-23 14:33:39 +00:00
afterEach ( async ( ) = > {
await closeAllWindows ( ) ;
ipcMain . removeAllListeners ( 'geometrychange' ) ;
} ) ;
2024-06-27 12:56:36 +00:00
2019-07-08 22:44:37 +00:00
it ( 'creates browser window with hidden title bar' , ( ) = > {
const w = new BrowserWindow ( {
show : false ,
width : 400 ,
height : 400 ,
titleBarStyle : 'hidden'
} ) ;
const contentSize = w . getContentSize ( ) ;
expect ( contentSize ) . to . deep . equal ( [ 400 , 400 ] ) ;
} ) ;
2024-06-27 12:56:36 +00:00
2021-08-11 18:07:36 +00:00
ifit ( process . platform === 'darwin' ) ( 'creates browser window with hidden inset title bar' , ( ) = > {
2019-07-08 22:44:37 +00:00
const w = new BrowserWindow ( {
show : false ,
width : 400 ,
height : 400 ,
titleBarStyle : 'hiddenInset'
} ) ;
const contentSize = w . getContentSize ( ) ;
expect ( contentSize ) . to . deep . equal ( [ 400 , 400 ] ) ;
} ) ;
2024-06-27 12:56:36 +00:00
2021-07-01 19:25:40 +00:00
it ( 'sets Window Control Overlay with hidden title bar' , async ( ) = > {
await testWindowsOverlay ( 'hidden' ) ;
} ) ;
2024-06-27 12:56:36 +00:00
2021-08-11 18:07:36 +00:00
ifit ( process . platform === 'darwin' ) ( 'sets Window Control Overlay with hidden inset title bar' , async ( ) = > {
2021-07-01 19:25:40 +00:00
await testWindowsOverlay ( 'hiddenInset' ) ;
} ) ;
2022-07-11 09:45:01 +00:00
2024-06-27 12:56:36 +00:00
ifdescribe ( process . platform !== 'darwin' ) ( 'when an invalid titleBarStyle is initially set' , ( ) = > {
2022-07-11 09:45:01 +00:00
let w : BrowserWindow ;
beforeEach ( ( ) = > {
w = new BrowserWindow ( {
show : false ,
webPreferences : {
nodeIntegration : true ,
contextIsolation : false
} ,
titleBarOverlay : {
color : '#0000f0' ,
symbolColor : '#ffffff'
} ,
titleBarStyle : 'hiddenInset'
} ) ;
} ) ;
afterEach ( async ( ) = > {
await closeAllWindows ( ) ;
} ) ;
it ( 'does not crash changing minimizability ' , ( ) = > {
expect ( ( ) = > {
w . setMinimizable ( false ) ;
} ) . to . not . throw ( ) ;
} ) ;
it ( 'does not crash changing maximizability' , ( ) = > {
expect ( ( ) = > {
w . setMaximizable ( false ) ;
} ) . to . not . throw ( ) ;
} ) ;
} ) ;
2019-07-08 22:44:37 +00:00
} ) ;
2024-06-27 12:56:36 +00:00
describe ( '"titleBarOverlay" option' , ( ) = > {
2022-01-24 22:09:21 +00:00
const testWindowsOverlayHeight = async ( size : any ) = > {
const w = new BrowserWindow ( {
show : false ,
width : 400 ,
height : 400 ,
titleBarStyle : 'hidden' ,
webPreferences : {
nodeIntegration : true ,
contextIsolation : false
} ,
titleBarOverlay : {
height : size
}
} ) ;
2024-06-27 12:56:36 +00:00
2022-01-24 22:09:21 +00:00
const overlayHTML = path . join ( __dirname , 'fixtures' , 'pages' , 'overlay.html' ) ;
if ( process . platform === 'darwin' ) {
await w . loadFile ( overlayHTML ) ;
} else {
2023-02-23 23:53:53 +00:00
const overlayReady = once ( ipcMain , 'geometrychange' ) ;
2022-01-24 22:09:21 +00:00
await w . loadFile ( overlayHTML ) ;
await overlayReady ;
}
2024-06-27 12:56:36 +00:00
2022-01-24 22:09:21 +00:00
const overlayEnabled = await w . webContents . executeJavaScript ( 'navigator.windowControlsOverlay.visible' ) ;
expect ( overlayEnabled ) . to . be . true ( 'overlayEnabled' ) ;
const overlayRectPreMax = await w . webContents . executeJavaScript ( 'getJSOverlayProperties()' ) ;
2022-05-16 16:14:27 +00:00
2022-01-24 22:09:21 +00:00
expect ( overlayRectPreMax . y ) . to . equal ( 0 ) ;
if ( process . platform === 'darwin' ) {
expect ( overlayRectPreMax . x ) . to . be . greaterThan ( 0 ) ;
} else {
expect ( overlayRectPreMax . x ) . to . equal ( 0 ) ;
}
2024-06-27 12:56:36 +00:00
expect ( overlayRectPreMax . width ) . to . be . greaterThan ( 0 ) ;
2022-01-24 22:09:21 +00:00
expect ( overlayRectPreMax . height ) . to . equal ( size ) ;
2024-06-27 12:56:36 +00:00
// 'maximize' event is not emitted on Linux in CI.
if ( process . platform !== 'linux' && ! w . isMaximized ( ) ) {
const maximize = once ( w , 'maximize' ) ;
w . show ( ) ;
w . maximize ( ) ;
await maximize ;
expect ( w . isMaximized ( ) ) . to . be . true ( 'not maximized' ) ;
const overlayRectPostMax = await w . webContents . executeJavaScript ( 'getJSOverlayProperties()' ) ;
expect ( overlayRectPostMax . height ) . to . equal ( size ) ;
}
2022-01-24 22:09:21 +00:00
} ;
2024-06-27 12:56:36 +00:00
2022-05-23 14:33:39 +00:00
afterEach ( async ( ) = > {
await closeAllWindows ( ) ;
ipcMain . removeAllListeners ( 'geometrychange' ) ;
} ) ;
2024-06-27 12:56:36 +00:00
2022-01-24 22:09:21 +00:00
it ( 'sets Window Control Overlay with title bar height of 40' , async ( ) = > {
await testWindowsOverlayHeight ( 40 ) ;
} ) ;
} ) ;
2024-06-27 12:56:36 +00:00
ifdescribe ( process . platform !== 'darwin' ) ( 'BrowserWindow.setTitlebarOverlay' , ( ) = > {
2022-05-23 14:33:39 +00:00
afterEach ( async ( ) = > {
await closeAllWindows ( ) ;
ipcMain . removeAllListeners ( 'geometrychange' ) ;
} ) ;
2022-05-16 16:14:27 +00:00
2024-06-27 12:56:36 +00:00
it ( 'throws when an invalid titleBarStyle is initially set' , ( ) = > {
2022-05-17 15:50:27 +00:00
const win = new BrowserWindow ( {
show : false ,
webPreferences : {
nodeIntegration : true ,
contextIsolation : false
} ,
titleBarOverlay : {
color : '#0000f0' ,
symbolColor : '#ffffff'
} ,
titleBarStyle : 'hiddenInset'
} ) ;
expect ( ( ) = > {
win . setTitleBarOverlay ( {
color : '#000000'
} ) ;
2024-06-27 12:56:36 +00:00
} ) . to . throw ( 'Titlebar overlay is not enabled' ) ;
2022-05-17 15:50:27 +00:00
} ) ;
2022-05-16 16:14:27 +00:00
it ( 'correctly updates the height of the overlay' , async ( ) = > {
2022-05-23 14:33:39 +00:00
const testOverlay = async ( w : BrowserWindow , size : Number , firstRun : boolean ) = > {
2022-05-16 16:14:27 +00:00
const overlayHTML = path . join ( __dirname , 'fixtures' , 'pages' , 'overlay.html' ) ;
2023-02-23 23:53:53 +00:00
const overlayReady = once ( ipcMain , 'geometrychange' ) ;
2022-05-23 14:33:39 +00:00
await w . loadFile ( overlayHTML ) ;
if ( firstRun ) {
await overlayReady ;
}
2022-05-16 16:14:27 +00:00
const overlayEnabled = await w . webContents . executeJavaScript ( 'navigator.windowControlsOverlay.visible' ) ;
expect ( overlayEnabled ) . to . be . true ( 'overlayEnabled' ) ;
2024-06-27 12:56:36 +00:00
2022-05-16 16:14:27 +00:00
const { height : preMaxHeight } = await w . webContents . executeJavaScript ( 'getJSOverlayProperties()' ) ;
2024-06-27 12:56:36 +00:00
expect ( preMaxHeight ) . to . equal ( size ) ;
2022-05-16 16:14:27 +00:00
2024-06-27 12:56:36 +00:00
// 'maximize' event is not emitted on Linux in CI.
if ( process . platform !== 'linux' && ! w . isMaximized ( ) ) {
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
2022-05-16 16:14:27 +00:00
w . show ( ) ;
w . maximize ( ) ;
2024-06-27 12:56:36 +00:00
2022-05-16 16:14:27 +00:00
await maximize ;
2024-06-27 12:56:36 +00:00
expect ( w . isMaximized ( ) ) . to . be . true ( 'not maximized' ) ;
2022-05-16 16:14:27 +00:00
2024-06-27 12:56:36 +00:00
const { x , y , width , height } = await w . webContents . executeJavaScript ( 'getJSOverlayProperties()' ) ;
expect ( x ) . to . equal ( 0 ) ;
expect ( y ) . to . equal ( 0 ) ;
expect ( width ) . to . be . greaterThan ( 0 ) ;
expect ( height ) . to . equal ( size ) ;
}
2022-05-16 16:14:27 +00:00
} ;
const INITIAL_SIZE = 40 ;
const w = new BrowserWindow ( {
show : false ,
width : 400 ,
height : 400 ,
titleBarStyle : 'hidden' ,
webPreferences : {
nodeIntegration : true ,
contextIsolation : false
} ,
titleBarOverlay : {
height : INITIAL_SIZE
}
} ) ;
2022-05-23 14:33:39 +00:00
await testOverlay ( w , INITIAL_SIZE , true ) ;
2022-05-16 16:14:27 +00:00
w . setTitleBarOverlay ( {
height : INITIAL_SIZE + 10
} ) ;
2022-05-23 14:33:39 +00:00
await testOverlay ( w , INITIAL_SIZE + 10 , false ) ;
2022-05-16 16:14:27 +00:00
} ) ;
} ) ;
2019-07-08 22:44:37 +00:00
ifdescribe ( process . platform === 'darwin' ) ( '"enableLargerThanScreen" option' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'can move the window out of screen' , ( ) = > {
2020-03-25 02:13:43 +00:00
const w = new BrowserWindow ( { show : true , enableLargerThanScreen : true } ) ;
w . setPosition ( - 10 , 50 ) ;
const after = w . getPosition ( ) ;
expect ( after ) . to . deep . equal ( [ - 10 , 50 ] ) ;
} ) ;
it ( 'cannot move the window behind menu bar' , ( ) = > {
2019-07-08 22:44:37 +00:00
const w = new BrowserWindow ( { show : true , enableLargerThanScreen : true } ) ;
w . setPosition ( - 10 , - 10 ) ;
const after = w . getPosition ( ) ;
2020-03-25 02:13:43 +00:00
expect ( after [ 1 ] ) . to . be . at . least ( 0 ) ;
2019-07-08 22:44:37 +00:00
} ) ;
2020-06-09 18:52:14 +00:00
it ( 'can move the window behind menu bar if it has no frame' , ( ) = > {
const w = new BrowserWindow ( { show : true , enableLargerThanScreen : true , frame : false } ) ;
w . setPosition ( - 10 , - 10 ) ;
const after = w . getPosition ( ) ;
expect ( after [ 0 ] ) . to . be . equal ( - 10 ) ;
expect ( after [ 1 ] ) . to . be . equal ( - 10 ) ;
} ) ;
2019-07-08 22:44:37 +00:00
it ( 'without it, cannot move the window out of screen' , ( ) = > {
const w = new BrowserWindow ( { show : true , enableLargerThanScreen : false } ) ;
w . setPosition ( - 10 , - 10 ) ;
const after = w . getPosition ( ) ;
expect ( after [ 1 ] ) . to . be . at . least ( 0 ) ;
} ) ;
it ( 'can set the window larger than screen' , ( ) = > {
const w = new BrowserWindow ( { show : true , enableLargerThanScreen : true } ) ;
const size = screen . getPrimaryDisplay ( ) . size ;
size . width += 100 ;
size . height += 100 ;
w . setSize ( size . width , size . height ) ;
expectBoundsEqual ( w . getSize ( ) , [ size . width , size . height ] ) ;
} ) ;
it ( 'without it, cannot set the window larger than screen' , ( ) = > {
const w = new BrowserWindow ( { show : true , enableLargerThanScreen : false } ) ;
const size = screen . getPrimaryDisplay ( ) . size ;
size . width += 100 ;
size . height += 100 ;
w . setSize ( size . width , size . height ) ;
expect ( w . getSize ( ) [ 1 ] ) . to . at . most ( screen . getPrimaryDisplay ( ) . size . height ) ;
} ) ;
} ) ;
ifdescribe ( process . platform === 'darwin' ) ( '"zoomToPageWidth" option' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'sets the window width to the page width when used' , ( ) = > {
const w = new BrowserWindow ( {
show : false ,
width : 500 ,
height : 400 ,
zoomToPageWidth : true
} ) ;
w . maximize ( ) ;
expect ( w . getSize ( ) [ 0 ] ) . to . equal ( 500 ) ;
} ) ;
} ) ;
describe ( '"tabbingIdentifier" option' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'can be set on a window' , ( ) = > {
expect ( ( ) = > {
2023-05-25 01:09:17 +00:00
/* eslint-disable-next-line no-new */
2019-07-08 22:44:37 +00:00
new BrowserWindow ( {
tabbingIdentifier : 'group1'
} ) ;
2023-05-25 01:09:17 +00:00
/* eslint-disable-next-line no-new */
2019-07-08 22:44:37 +00:00
new BrowserWindow ( {
tabbingIdentifier : 'group2' ,
frame : false
} ) ;
} ) . not . to . throw ( ) ;
} ) ;
} ) ;
2019-07-16 04:13:32 +00:00
describe ( '"webPreferences" option' , ( ) = > {
afterEach ( ( ) = > { ipcMain . removeAllListeners ( 'answer' ) ; } ) ;
afterEach ( closeAllWindows ) ;
describe ( '"preload" option' , ( ) = > {
2020-03-05 22:22:12 +00:00
const doesNotLeakSpec = ( name : string , webPrefs : { nodeIntegration : boolean , sandbox : boolean , contextIsolation : boolean } ) = > {
2019-07-16 04:13:32 +00:00
it ( name , async ( ) = > {
const w = new BrowserWindow ( {
webPreferences : {
. . . webPrefs ,
preload : path.resolve ( fixtures , 'module' , 'empty.js' )
} ,
show : false
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'no-leak.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , result ] = await once ( ipcMain , 'leak-result' ) ;
2019-07-16 04:13:32 +00:00
expect ( result ) . to . have . property ( 'require' , 'undefined' ) ;
expect ( result ) . to . have . property ( 'exports' , 'undefined' ) ;
expect ( result ) . to . have . property ( 'windowExports' , 'undefined' ) ;
expect ( result ) . to . have . property ( 'windowPreload' , 'undefined' ) ;
expect ( result ) . to . have . property ( 'windowRequire' , 'undefined' ) ;
} ) ;
} ;
doesNotLeakSpec ( 'does not leak require' , {
nodeIntegration : false ,
sandbox : false ,
contextIsolation : false
} ) ;
doesNotLeakSpec ( 'does not leak require when sandbox is enabled' , {
nodeIntegration : false ,
sandbox : true ,
contextIsolation : false
} ) ;
doesNotLeakSpec ( 'does not leak require when context isolation is enabled' , {
nodeIntegration : false ,
sandbox : false ,
contextIsolation : true
} ) ;
doesNotLeakSpec ( 'does not leak require when context isolation and sandbox are enabled' , {
nodeIntegration : false ,
sandbox : true ,
contextIsolation : true
} ) ;
2019-12-02 18:09:47 +00:00
it ( 'does not leak any node globals on the window object with nodeIntegration is disabled' , async ( ) = > {
let w = new BrowserWindow ( {
webPreferences : {
contextIsolation : false ,
nodeIntegration : false ,
preload : path.resolve ( fixtures , 'module' , 'empty.js' )
} ,
show : false
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'globals.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , notIsolated ] = await once ( ipcMain , 'leak-result' ) ;
2019-12-02 18:09:47 +00:00
expect ( notIsolated ) . to . have . property ( 'globals' ) ;
w . destroy ( ) ;
w = new BrowserWindow ( {
webPreferences : {
contextIsolation : true ,
nodeIntegration : false ,
preload : path.resolve ( fixtures , 'module' , 'empty.js' )
} ,
show : false
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'globals.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , isolated ] = await once ( ipcMain , 'leak-result' ) ;
2019-12-02 18:09:47 +00:00
expect ( isolated ) . to . have . property ( 'globals' ) ;
const notIsolatedGlobals = new Set ( notIsolated . globals ) ;
for ( const isolatedGlobal of isolated . globals ) {
notIsolatedGlobals . delete ( isolatedGlobal ) ;
}
2022-06-16 07:46:11 +00:00
expect ( [ . . . notIsolatedGlobals ] ) . to . deep . equal ( [ ] , 'non-isolated renderer should have no additional globals' ) ;
2019-12-02 18:09:47 +00:00
} ) ;
2019-07-16 04:13:32 +00:00
it ( 'loads the script before other scripts in window' , async ( ) = > {
const preload = path . join ( fixtures , 'module' , 'set-global.js' ) ;
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
nodeIntegration : true ,
2021-03-01 21:52:29 +00:00
contextIsolation : false ,
2019-07-16 04:13:32 +00:00
preload
}
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'preload.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , test ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( test ) . to . eql ( 'preload' ) ;
} ) ;
it ( 'has synchronous access to all eventual window APIs' , async ( ) = > {
const preload = path . join ( fixtures , 'module' , 'access-blink-apis.js' ) ;
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
nodeIntegration : true ,
2021-03-01 21:52:29 +00:00
contextIsolation : false ,
2019-07-16 04:13:32 +00:00
preload
}
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'preload.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , test ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( test ) . to . be . an ( 'object' ) ;
expect ( test . atPreload ) . to . be . an ( 'array' ) ;
expect ( test . atLoad ) . to . be . an ( 'array' ) ;
expect ( test . atPreload ) . to . deep . equal ( test . atLoad , 'should have access to the same window APIs' ) ;
} ) ;
} ) ;
describe ( 'session preload scripts' , function ( ) {
const preloads = [
path . join ( fixtures , 'module' , 'set-global-preload-1.js' ) ,
path . join ( fixtures , 'module' , 'set-global-preload-2.js' ) ,
path . relative ( process . cwd ( ) , path . join ( fixtures , 'module' , 'set-global-preload-3.js' ) )
] ;
const defaultSession = session . defaultSession ;
beforeEach ( ( ) = > {
expect ( defaultSession . getPreloads ( ) ) . to . deep . equal ( [ ] ) ;
defaultSession . setPreloads ( preloads ) ;
} ) ;
afterEach ( ( ) = > {
defaultSession . setPreloads ( [ ] ) ;
} ) ;
it ( 'can set multiple session preload script' , ( ) = > {
expect ( defaultSession . getPreloads ( ) ) . to . deep . equal ( preloads ) ;
} ) ;
const generateSpecs = ( description : string , sandbox : boolean ) = > {
describe ( description , ( ) = > {
2019-10-09 17:59:08 +00:00
it ( 'loads the script before other scripts in window including normal preloads' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox ,
2021-03-01 21:52:29 +00:00
preload : path.join ( fixtures , 'module' , 'get-global-preload.js' ) ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
w . loadURL ( 'about:blank' ) ;
2023-02-23 23:53:53 +00:00
const [ , preload1 , preload2 , preload3 ] = await once ( ipcMain , 'vars' ) ;
2019-10-09 17:59:08 +00:00
expect ( preload1 ) . to . equal ( 'preload-1' ) ;
expect ( preload2 ) . to . equal ( 'preload-1-2' ) ;
expect ( preload3 ) . to . be . undefined ( 'preload 3' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
} ) ;
} ;
2020-03-20 20:28:31 +00:00
2019-07-16 04:13:32 +00:00
generateSpecs ( 'without sandbox' , false ) ;
generateSpecs ( 'with sandbox' , true ) ;
} ) ;
describe ( '"additionalArguments" option' , ( ) = > {
it ( 'adds extra args to process.argv in the renderer process' , async ( ) = > {
const preload = path . join ( fixtures , 'module' , 'check-arguments.js' ) ;
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
nodeIntegration : true ,
preload ,
additionalArguments : [ '--my-magic-arg' ]
}
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'blank.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , argv ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( argv ) . to . include ( '--my-magic-arg' ) ;
} ) ;
it ( 'adds extra value args to process.argv in the renderer process' , async ( ) = > {
const preload = path . join ( fixtures , 'module' , 'check-arguments.js' ) ;
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
nodeIntegration : true ,
preload ,
additionalArguments : [ '--my-magic-arg=foo' ]
}
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'blank.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , argv ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( argv ) . to . include ( '--my-magic-arg=foo' ) ;
} ) ;
} ) ;
describe ( '"node-integration" option' , ( ) = > {
it ( 'disables node integration by default' , async ( ) = > {
const preload = path . join ( fixtures , 'module' , 'send-later.js' ) ;
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
2021-03-01 21:52:29 +00:00
preload ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'blank.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , typeofProcess , typeofBuffer ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( typeofProcess ) . to . equal ( 'undefined' ) ;
expect ( typeofBuffer ) . to . equal ( 'undefined' ) ;
} ) ;
} ) ;
describe ( '"sandbox" option' , ( ) = > {
2020-04-22 22:53:12 +00:00
const preload = path . join ( path . resolve ( __dirname , 'fixtures' ) , 'module' , 'preload-sandbox.js' ) ;
2019-07-16 04:13:32 +00:00
2023-02-19 09:24:24 +00:00
let server : http.Server ;
let serverUrl : string ;
2019-07-16 04:13:32 +00:00
2023-02-20 11:30:57 +00:00
before ( async ( ) = > {
2019-07-16 04:13:32 +00:00
server = http . createServer ( ( request , response ) = > {
switch ( request . url ) {
case '/cross-site' :
response . end ( ` <html><body><h1> ${ request . url } </h1></body></html> ` ) ;
break ;
default :
throw new Error ( ` unsupported endpoint: ${ request . url } ` ) ;
}
} ) ;
2023-02-20 11:30:57 +00:00
serverUrl = ( await listen ( server ) ) . url ;
2019-07-16 04:13:32 +00:00
} ) ;
after ( ( ) = > {
server . close ( ) ;
} ) ;
it ( 'exposes ipcRenderer to preload script' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true ,
2021-03-01 21:52:29 +00:00
preload ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'preload.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , test ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( test ) . to . equal ( 'preload' ) ;
} ) ;
it ( 'exposes ipcRenderer to preload script (path has special chars)' , async ( ) = > {
const preloadSpecialChars = path . join ( fixtures , 'module' , 'preload-sandboxæø åü.js' ) ;
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true ,
2021-03-01 21:52:29 +00:00
preload : preloadSpecialChars ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'preload.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , test ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( test ) . to . equal ( 'preload' ) ;
} ) ;
it ( 'exposes "loaded" event to preload script' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true ,
preload
}
} ) ;
w . loadURL ( 'about:blank' ) ;
2023-02-23 23:53:53 +00:00
await once ( ipcMain , 'process-loaded' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
it ( 'exposes "exit" event to preload script' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true ,
2021-03-01 21:52:29 +00:00
preload ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
2019-11-14 22:09:03 +00:00
const htmlPath = path . join ( __dirname , 'fixtures' , 'api' , 'sandbox.html?exit-event' ) ;
2019-07-16 04:13:32 +00:00
const pageUrl = 'file://' + htmlPath ;
w . loadURL ( pageUrl ) ;
2023-02-23 23:53:53 +00:00
const [ , url ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
const expectedUrl = process . platform === 'win32'
2023-09-07 06:50:14 +00:00
? 'file:///' + htmlPath . replaceAll ( '\\' , '/' )
2019-07-16 04:13:32 +00:00
: pageUrl ;
expect ( url ) . to . equal ( expectedUrl ) ;
} ) ;
2022-09-15 16:33:08 +00:00
it ( 'exposes full EventEmitter object to preload script' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true ,
preload : path.join ( fixtures , 'module' , 'preload-eventemitter.js' )
}
} ) ;
w . loadURL ( 'about:blank' ) ;
2023-02-23 23:53:53 +00:00
const [ , rendererEventEmitterProperties ] = await once ( ipcMain , 'answer' ) ;
2023-06-15 14:42:27 +00:00
const { EventEmitter } = require ( 'node:events' ) ;
2022-09-15 16:33:08 +00:00
const emitter = new EventEmitter ( ) ;
const browserEventEmitterProperties = [ ] ;
let currentObj = emitter ;
do {
browserEventEmitterProperties . push ( . . . Object . getOwnPropertyNames ( currentObj ) ) ;
} while ( ( currentObj = Object . getPrototypeOf ( currentObj ) ) ) ;
expect ( rendererEventEmitterProperties ) . to . deep . equal ( browserEventEmitterProperties ) ;
} ) ;
2019-07-16 04:13:32 +00:00
it ( 'should open windows in same domain with cross-scripting enabled' , async ( ) = > {
const w = new BrowserWindow ( {
2020-11-10 17:06:03 +00:00
show : true ,
2019-07-16 04:13:32 +00:00
webPreferences : {
sandbox : true ,
2021-03-01 21:52:29 +00:00
preload ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
2020-11-10 17:06:03 +00:00
w . webContents . setWindowOpenHandler ( ( ) = > ( {
action : 'allow' ,
overrideBrowserWindowOptions : {
webPreferences : {
preload
}
}
} ) ) ;
2019-11-14 22:09:03 +00:00
const htmlPath = path . join ( __dirname , 'fixtures' , 'api' , 'sandbox.html?window-open' ) ;
2019-07-16 04:13:32 +00:00
const pageUrl = 'file://' + htmlPath ;
2023-02-23 23:53:53 +00:00
const answer = once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
w . loadURL ( pageUrl ) ;
2023-06-22 18:38:52 +00:00
const [ , { url , frameName , options } ] = await once ( w . webContents , 'did-create-window' ) as [ BrowserWindow , Electron . DidCreateWindowDetails ] ;
2019-07-16 04:13:32 +00:00
const expectedUrl = process . platform === 'win32'
2023-09-07 06:50:14 +00:00
? 'file:///' + htmlPath . replaceAll ( '\\' , '/' )
2019-07-16 04:13:32 +00:00
: pageUrl ;
expect ( url ) . to . equal ( expectedUrl ) ;
expect ( frameName ) . to . equal ( 'popup!' ) ;
expect ( options . width ) . to . equal ( 500 ) ;
expect ( options . height ) . to . equal ( 600 ) ;
const [ , html ] = await answer ;
expect ( html ) . to . equal ( '<h1>scripting from opener</h1>' ) ;
} ) ;
it ( 'should open windows in another domain with cross-scripting disabled' , async ( ) = > {
const w = new BrowserWindow ( {
2020-11-10 17:06:03 +00:00
show : true ,
2019-07-16 04:13:32 +00:00
webPreferences : {
sandbox : true ,
2021-03-01 21:52:29 +00:00
preload ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
2020-11-10 17:06:03 +00:00
w . webContents . setWindowOpenHandler ( ( ) = > ( {
action : 'allow' ,
overrideBrowserWindowOptions : {
webPreferences : {
preload
}
}
} ) ) ;
2019-07-16 04:13:32 +00:00
w . loadFile (
2019-11-14 22:09:03 +00:00
path . join ( __dirname , 'fixtures' , 'api' , 'sandbox.html' ) ,
2019-07-16 04:13:32 +00:00
{ search : 'window-open-external' }
) ;
// Wait for a message from the main window saying that it's ready.
2023-02-23 23:53:53 +00:00
await once ( ipcMain , 'opener-loaded' ) ;
2019-07-16 04:13:32 +00:00
// Ask the opener to open a popup with window.opener.
const expectedPopupUrl = ` ${ serverUrl } /cross-site ` ; // Set in "sandbox.html".
w . webContents . send ( 'open-the-popup' , expectedPopupUrl ) ;
// The page is going to open a popup that it won't be able to close.
// We have to close it from here later.
2023-06-22 18:38:52 +00:00
const [ , popupWindow ] = await once ( app , 'browser-window-created' ) as [ any , BrowserWindow ] ;
2019-07-16 04:13:32 +00:00
// Ask the popup window for details.
2023-02-23 23:53:53 +00:00
const detailsAnswer = once ( ipcMain , 'child-loaded' ) ;
2019-07-16 04:13:32 +00:00
popupWindow . webContents . send ( 'provide-details' ) ;
const [ , openerIsNull , , locationHref ] = await detailsAnswer ;
expect ( openerIsNull ) . to . be . false ( 'window.opener is null' ) ;
expect ( locationHref ) . to . equal ( expectedPopupUrl ) ;
// Ask the page to access the popup.
2023-02-23 23:53:53 +00:00
const touchPopupResult = once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
w . webContents . send ( 'touch-the-popup' ) ;
const [ , popupAccessMessage ] = await touchPopupResult ;
// Ask the popup to access the opener.
2023-02-23 23:53:53 +00:00
const touchOpenerResult = once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
popupWindow . webContents . send ( 'touch-the-opener' ) ;
const [ , openerAccessMessage ] = await touchOpenerResult ;
// We don't need the popup anymore, and its parent page can't close it,
// so let's close it from here before we run any checks.
await closeWindow ( popupWindow , { assertNotWindows : false } ) ;
2023-09-18 20:44:09 +00:00
const errorPattern = /Failed to read a named property 'document' from 'Window': Blocked a frame with origin "(.*?)" from accessing a cross-origin frame./ ;
2019-07-16 04:13:32 +00:00
expect ( popupAccessMessage ) . to . be . a ( 'string' ,
2020-03-20 15:12:18 +00:00
'child\'s .document is accessible from its parent window' ) ;
2023-09-18 20:44:09 +00:00
expect ( popupAccessMessage ) . to . match ( errorPattern ) ;
2019-07-16 04:13:32 +00:00
expect ( openerAccessMessage ) . to . be . a ( 'string' ,
2020-03-20 15:12:18 +00:00
'opener .document is accessible from a popup window' ) ;
2023-09-18 20:44:09 +00:00
expect ( openerAccessMessage ) . to . match ( errorPattern ) ;
2019-07-16 04:13:32 +00:00
} ) ;
it ( 'should inherit the sandbox setting in opened windows' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true
}
} ) ;
2022-01-06 17:28:03 +00:00
const preloadPath = path . join ( mainFixtures , 'api' , 'new-window-preload.js' ) ;
2020-11-10 17:06:03 +00:00
w . webContents . setWindowOpenHandler ( ( ) = > ( { action : 'allow' , overrideBrowserWindowOptions : { webPreferences : { preload : preloadPath } } } ) ) ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'new-window.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , { argv } ] = await once ( ipcMain , 'answer' ) ;
2020-11-10 17:06:03 +00:00
expect ( argv ) . to . include ( '--enable-sandbox' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2022-08-09 21:57:05 +00:00
it ( 'should open windows with the options configured via setWindowOpenHandler handlers' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true
}
} ) ;
2022-01-06 17:28:03 +00:00
const preloadPath = path . join ( mainFixtures , 'api' , 'new-window-preload.js' ) ;
2021-07-26 16:04:09 +00:00
w . webContents . setWindowOpenHandler ( ( ) = > ( { action : 'allow' , overrideBrowserWindowOptions : { webPreferences : { preload : preloadPath , contextIsolation : false } } } ) ) ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'new-window.html' ) ) ;
2019-11-14 22:09:03 +00:00
const [ [ , childWebContents ] ] = await Promise . all ( [
2023-06-22 18:38:52 +00:00
once ( app , 'web-contents-created' ) as Promise < [ any , WebContents ] > ,
2023-02-23 23:53:53 +00:00
once ( ipcMain , 'answer' )
2019-11-14 22:09:03 +00:00
] ) ;
2020-06-25 17:19:08 +00:00
const webPreferences = childWebContents . getLastWebPreferences ( ) ;
2023-06-22 18:38:52 +00:00
expect ( webPreferences ! . contextIsolation ) . to . equal ( false ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'should set ipc event sender correctly' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true ,
2021-03-01 21:52:29 +00:00
preload ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
let childWc : WebContents | null = null ;
2021-04-21 17:55:17 +00:00
w . webContents . setWindowOpenHandler ( ( ) = > ( { action : 'allow' , overrideBrowserWindowOptions : { webPreferences : { preload , contextIsolation : false } } } ) ) ;
2020-11-10 17:06:03 +00:00
w . webContents . on ( 'did-create-window' , ( win ) = > {
childWc = win . webContents ;
2019-07-16 04:13:32 +00:00
expect ( w . webContents ) . to . not . equal ( childWc ) ;
} ) ;
2020-11-10 17:06:03 +00:00
2019-07-16 04:13:32 +00:00
ipcMain . once ( 'parent-ready' , function ( event ) {
expect ( event . sender ) . to . equal ( w . webContents , 'sender should be the parent' ) ;
event . sender . send ( 'verified' ) ;
} ) ;
ipcMain . once ( 'child-ready' , function ( event ) {
expect ( childWc ) . to . not . be . null ( 'child webcontents should be available' ) ;
expect ( event . sender ) . to . equal ( childWc , 'sender should be the child' ) ;
event . sender . send ( 'verified' ) ;
} ) ;
2020-07-01 19:14:38 +00:00
const done = Promise . all ( [
2019-07-16 04:13:32 +00:00
'parent-answer' ,
'child-answer'
2023-02-23 23:53:53 +00:00
] . map ( name = > once ( ipcMain , name ) ) ) ;
2019-11-14 22:09:03 +00:00
w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'sandbox.html' ) , { search : 'verify-ipc-sender' } ) ;
2020-07-01 19:14:38 +00:00
await done ;
2019-07-16 04:13:32 +00:00
} ) ;
describe ( 'event handling' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-07-16 04:13:32 +00:00
beforeEach ( ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false , webPreferences : { sandbox : true } } ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'works for window events' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const pageTitleUpdated = once ( w , 'page-title-updated' ) ;
2020-03-20 15:12:18 +00:00
w . loadURL ( 'data:text/html,<script>document.title = \'changed\'</script>' ) ;
2020-07-01 19:14:38 +00:00
await pageTitleUpdated ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'works for stop events' , async ( ) = > {
const done = Promise . all ( [
2019-07-16 04:13:32 +00:00
'did-navigate' ,
'did-fail-load' ,
'did-stop-loading'
2023-02-23 23:53:53 +00:00
] . map ( name = > once ( w . webContents , name ) ) ) ;
2020-03-20 15:12:18 +00:00
w . loadURL ( 'data:text/html,<script>stop()</script>' ) ;
2020-07-01 19:14:38 +00:00
await done ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'works for web contents events' , async ( ) = > {
const done = Promise . all ( [
2019-07-16 04:13:32 +00:00
'did-finish-load' ,
'did-frame-finish-load' ,
'did-navigate-in-page' ,
2020-02-21 19:08:26 +00:00
'will-navigate' ,
2019-07-16 04:13:32 +00:00
'did-start-loading' ,
'did-stop-loading' ,
'did-frame-finish-load' ,
'dom-ready'
2023-02-23 23:53:53 +00:00
] . map ( name = > once ( w . webContents , name ) ) ) ;
2019-11-14 22:09:03 +00:00
w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'sandbox.html' ) , { search : 'webcontents-events' } ) ;
2020-07-01 19:14:38 +00:00
await done ;
2019-07-16 04:13:32 +00:00
} ) ;
} ) ;
it ( 'validates process APIs access in sandboxed renderer' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true ,
2021-03-01 21:52:29 +00:00
preload ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
w . webContents . once ( 'preload-error' , ( event , preloadPath , error ) = > {
throw error ;
} ) ;
process . env . sandboxmain = 'foo' ;
w . loadFile ( path . join ( fixtures , 'api' , 'preload.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , test ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( test . hasCrash ) . to . be . true ( 'has crash' ) ;
expect ( test . hasHang ) . to . be . true ( 'has hang' ) ;
expect ( test . heapStatistics ) . to . be . an ( 'object' ) ;
expect ( test . blinkMemoryInfo ) . to . be . an ( 'object' ) ;
expect ( test . processMemoryInfo ) . to . be . an ( 'object' ) ;
expect ( test . systemVersion ) . to . be . a ( 'string' ) ;
expect ( test . cpuUsage ) . to . be . an ( 'object' ) ;
2020-11-30 07:49:18 +00:00
expect ( test . uptime ) . to . be . a ( 'number' ) ;
2019-07-16 04:13:32 +00:00
expect ( test . arch ) . to . equal ( process . arch ) ;
expect ( test . platform ) . to . equal ( process . platform ) ;
expect ( test . env ) . to . deep . equal ( process . env ) ;
expect ( test . execPath ) . to . equal ( process . helperExecPath ) ;
expect ( test . sandboxed ) . to . be . true ( 'sandboxed' ) ;
2021-03-18 21:00:19 +00:00
expect ( test . contextIsolated ) . to . be . false ( 'contextIsolated' ) ;
2019-07-16 04:13:32 +00:00
expect ( test . type ) . to . equal ( 'renderer' ) ;
expect ( test . version ) . to . equal ( process . version ) ;
expect ( test . versions ) . to . deep . equal ( process . versions ) ;
2021-03-17 18:23:03 +00:00
expect ( test . contextId ) . to . be . a ( 'string' ) ;
2023-06-10 18:36:16 +00:00
expect ( test . nodeEvents ) . to . equal ( true ) ;
expect ( test . nodeTimers ) . to . equal ( true ) ;
expect ( test . nodeUrl ) . to . equal ( true ) ;
2019-07-16 04:13:32 +00:00
if ( process . platform === 'linux' && test . osSandbox ) {
expect ( test . creationTime ) . to . be . null ( 'creation time' ) ;
expect ( test . systemMemoryInfo ) . to . be . null ( 'system memory info' ) ;
} else {
expect ( test . creationTime ) . to . be . a ( 'number' ) ;
expect ( test . systemMemoryInfo ) . to . be . an ( 'object' ) ;
}
} ) ;
it ( 'webview in sandbox renderer' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true ,
preload ,
2021-03-01 21:52:29 +00:00
webviewTag : true ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
2023-06-22 18:38:52 +00:00
const didAttachWebview = once ( w . webContents , 'did-attach-webview' ) as Promise < [ any , WebContents ] > ;
2023-02-23 23:53:53 +00:00
const webviewDomReady = once ( ipcMain , 'webview-dom-ready' ) ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'pages' , 'webview-did-attach-event.html' ) ) ;
const [ , webContents ] = await didAttachWebview ;
const [ , id ] = await webviewDomReady ;
expect ( webContents . id ) . to . equal ( id ) ;
} ) ;
} ) ;
2022-01-06 17:28:03 +00:00
describe ( 'child windows' , ( ) = > {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-07-16 04:13:32 +00:00
beforeEach ( ( ) = > {
w = new BrowserWindow ( {
show : false ,
webPreferences : {
nodeIntegration : true ,
// tests relies on preloads in opened windows
2021-03-01 21:52:29 +00:00
nodeIntegrationInSubFrames : true ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'opens window of about:blank with cross-scripting enabled' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const answer = once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'native-window-open-blank.html' ) ) ;
2020-06-30 22:10:36 +00:00
const [ , content ] = await answer ;
expect ( content ) . to . equal ( 'Hello' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'opens window of same domain with cross-scripting enabled' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const answer = once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'native-window-open-file.html' ) ) ;
2020-06-30 22:10:36 +00:00
const [ , content ] = await answer ;
expect ( content ) . to . equal ( 'Hello' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'blocks accessing cross-origin frames' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const answer = once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'native-window-open-cross-origin.html' ) ) ;
2020-06-30 22:10:36 +00:00
const [ , content ] = await answer ;
2023-09-18 20:44:09 +00:00
expect ( content ) . to . equal ( 'Failed to read a named property \'toString\' from \'Location\': Blocked a frame with origin "file://" from accessing a cross-origin frame.' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'opens window from <iframe> tags' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const answer = once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'native-window-open-iframe.html' ) ) ;
2020-06-30 22:10:36 +00:00
const [ , content ] = await answer ;
expect ( content ) . to . equal ( 'Hello' ) ;
2019-11-01 20:37:02 +00:00
} ) ;
2022-01-06 17:28:03 +00:00
it ( 'opens window with cross-scripting enabled from isolated context' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
preload : path.join ( fixtures , 'api' , 'native-window-open-isolated-preload.js' )
}
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'native-window-open-isolated.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , content ] = await once ( ipcMain , 'answer' ) ;
2022-01-06 17:28:03 +00:00
expect ( content ) . to . equal ( 'Hello' ) ;
} ) ;
2019-07-16 04:13:32 +00:00
ifit ( ! process . env . ELECTRON_SKIP_NATIVE_MODULE_TESTS ) ( 'loads native addons correctly after reload' , async ( ) = > {
2019-10-09 23:33:15 +00:00
w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'native-window-open-native-addon.html' ) ) ;
2019-07-16 04:13:32 +00:00
{
2023-02-23 23:53:53 +00:00
const [ , content ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( content ) . to . equal ( 'function' ) ;
}
w . reload ( ) ;
{
2023-02-23 23:53:53 +00:00
const [ , content ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( content ) . to . equal ( 'function' ) ;
}
} ) ;
2020-06-30 22:10:36 +00:00
it ( '<webview> works in a scriptable popup' , async ( ) = > {
2019-07-16 22:45:35 +00:00
const preload = path . join ( fixtures , 'api' , 'new-window-webview-preload.js' ) ;
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
nodeIntegrationInSubFrames : true ,
webviewTag : true ,
2021-03-01 21:52:29 +00:00
contextIsolation : false ,
2019-07-16 22:45:35 +00:00
preload
}
} ) ;
2021-04-21 17:55:17 +00:00
w . webContents . setWindowOpenHandler ( ( ) = > ( {
action : 'allow' ,
2022-06-15 20:22:28 +00:00
overrideBrowserWindowOptions : {
show : false ,
webPreferences : {
contextIsolation : false ,
webviewTag : true ,
nodeIntegrationInSubFrames : true ,
preload
}
}
2021-04-21 17:55:17 +00:00
} ) ) ;
2019-07-16 22:45:35 +00:00
2023-02-23 23:53:53 +00:00
const webviewLoaded = once ( ipcMain , 'webview-loaded' ) ;
2019-07-16 22:45:35 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'new-window-webview.html' ) ) ;
2020-06-30 22:10:36 +00:00
await webviewLoaded ;
2019-07-16 22:45:35 +00:00
} ) ;
2022-08-09 21:57:05 +00:00
it ( 'should open windows with the options configured via setWindowOpenHandler handlers' , async ( ) = > {
2022-01-06 17:28:03 +00:00
const preloadPath = path . join ( mainFixtures , 'api' , 'new-window-preload.js' ) ;
2020-11-10 17:06:03 +00:00
w . webContents . setWindowOpenHandler ( ( ) = > ( {
action : 'allow' ,
overrideBrowserWindowOptions : {
webPreferences : {
preload : preloadPath ,
2021-07-26 16:04:09 +00:00
contextIsolation : false
2020-11-10 17:06:03 +00:00
}
}
} ) ) ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'new-window.html' ) ) ;
2019-11-14 22:09:03 +00:00
const [ [ , childWebContents ] ] = await Promise . all ( [
2023-06-22 18:38:52 +00:00
once ( app , 'web-contents-created' ) as Promise < [ any , WebContents ] > ,
2023-02-23 23:53:53 +00:00
once ( ipcMain , 'answer' )
2019-11-14 22:09:03 +00:00
] ) ;
2020-06-25 17:19:08 +00:00
const webPreferences = childWebContents . getLastWebPreferences ( ) ;
2023-06-22 18:38:52 +00:00
expect ( webPreferences ! . contextIsolation ) . to . equal ( false ) ;
2019-07-16 04:13:32 +00:00
} ) ;
describe ( 'window.location' , ( ) = > {
const protocols = [
[ 'foo' , path . join ( fixtures , 'api' , 'window-open-location-change.html' ) ] ,
[ 'bar' , path . join ( fixtures , 'api' , 'window-open-location-final.html' ) ]
] ;
2020-06-02 16:46:18 +00:00
beforeEach ( ( ) = > {
for ( const [ scheme , path ] of protocols ) {
2019-07-16 04:13:32 +00:00
protocol . registerBufferProtocol ( scheme , ( request , callback ) = > {
callback ( {
mimeType : 'text/html' ,
data : fs.readFileSync ( path )
} ) ;
} ) ;
2020-06-02 16:46:18 +00:00
}
2019-07-16 04:13:32 +00:00
} ) ;
2020-06-02 16:46:18 +00:00
afterEach ( ( ) = > {
for ( const [ scheme ] of protocols ) {
protocol . unregisterProtocol ( scheme ) ;
}
2019-07-16 04:13:32 +00:00
} ) ;
it ( 'retains the original web preferences when window.location is changed to a new origin' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
// test relies on preloads in opened window
2021-03-01 21:52:29 +00:00
nodeIntegrationInSubFrames : true ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
2020-11-10 17:06:03 +00:00
w . webContents . setWindowOpenHandler ( ( ) = > ( {
action : 'allow' ,
overrideBrowserWindowOptions : {
webPreferences : {
2022-01-06 17:28:03 +00:00
preload : path.join ( mainFixtures , 'api' , 'window-open-preload.js' ) ,
2021-04-21 17:55:17 +00:00
contextIsolation : false ,
nodeIntegrationInSubFrames : true
2020-11-10 17:06:03 +00:00
}
}
} ) ) ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'window-open-location-open.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , { nodeIntegration , typeofProcess } ] = await once ( ipcMain , 'answer' ) ;
2020-11-10 17:06:03 +00:00
expect ( nodeIntegration ) . to . be . false ( ) ;
2019-07-16 04:13:32 +00:00
expect ( typeofProcess ) . to . eql ( 'undefined' ) ;
} ) ;
it ( 'window.opener is not null when window.location is changed to a new origin' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
// test relies on preloads in opened window
nodeIntegrationInSubFrames : true
}
} ) ;
2020-11-10 17:06:03 +00:00
w . webContents . setWindowOpenHandler ( ( ) = > ( {
action : 'allow' ,
overrideBrowserWindowOptions : {
webPreferences : {
2022-01-06 17:28:03 +00:00
preload : path.join ( mainFixtures , 'api' , 'window-open-preload.js' )
2020-11-10 17:06:03 +00:00
}
}
} ) ) ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'window-open-location-open.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , { windowOpenerIsNull } ] = await once ( ipcMain , 'answer' ) ;
2019-07-16 04:13:32 +00:00
expect ( windowOpenerIsNull ) . to . be . false ( 'window.opener is null' ) ;
} ) ;
} ) ;
} ) ;
describe ( '"disableHtmlFullscreenWindowResize" option' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'prevents window from resizing when set' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
disableHtmlFullscreenWindowResize : true
}
} ) ;
2020-06-30 22:10:36 +00:00
await w . loadURL ( 'about:blank' ) ;
const size = w . getSize ( ) ;
2023-02-23 23:53:53 +00:00
const enterHtmlFullScreen = once ( w . webContents , 'enter-html-full-screen' ) ;
2020-06-30 22:10:36 +00:00
w . webContents . executeJavaScript ( 'document.body.webkitRequestFullscreen()' , true ) ;
await enterHtmlFullScreen ;
expect ( w . getSize ( ) ) . to . deep . equal ( size ) ;
2019-07-16 04:13:32 +00:00
} ) ;
} ) ;
2023-04-13 09:30:25 +00:00
describe ( '"defaultFontFamily" option' , ( ) = > {
it ( 'can change the standard font family' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
defaultFontFamily : {
standard : 'Impact'
}
}
} ) ;
await w . loadFile ( path . join ( fixtures , 'pages' , 'content.html' ) ) ;
const fontFamily = await w . webContents . executeJavaScript ( "window.getComputedStyle(document.getElementsByTagName('p')[0])['font-family']" , true ) ;
expect ( fontFamily ) . to . equal ( 'Impact' ) ;
} ) ;
} ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2019-11-27 17:42:54 +00:00
describe ( 'beforeunload handler' , function ( ) {
2023-02-19 09:24:24 +00:00
let w : BrowserWindow ;
2019-07-16 04:13:32 +00:00
beforeEach ( ( ) = > {
2019-11-01 20:37:02 +00:00
w = new BrowserWindow ( { show : false , webPreferences : { nodeIntegration : true } } ) ;
2019-07-16 04:13:32 +00:00
} ) ;
afterEach ( closeAllWindows ) ;
2020-05-26 13:21:38 +00:00
it ( 'returning undefined would not prevent close' , async ( ) = > {
2020-06-02 02:32:39 +00:00
await w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'beforeunload-undefined.html' ) ) ;
2023-02-23 23:53:53 +00:00
const wait = once ( w , 'closed' ) ;
2020-05-26 13:21:38 +00:00
w . close ( ) ;
await wait ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-05-26 13:21:38 +00:00
2019-11-14 22:09:03 +00:00
it ( 'returning false would prevent close' , async ( ) = > {
2020-06-02 02:32:39 +00:00
await w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'beforeunload-false.html' ) ) ;
2020-05-26 13:21:38 +00:00
w . close ( ) ;
2023-12-13 21:01:03 +00:00
const [ , proceed ] = await once ( w . webContents , '-before-unload-fired' ) ;
2020-05-26 13:21:38 +00:00
expect ( proceed ) . to . equal ( false ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-05-26 13:21:38 +00:00
it ( 'returning empty string would prevent close' , async ( ) = > {
2020-06-02 02:32:39 +00:00
await w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'beforeunload-empty-string.html' ) ) ;
2020-05-26 13:21:38 +00:00
w . close ( ) ;
2023-12-13 21:01:03 +00:00
const [ , proceed ] = await once ( w . webContents , '-before-unload-fired' ) ;
2020-05-26 13:21:38 +00:00
expect ( proceed ) . to . equal ( false ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-04-16 22:22:39 +00:00
it ( 'emits for each close attempt' , async ( ) = > {
await w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'beforeunload-false-prevent3.html' ) ) ;
const destroyListener = ( ) = > { expect . fail ( 'Close was not prevented' ) ; } ;
w . webContents . once ( 'destroyed' , destroyListener ) ;
2020-06-02 02:32:39 +00:00
w . webContents . executeJavaScript ( 'installBeforeUnload(2)' , true ) ;
// The renderer needs to report the status of beforeunload handler
// back to main process, so wait for next console message, which means
// the SuddenTerminationStatus message have been flushed.
2023-02-23 23:53:53 +00:00
await once ( w . webContents , 'console-message' ) ;
2020-05-26 13:21:38 +00:00
w . close ( ) ;
2023-12-13 21:01:03 +00:00
await once ( w . webContents , '-before-unload-fired' ) ;
2020-05-26 13:21:38 +00:00
w . close ( ) ;
2023-12-13 21:01:03 +00:00
await once ( w . webContents , '-before-unload-fired' ) ;
2020-04-16 22:22:39 +00:00
w . webContents . removeListener ( 'destroyed' , destroyListener ) ;
2023-02-23 23:53:53 +00:00
const wait = once ( w , 'closed' ) ;
2020-04-16 22:22:39 +00:00
w . close ( ) ;
2020-05-26 13:21:38 +00:00
await wait ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-04-16 22:22:39 +00:00
it ( 'emits for each reload attempt' , async ( ) = > {
await w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'beforeunload-false-prevent3.html' ) ) ;
const navigationListener = ( ) = > { expect . fail ( 'Reload was not prevented' ) ; } ;
w . webContents . once ( 'did-start-navigation' , navigationListener ) ;
2020-06-02 02:32:39 +00:00
w . webContents . executeJavaScript ( 'installBeforeUnload(2)' , true ) ;
// The renderer needs to report the status of beforeunload handler
// back to main process, so wait for next console message, which means
// the SuddenTerminationStatus message have been flushed.
2023-02-23 23:53:53 +00:00
await once ( w . webContents , 'console-message' ) ;
2020-04-16 22:22:39 +00:00
w . reload ( ) ;
2023-12-13 21:01:03 +00:00
// Chromium does not emit '-before-unload-fired' on WebContents for
2020-05-26 13:21:38 +00:00
// navigations, so we have to use other ways to know if beforeunload
// is fired.
await emittedUntil ( w . webContents , 'console-message' , isBeforeUnload ) ;
2020-04-16 22:22:39 +00:00
w . reload ( ) ;
2020-05-26 13:21:38 +00:00
await emittedUntil ( w . webContents , 'console-message' , isBeforeUnload ) ;
2020-04-16 22:22:39 +00:00
w . webContents . removeListener ( 'did-start-navigation' , navigationListener ) ;
w . reload ( ) ;
2023-02-23 23:53:53 +00:00
await once ( w . webContents , 'did-finish-load' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-04-16 22:22:39 +00:00
it ( 'emits for each navigation attempt' , async ( ) = > {
await w . loadFile ( path . join ( __dirname , 'fixtures' , 'api' , 'beforeunload-false-prevent3.html' ) ) ;
const navigationListener = ( ) = > { expect . fail ( 'Reload was not prevented' ) ; } ;
w . webContents . once ( 'did-start-navigation' , navigationListener ) ;
2020-06-02 02:32:39 +00:00
w . webContents . executeJavaScript ( 'installBeforeUnload(2)' , true ) ;
// The renderer needs to report the status of beforeunload handler
// back to main process, so wait for next console message, which means
// the SuddenTerminationStatus message have been flushed.
2023-02-23 23:53:53 +00:00
await once ( w . webContents , 'console-message' ) ;
2020-04-16 22:22:39 +00:00
w . loadURL ( 'about:blank' ) ;
2023-12-13 21:01:03 +00:00
// Chromium does not emit '-before-unload-fired' on WebContents for
2020-05-26 13:21:38 +00:00
// navigations, so we have to use other ways to know if beforeunload
// is fired.
await emittedUntil ( w . webContents , 'console-message' , isBeforeUnload ) ;
2020-04-16 22:22:39 +00:00
w . loadURL ( 'about:blank' ) ;
2020-05-26 13:21:38 +00:00
await emittedUntil ( w . webContents , 'console-message' , isBeforeUnload ) ;
2020-04-16 22:22:39 +00:00
w . webContents . removeListener ( 'did-start-navigation' , navigationListener ) ;
2020-06-30 22:10:36 +00:00
await w . loadURL ( 'about:blank' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
} ) ;
2023-07-28 08:48:25 +00:00
// TODO(codebytere): figure out how to make these pass in CI on Windows.
ifdescribe ( process . platform !== 'win32' ) ( 'document.visibilityState/hidden' , ( ) = > {
2019-07-16 04:13:32 +00:00
afterEach ( closeAllWindows ) ;
it ( 'visibilityState is initially visible despite window being hidden' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
width : 100 ,
height : 100 ,
webPreferences : {
2021-03-01 21:52:29 +00:00
nodeIntegration : true ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
let readyToShow = false ;
w . once ( 'ready-to-show' , ( ) = > {
readyToShow = true ;
} ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'visibilitychange.html' ) ) ;
2023-02-23 23:53:53 +00:00
const [ , visibilityState , hidden ] = await once ( ipcMain , 'pong' ) ;
2019-07-16 04:13:32 +00:00
expect ( readyToShow ) . to . be . false ( 'ready to show' ) ;
expect ( visibilityState ) . to . equal ( 'visible' ) ;
expect ( hidden ) . to . be . false ( 'hidden' ) ;
} ) ;
2023-07-28 08:48:25 +00:00
it ( 'visibilityState changes when window is hidden' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( {
width : 100 ,
height : 100 ,
webPreferences : {
2021-03-01 21:52:29 +00:00
nodeIntegration : true ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'visibilitychange.html' ) ) ;
{
2023-02-23 23:53:53 +00:00
const [ , visibilityState , hidden ] = await once ( ipcMain , 'pong' ) ;
2019-07-16 04:13:32 +00:00
expect ( visibilityState ) . to . equal ( 'visible' ) ;
expect ( hidden ) . to . be . false ( 'hidden' ) ;
}
w . hide ( ) ;
{
2023-02-23 23:53:53 +00:00
const [ , visibilityState , hidden ] = await once ( ipcMain , 'pong' ) ;
2019-07-16 04:13:32 +00:00
expect ( visibilityState ) . to . equal ( 'hidden' ) ;
expect ( hidden ) . to . be . true ( 'hidden' ) ;
}
} ) ;
2023-07-28 08:48:25 +00:00
it ( 'visibilityState changes when window is shown' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( {
width : 100 ,
height : 100 ,
webPreferences : {
2021-03-01 21:52:29 +00:00
nodeIntegration : true ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'visibilitychange.html' ) ) ;
if ( process . platform === 'darwin' ) {
// See https://github.com/electron/electron/issues/8664
2023-02-23 23:53:53 +00:00
await once ( w , 'show' ) ;
2019-07-16 04:13:32 +00:00
}
w . hide ( ) ;
w . show ( ) ;
2023-02-23 23:53:53 +00:00
const [ , visibilityState ] = await once ( ipcMain , 'pong' ) ;
2019-07-16 04:13:32 +00:00
expect ( visibilityState ) . to . equal ( 'visible' ) ;
} ) ;
2023-07-28 08:48:25 +00:00
it ( 'visibilityState changes when window is shown inactive' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( {
width : 100 ,
height : 100 ,
webPreferences : {
2021-03-01 21:52:29 +00:00
nodeIntegration : true ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'visibilitychange.html' ) ) ;
if ( process . platform === 'darwin' ) {
// See https://github.com/electron/electron/issues/8664
2023-02-23 23:53:53 +00:00
await once ( w , 'show' ) ;
2019-07-16 04:13:32 +00:00
}
w . hide ( ) ;
w . showInactive ( ) ;
2023-02-23 23:53:53 +00:00
const [ , visibilityState ] = await once ( ipcMain , 'pong' ) ;
2019-07-16 04:13:32 +00:00
expect ( visibilityState ) . to . equal ( 'visible' ) ;
} ) ;
2019-10-18 19:57:34 +00:00
ifit ( process . platform === 'darwin' ) ( 'visibilityState changes when window is minimized' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( {
width : 100 ,
height : 100 ,
webPreferences : {
2021-03-01 21:52:29 +00:00
nodeIntegration : true ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'visibilitychange.html' ) ) ;
{
2023-02-23 23:53:53 +00:00
const [ , visibilityState , hidden ] = await once ( ipcMain , 'pong' ) ;
2019-07-16 04:13:32 +00:00
expect ( visibilityState ) . to . equal ( 'visible' ) ;
expect ( hidden ) . to . be . false ( 'hidden' ) ;
}
w . minimize ( ) ;
{
2023-02-23 23:53:53 +00:00
const [ , visibilityState , hidden ] = await once ( ipcMain , 'pong' ) ;
2019-07-16 04:13:32 +00:00
expect ( visibilityState ) . to . equal ( 'hidden' ) ;
expect ( hidden ) . to . be . true ( 'hidden' ) ;
}
} ) ;
2023-04-04 13:48:51 +00:00
it ( 'visibilityState remains visible if backgroundThrottling is disabled' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( {
show : false ,
width : 100 ,
height : 100 ,
webPreferences : {
backgroundThrottling : false ,
2023-07-28 08:48:25 +00:00
nodeIntegration : true ,
contextIsolation : false
2019-07-16 04:13:32 +00:00
}
} ) ;
2023-07-28 08:48:25 +00:00
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'pages' , 'visibilitychange.html' ) ) ;
2023-07-28 08:48:25 +00:00
2019-07-16 04:13:32 +00:00
{
2023-02-23 23:53:53 +00:00
const [ , visibilityState , hidden ] = await once ( ipcMain , 'pong' ) ;
2019-07-16 04:13:32 +00:00
expect ( visibilityState ) . to . equal ( 'visible' ) ;
expect ( hidden ) . to . be . false ( 'hidden' ) ;
}
ipcMain . once ( 'pong' , ( event , visibilityState , hidden ) = > {
throw new Error ( ` Unexpected visibility change event. visibilityState: ${ visibilityState } hidden: ${ hidden } ` ) ;
} ) ;
try {
2023-02-23 23:53:53 +00:00
const shown1 = once ( w , 'show' ) ;
2019-07-16 04:13:32 +00:00
w . show ( ) ;
await shown1 ;
2023-02-23 23:53:53 +00:00
const hidden = once ( w , 'hide' ) ;
2019-07-16 04:13:32 +00:00
w . hide ( ) ;
await hidden ;
2023-02-23 23:53:53 +00:00
const shown2 = once ( w , 'show' ) ;
2019-07-16 04:13:32 +00:00
w . show ( ) ;
await shown2 ;
} finally {
ipcMain . removeAllListeners ( 'pong' ) ;
}
} ) ;
} ) ;
ifdescribe ( process . platform !== 'linux' ) ( 'max/minimize events' , ( ) = > {
afterEach ( closeAllWindows ) ;
2020-07-01 19:14:38 +00:00
it ( 'emits an event when window is maximized' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
2019-07-16 04:13:32 +00:00
w . show ( ) ;
w . maximize ( ) ;
2020-07-01 19:14:38 +00:00
await maximize ;
2019-07-16 04:13:32 +00:00
} ) ;
2022-01-31 21:10:57 +00:00
it ( 'emits an event when a transparent window is maximized' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
frame : false ,
transparent : true
} ) ;
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
2022-01-31 21:10:57 +00:00
w . show ( ) ;
w . maximize ( ) ;
await maximize ;
} ) ;
2020-08-24 20:32:08 +00:00
it ( 'emits only one event when frameless window is maximized' , ( ) = > {
const w = new BrowserWindow ( { show : false , frame : false } ) ;
let emitted = 0 ;
w . on ( 'maximize' , ( ) = > emitted ++ ) ;
w . show ( ) ;
w . maximize ( ) ;
expect ( emitted ) . to . equal ( 1 ) ;
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'emits an event when window is unmaximized' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2023-02-23 23:53:53 +00:00
const unmaximize = once ( w , 'unmaximize' ) ;
2019-07-16 04:13:32 +00:00
w . show ( ) ;
w . maximize ( ) ;
w . unmaximize ( ) ;
2020-07-01 19:14:38 +00:00
await unmaximize ;
2019-07-16 04:13:32 +00:00
} ) ;
2022-01-31 21:10:57 +00:00
it ( 'emits an event when a transparent window is unmaximized' , async ( ) = > {
const w = new BrowserWindow ( {
show : false ,
frame : false ,
transparent : true
} ) ;
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
const unmaximize = once ( w , 'unmaximize' ) ;
2022-01-31 21:10:57 +00:00
w . show ( ) ;
w . maximize ( ) ;
await maximize ;
w . unmaximize ( ) ;
await unmaximize ;
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'emits an event when window is minimized' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2023-02-23 23:53:53 +00:00
const minimize = once ( w , 'minimize' ) ;
2019-07-16 04:13:32 +00:00
w . show ( ) ;
w . minimize ( ) ;
2020-07-01 19:14:38 +00:00
await minimize ;
2019-07-16 04:13:32 +00:00
} ) ;
} ) ;
describe ( 'beginFrameSubscription method' , ( ) = > {
it ( 'does not crash when callback returns nothing' , ( done ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2022-05-11 17:23:24 +00:00
let called = false ;
2019-07-16 04:13:32 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'frame-subscriber.html' ) ) ;
w . webContents . on ( 'dom-ready' , ( ) = > {
2019-11-01 20:37:02 +00:00
w . webContents . beginFrameSubscription ( function ( ) {
2022-05-11 17:23:24 +00:00
// This callback might be called twice.
if ( called ) return ;
called = true ;
2019-07-16 04:13:32 +00:00
// Pending endFrameSubscription to next tick can reliably reproduce
// a crash which happens when nothing is returned in the callback.
2023-02-23 23:53:53 +00:00
setTimeout ( ) . then ( ( ) = > {
2019-07-16 04:13:32 +00:00
w . webContents . endFrameSubscription ( ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
} ) ;
it ( 'subscribes to frame updates' , ( done ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
let called = false ;
w . loadFile ( path . join ( fixtures , 'api' , 'frame-subscriber.html' ) ) ;
w . webContents . on ( 'dom-ready' , ( ) = > {
w . webContents . beginFrameSubscription ( function ( data ) {
// This callback might be called twice.
if ( called ) return ;
called = true ;
2020-06-30 22:10:36 +00:00
try {
expect ( data . constructor . name ) . to . equal ( 'NativeImage' ) ;
expect ( data . isEmpty ( ) ) . to . be . false ( 'data is empty' ) ;
done ( ) ;
} catch ( e ) {
done ( e ) ;
} finally {
w . webContents . endFrameSubscription ( ) ;
}
2019-07-16 04:13:32 +00:00
} ) ;
} ) ;
} ) ;
it ( 'subscribes to frame updates (only dirty rectangle)' , ( done ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
let called = false ;
let gotInitialFullSizeFrame = false ;
const [ contentWidth , contentHeight ] = w . getContentSize ( ) ;
w . webContents . on ( 'did-finish-load' , ( ) = > {
w . webContents . beginFrameSubscription ( true , ( image , rect ) = > {
if ( image . isEmpty ( ) ) {
// Chromium sometimes sends a 0x0 frame at the beginning of the
// page load.
return ;
}
if ( rect . height === contentHeight && rect . width === contentWidth &&
2020-03-05 22:22:12 +00:00
! gotInitialFullSizeFrame ) {
2019-07-16 04:13:32 +00:00
// The initial frame is full-size, but we're looking for a call
// with just the dirty-rect. The next frame should be a smaller
// rect.
gotInitialFullSizeFrame = true ;
return ;
}
// This callback might be called twice.
if ( called ) return ;
// We asked for just the dirty rectangle, so we expect to receive a
// rect smaller than the full size.
// TODO(jeremy): this is failing on windows currently; investigate.
// assert(rect.width < contentWidth || rect.height < contentHeight)
called = true ;
2020-06-30 22:10:36 +00:00
try {
const expectedSize = rect . width * rect . height * 4 ;
expect ( image . getBitmap ( ) ) . to . be . an . instanceOf ( Buffer ) . with . lengthOf ( expectedSize ) ;
done ( ) ;
} catch ( e ) {
done ( e ) ;
} finally {
w . webContents . endFrameSubscription ( ) ;
}
2019-07-16 04:13:32 +00:00
} ) ;
} ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'frame-subscriber.html' ) ) ;
} ) ;
it ( 'throws error when subscriber is not well defined' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
expect ( ( ) = > {
w . webContents . beginFrameSubscription ( true , true as any ) ;
2019-10-21 07:05:40 +00:00
// TODO(zcbenz): gin is weak at guessing parameter types, we should
// upstream native_mate's implementation to gin.
} ) . to . throw ( 'Error processing argument at index 1, conversion failure from ' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
} ) ;
describe ( 'savePage method' , ( ) = > {
const savePageDir = path . join ( fixtures , 'save_page' ) ;
const savePageHtmlPath = path . join ( savePageDir , 'save_page.html' ) ;
const savePageJsPath = path . join ( savePageDir , 'save_page_files' , 'test.js' ) ;
const savePageCssPath = path . join ( savePageDir , 'save_page_files' , 'test.css' ) ;
2022-02-03 21:56:50 +00:00
afterEach ( ( ) = > {
closeAllWindows ( ) ;
2019-07-16 04:13:32 +00:00
try {
fs . unlinkSync ( savePageCssPath ) ;
fs . unlinkSync ( savePageJsPath ) ;
fs . unlinkSync ( savePageHtmlPath ) ;
fs . rmdirSync ( path . join ( savePageDir , 'save_page_files' ) ) ;
fs . rmdirSync ( savePageDir ) ;
2022-02-03 21:56:50 +00:00
} catch { }
} ) ;
2022-02-07 08:51:59 +00:00
it ( 'should throw when passing relative paths' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
await w . loadFile ( path . join ( fixtures , 'pages' , 'save_page' , 'index.html' ) ) ;
await expect (
w . webContents . savePage ( 'save_page.html' , 'HTMLComplete' )
) . to . eventually . be . rejectedWith ( 'Path must be absolute' ) ;
await expect (
w . webContents . savePage ( 'save_page.html' , 'HTMLOnly' )
) . to . eventually . be . rejectedWith ( 'Path must be absolute' ) ;
await expect (
w . webContents . savePage ( 'save_page.html' , 'MHTML' )
) . to . eventually . be . rejectedWith ( 'Path must be absolute' ) ;
} ) ;
2022-02-03 21:56:50 +00:00
it ( 'should save page to disk with HTMLOnly' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
await w . loadFile ( path . join ( fixtures , 'pages' , 'save_page' , 'index.html' ) ) ;
await w . webContents . savePage ( savePageHtmlPath , 'HTMLOnly' ) ;
expect ( fs . existsSync ( savePageHtmlPath ) ) . to . be . true ( 'html path' ) ;
expect ( fs . existsSync ( savePageJsPath ) ) . to . be . false ( 'js path' ) ;
expect ( fs . existsSync ( savePageCssPath ) ) . to . be . false ( 'css path' ) ;
} ) ;
it ( 'should save page to disk with MHTML' , async ( ) = > {
2023-02-03 11:43:42 +00:00
/ * U s e t e m p d i r e c t o r y f o r s a v i n g M H T M L f i l e s i n c e t h e w r i t e h a n d l e
* gets passed to untrusted process and chromium will deny exec access to
* the path . To perform this task , chromium requires that the path is one
* of the browser controlled paths , refs https : //chromium-review.googlesource.com/c/chromium/src/+/3774416
* /
const tmpDir = await fs . promises . mkdtemp ( path . resolve ( os . tmpdir ( ) , 'electron-mhtml-save-' ) ) ;
const savePageMHTMLPath = path . join ( tmpDir , 'save_page.html' ) ;
2022-02-03 21:56:50 +00:00
const w = new BrowserWindow ( { show : false } ) ;
await w . loadFile ( path . join ( fixtures , 'pages' , 'save_page' , 'index.html' ) ) ;
2023-02-03 11:43:42 +00:00
await w . webContents . savePage ( savePageMHTMLPath , 'MHTML' ) ;
2022-02-03 21:56:50 +00:00
2023-02-03 11:43:42 +00:00
expect ( fs . existsSync ( savePageMHTMLPath ) ) . to . be . true ( 'html path' ) ;
2022-02-03 21:56:50 +00:00
expect ( fs . existsSync ( savePageJsPath ) ) . to . be . false ( 'js path' ) ;
expect ( fs . existsSync ( savePageCssPath ) ) . to . be . false ( 'css path' ) ;
2023-02-03 11:43:42 +00:00
try {
await fs . promises . unlink ( savePageMHTMLPath ) ;
await fs . promises . rmdir ( tmpDir ) ;
} catch { }
2019-07-16 04:13:32 +00:00
} ) ;
2022-02-03 21:56:50 +00:00
it ( 'should save page to disk with HTMLComplete' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
await w . loadFile ( path . join ( fixtures , 'pages' , 'save_page' , 'index.html' ) ) ;
await w . webContents . savePage ( savePageHtmlPath , 'HTMLComplete' ) ;
expect ( fs . existsSync ( savePageHtmlPath ) ) . to . be . true ( 'html path' ) ;
expect ( fs . existsSync ( savePageJsPath ) ) . to . be . true ( 'js path' ) ;
expect ( fs . existsSync ( savePageCssPath ) ) . to . be . true ( 'css path' ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow options argument is optional' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'should create a window with default size (800x600)' , ( ) = > {
const w = new BrowserWindow ( ) ;
expect ( w . getSize ( ) ) . to . deep . equal ( [ 800 , 600 ] ) ;
} ) ;
} ) ;
describe ( 'BrowserWindow.restore()' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'should restore the previous window size' , ( ) = > {
const w = new BrowserWindow ( {
minWidth : 800 ,
width : 800
} ) ;
const initialSize = w . getSize ( ) ;
w . minimize ( ) ;
w . restore ( ) ;
expectBoundsEqual ( w . getSize ( ) , initialSize ) ;
} ) ;
2020-01-17 19:29:02 +00:00
it ( 'does not crash when restoring hidden minimized window' , ( ) = > {
const w = new BrowserWindow ( { } ) ;
w . minimize ( ) ;
w . hide ( ) ;
w . show ( ) ;
} ) ;
2023-02-21 08:49:02 +00:00
// TODO(zcbenz):
// This test does not run on Linux CI. See:
// https://github.com/electron/electron/issues/28699
ifit ( process . platform === 'linux' && ! process . env . CI ) ( 'should bring a minimized maximized window back to maximized state' , async ( ) = > {
const w = new BrowserWindow ( { } ) ;
2023-02-23 23:53:53 +00:00
const maximize = once ( w , 'maximize' ) ;
2023-02-21 08:49:02 +00:00
w . maximize ( ) ;
await maximize ;
2023-02-23 23:53:53 +00:00
const minimize = once ( w , 'minimize' ) ;
2023-02-21 08:49:02 +00:00
w . minimize ( ) ;
await minimize ;
expect ( w . isMaximized ( ) ) . to . equal ( false ) ;
2023-02-23 23:53:53 +00:00
const restore = once ( w , 'restore' ) ;
2023-02-21 08:49:02 +00:00
w . restore ( ) ;
await restore ;
expect ( w . isMaximized ( ) ) . to . equal ( true ) ;
} ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2022-03-09 22:30:42 +00:00
// TODO(dsanders11): Enable once maximize event works on Linux again on CI
ifdescribe ( process . platform !== 'linux' ) ( 'BrowserWindow.maximize()' , ( ) = > {
afterEach ( closeAllWindows ) ;
2022-03-29 23:08:34 +00:00
it ( 'should show the window if it is not currently shown' , async ( ) = > {
2022-03-09 22:30:42 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2023-02-23 23:53:53 +00:00
const hidden = once ( w , 'hide' ) ;
let shown = once ( w , 'show' ) ;
const maximize = once ( w , 'maximize' ) ;
2022-03-09 22:30:42 +00:00
expect ( w . isVisible ( ) ) . to . be . false ( 'visible' ) ;
w . maximize ( ) ;
await maximize ;
2022-03-29 23:08:34 +00:00
await shown ;
expect ( w . isMaximized ( ) ) . to . be . true ( 'maximized' ) ;
2022-03-09 22:30:42 +00:00
expect ( w . isVisible ( ) ) . to . be . true ( 'visible' ) ;
// Even if the window is already maximized
w . hide ( ) ;
await hidden ;
expect ( w . isVisible ( ) ) . to . be . false ( 'visible' ) ;
2023-02-23 23:53:53 +00:00
shown = once ( w , 'show' ) ;
2022-03-09 22:30:42 +00:00
w . maximize ( ) ;
2022-03-29 23:08:34 +00:00
await shown ;
2022-03-09 22:30:42 +00:00
expect ( w . isVisible ( ) ) . to . be . true ( 'visible' ) ;
} ) ;
} ) ;
2019-07-16 04:13:32 +00:00
describe ( 'BrowserWindow.unmaximize()' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'should restore the previous window position' , ( ) = > {
const w = new BrowserWindow ( ) ;
const initialPosition = w . getPosition ( ) ;
w . maximize ( ) ;
w . unmaximize ( ) ;
expectBoundsEqual ( w . getPosition ( ) , initialPosition ) ;
} ) ;
2022-01-17 07:47:14 +00:00
// TODO(dsanders11): Enable once minimize event works on Linux again.
// See https://github.com/electron/electron/issues/28699
ifit ( process . platform !== 'linux' ) ( 'should not restore a minimized window' , async ( ) = > {
const w = new BrowserWindow ( ) ;
2023-02-23 23:53:53 +00:00
const minimize = once ( w , 'minimize' ) ;
2022-01-17 07:47:14 +00:00
w . minimize ( ) ;
await minimize ;
w . unmaximize ( ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( 1000 ) ;
2022-01-17 07:47:14 +00:00
expect ( w . isMinimized ( ) ) . to . be . true ( ) ;
} ) ;
it ( 'should not change the size or position of a normal window' , async ( ) = > {
const w = new BrowserWindow ( ) ;
const initialSize = w . getSize ( ) ;
const initialPosition = w . getPosition ( ) ;
w . unmaximize ( ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( 1000 ) ;
2022-01-17 07:47:14 +00:00
expectBoundsEqual ( w . getSize ( ) , initialSize ) ;
expectBoundsEqual ( w . getPosition ( ) , initialPosition ) ;
} ) ;
2022-03-30 22:29:02 +00:00
ifit ( process . platform === 'darwin' ) ( 'should not change size or position of a window which is functionally maximized' , async ( ) = > {
const { workArea } = screen . getPrimaryDisplay ( ) ;
const bounds = {
x : workArea.x ,
y : workArea.y ,
width : workArea.width ,
height : workArea.height
} ;
const w = new BrowserWindow ( bounds ) ;
w . unmaximize ( ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( 1000 ) ;
2022-03-30 22:29:02 +00:00
expectBoundsEqual ( w . getBounds ( ) , bounds ) ;
} ) ;
2019-07-16 04:13:32 +00:00
} ) ;
describe ( 'setFullScreen(false)' , ( ) = > {
afterEach ( closeAllWindows ) ;
// only applicable to windows: https://github.com/electron/electron/issues/6036
ifdescribe ( process . platform === 'win32' ) ( 'on windows' , ( ) = > {
it ( 'should restore a normal visible window from a fullscreen startup state' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
await w . loadURL ( 'about:blank' ) ;
2023-02-23 23:53:53 +00:00
const shown = once ( w , 'show' ) ;
2019-07-16 04:13:32 +00:00
// start fullscreen and hidden
w . setFullScreen ( true ) ;
w . show ( ) ;
await shown ;
2023-02-23 23:53:53 +00:00
const leftFullScreen = once ( w , 'leave-full-screen' ) ;
2019-07-16 04:13:32 +00:00
w . setFullScreen ( false ) ;
await leftFullScreen ;
expect ( w . isVisible ( ) ) . to . be . true ( 'visible' ) ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'fullscreen' ) ;
} ) ;
it ( 'should keep window hidden if already in hidden state' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
await w . loadURL ( 'about:blank' ) ;
2023-02-23 23:53:53 +00:00
const leftFullScreen = once ( w , 'leave-full-screen' ) ;
2019-07-16 04:13:32 +00:00
w . setFullScreen ( false ) ;
await leftFullScreen ;
expect ( w . isVisible ( ) ) . to . be . false ( 'visible' ) ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'fullscreen' ) ;
} ) ;
} ) ;
ifdescribe ( process . platform === 'darwin' ) ( 'BrowserWindow.setFullScreen(false) when HTML fullscreen' , ( ) = > {
it ( 'exits HTML fullscreen when window leaves fullscreen' , async ( ) = > {
const w = new BrowserWindow ( ) ;
await w . loadURL ( 'about:blank' ) ;
await w . webContents . executeJavaScript ( 'document.body.webkitRequestFullscreen()' , true ) ;
2023-02-23 23:53:53 +00:00
await once ( w , 'enter-full-screen' ) ;
2019-07-16 04:13:32 +00:00
// Wait a tick for the full-screen state to 'stick'
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2019-07-16 04:13:32 +00:00
w . setFullScreen ( false ) ;
2023-02-23 23:53:53 +00:00
await once ( w , 'leave-html-full-screen' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
} ) ;
} ) ;
describe ( 'parent window' , ( ) = > {
afterEach ( closeAllWindows ) ;
2020-07-01 19:14:38 +00:00
ifit ( process . platform === 'darwin' ) ( 'sheet-begin event emits when window opens a sheet' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( ) ;
2023-02-23 23:53:53 +00:00
const sheetBegin = once ( w , 'sheet-begin' ) ;
2019-11-01 20:37:02 +00:00
// eslint-disable-next-line no-new
2019-07-16 04:13:32 +00:00
new BrowserWindow ( {
modal : true ,
parent : w
} ) ;
2020-07-01 19:14:38 +00:00
await sheetBegin ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-07-01 19:14:38 +00:00
ifit ( process . platform === 'darwin' ) ( 'sheet-end event emits when window has closed a sheet' , async ( ) = > {
2019-07-16 04:13:32 +00:00
const w = new BrowserWindow ( ) ;
const sheet = new BrowserWindow ( {
modal : true ,
parent : w
} ) ;
2023-02-23 23:53:53 +00:00
const sheetEnd = once ( w , 'sheet-end' ) ;
2019-07-16 04:13:32 +00:00
sheet . close ( ) ;
2020-07-01 19:14:38 +00:00
await sheetEnd ;
2019-07-16 04:13:32 +00:00
} ) ;
describe ( 'parent option' , ( ) = > {
it ( 'sets parent window' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { show : false , parent : w } ) ;
2019-07-16 04:13:32 +00:00
expect ( c . getParentWindow ( ) ) . to . equal ( w ) ;
} ) ;
2023-05-31 09:57:44 +00:00
2019-07-16 04:13:32 +00:00
it ( 'adds window to child windows of parent' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { show : false , parent : w } ) ;
2019-07-16 04:13:32 +00:00
expect ( w . getChildWindows ( ) ) . to . deep . equal ( [ c ] ) ;
} ) ;
2023-05-31 09:57:44 +00:00
2020-06-30 22:10:36 +00:00
it ( 'removes from child windows of parent when window is closed' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { show : false , parent : w } ) ;
2023-02-23 23:53:53 +00:00
const closed = once ( c , 'closed' ) ;
2019-07-16 04:13:32 +00:00
c . close ( ) ;
2020-06-30 22:10:36 +00:00
await closed ;
// The child window list is not immediately cleared, so wait a tick until it's ready.
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2020-06-30 22:10:36 +00:00
expect ( w . getChildWindows ( ) . length ) . to . equal ( 0 ) ;
2023-06-08 10:18:37 +00:00
} ) ;
it ( 'can handle child window close and reparent multiple times' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
let c : BrowserWindow | null ;
for ( let i = 0 ; i < 5 ; i ++ ) {
c = new BrowserWindow ( { show : false , parent : w } ) ;
const closed = once ( c , 'closed' ) ;
c . close ( ) ;
await closed ;
}
await setTimeout ( ) ;
expect ( w . getChildWindows ( ) . length ) . to . equal ( 0 ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2023-10-05 13:19:57 +00:00
ifit ( process . platform === 'darwin' ) ( 'only shows the intended window when a child with siblings is shown' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
const childOne = new BrowserWindow ( { show : false , parent : w } ) ;
const childTwo = new BrowserWindow ( { show : false , parent : w } ) ;
const parentShown = once ( w , 'show' ) ;
w . show ( ) ;
await parentShown ;
expect ( childOne . isVisible ( ) ) . to . be . false ( 'childOne is visible' ) ;
expect ( childTwo . isVisible ( ) ) . to . be . false ( 'childTwo is visible' ) ;
const childOneShown = once ( childOne , 'show' ) ;
childOne . show ( ) ;
await childOneShown ;
expect ( childOne . isVisible ( ) ) . to . be . true ( 'childOne is not visible' ) ;
expect ( childTwo . isVisible ( ) ) . to . be . false ( 'childTwo is visible' ) ;
} ) ;
ifit ( process . platform === 'darwin' ) ( 'child matches parent visibility when parent visibility changes' , async ( ) = > {
2023-05-31 09:57:44 +00:00
const w = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { show : false , parent : w } ) ;
const wShow = once ( w , 'show' ) ;
const cShow = once ( c , 'show' ) ;
w . show ( ) ;
c . show ( ) ;
await Promise . all ( [ wShow , cShow ] ) ;
const minimized = once ( w , 'minimize' ) ;
w . minimize ( ) ;
await minimized ;
expect ( w . isVisible ( ) ) . to . be . false ( 'parent is visible' ) ;
expect ( c . isVisible ( ) ) . to . be . false ( 'child is visible' ) ;
const restored = once ( w , 'restore' ) ;
w . restore ( ) ;
await restored ;
expect ( w . isVisible ( ) ) . to . be . true ( 'parent is visible' ) ;
expect ( c . isVisible ( ) ) . to . be . true ( 'child is visible' ) ;
} ) ;
2023-10-05 13:19:57 +00:00
ifit ( process . platform === 'darwin' ) ( 'parent matches child visibility when child visibility changes' , async ( ) = > {
2023-05-31 09:57:44 +00:00
const w = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { show : false , parent : w } ) ;
const wShow = once ( w , 'show' ) ;
const cShow = once ( c , 'show' ) ;
w . show ( ) ;
c . show ( ) ;
await Promise . all ( [ wShow , cShow ] ) ;
const minimized = once ( c , 'minimize' ) ;
c . minimize ( ) ;
await minimized ;
expect ( c . isVisible ( ) ) . to . be . false ( 'child is visible' ) ;
const restored = once ( c , 'restore' ) ;
c . restore ( ) ;
await restored ;
expect ( w . isVisible ( ) ) . to . be . true ( 'parent is visible' ) ;
expect ( c . isVisible ( ) ) . to . be . true ( 'child is visible' ) ;
} ) ;
2023-09-04 10:33:29 +00:00
it ( 'closes a grandchild window when a middle child window is destroyed' , async ( ) = > {
2022-03-29 16:22:58 +00:00
const w = new BrowserWindow ( ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'base-page.html' ) ) ;
w . webContents . executeJavaScript ( 'window.open("")' ) ;
w . webContents . on ( 'did-create-window' , async ( window ) = > {
const childWindow = new BrowserWindow ( { parent : window } ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2023-09-04 10:33:29 +00:00
const closed = once ( childWindow , 'closed' ) ;
2022-03-29 16:22:58 +00:00
window . close ( ) ;
2023-09-04 10:33:29 +00:00
await closed ;
2022-03-29 16:22:58 +00:00
2023-09-04 10:33:29 +00:00
expect ( ( ) = > { BrowserWindow . getFocusedWindow ( ) ; } ) . to . not . throw ( ) ;
2022-03-29 16:22:58 +00:00
} ) ;
} ) ;
2019-07-16 04:13:32 +00:00
it ( 'should not affect the show option' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { show : false , parent : w } ) ;
2019-07-16 04:13:32 +00:00
expect ( c . isVisible ( ) ) . to . be . false ( 'child is visible' ) ;
2021-10-25 15:10:33 +00:00
expect ( c . getParentWindow ( ) ! . isVisible ( ) ) . to . be . false ( 'parent is visible' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
} ) ;
describe ( 'win.setParentWindow(parent)' , ( ) = > {
it ( 'sets parent window' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
expect ( w . getParentWindow ( ) ) . to . be . null ( 'w.parent' ) ;
expect ( c . getParentWindow ( ) ) . to . be . null ( 'c.parent' ) ;
c . setParentWindow ( w ) ;
expect ( c . getParentWindow ( ) ) . to . equal ( w ) ;
c . setParentWindow ( null ) ;
expect ( c . getParentWindow ( ) ) . to . be . null ( 'c.parent' ) ;
} ) ;
2023-07-26 14:47:32 +00:00
2019-07-16 04:13:32 +00:00
it ( 'adds window to child windows of parent' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
expect ( w . getChildWindows ( ) ) . to . deep . equal ( [ ] ) ;
c . setParentWindow ( w ) ;
expect ( w . getChildWindows ( ) ) . to . deep . equal ( [ c ] ) ;
c . setParentWindow ( null ) ;
expect ( w . getChildWindows ( ) ) . to . deep . equal ( [ ] ) ;
} ) ;
2023-07-26 14:47:32 +00:00
2020-06-30 22:10:36 +00:00
it ( 'removes from child windows of parent when window is closed' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { show : false } ) ;
2023-02-23 23:53:53 +00:00
const closed = once ( c , 'closed' ) ;
2019-07-16 04:13:32 +00:00
c . setParentWindow ( w ) ;
c . close ( ) ;
2020-06-30 22:10:36 +00:00
await closed ;
// The child window list is not immediately cleared, so wait a tick until it's ready.
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2020-06-30 22:10:36 +00:00
expect ( w . getChildWindows ( ) . length ) . to . equal ( 0 ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2023-07-26 14:47:32 +00:00
ifit ( process . platform === 'darwin' ) ( 'can reparent when the first parent is destroyed' , async ( ) = > {
const w1 = new BrowserWindow ( { show : false } ) ;
const w2 = new BrowserWindow ( { show : false } ) ;
const c = new BrowserWindow ( { show : false } ) ;
c . setParentWindow ( w1 ) ;
expect ( w1 . getChildWindows ( ) . length ) . to . equal ( 1 ) ;
const closed = once ( w1 , 'closed' ) ;
w1 . destroy ( ) ;
await closed ;
c . setParentWindow ( w2 ) ;
await setTimeout ( ) ;
const children = w2 . getChildWindows ( ) ;
expect ( children [ 0 ] ) . to . equal ( c ) ;
} ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-02-28 23:10:21 +00:00
describe ( 'modal option' , ( ) = > {
it ( 'does not freeze or crash' , async ( ) = > {
const parentWindow = new BrowserWindow ( ) ;
const createTwo = async ( ) = > {
const two = new BrowserWindow ( {
width : 300 ,
height : 200 ,
parent : parentWindow ,
modal : true ,
show : false
} ) ;
2023-02-23 23:53:53 +00:00
const twoShown = once ( two , 'show' ) ;
2020-02-28 23:10:21 +00:00
two . show ( ) ;
await twoShown ;
2023-02-23 23:53:53 +00:00
setTimeout ( 500 ) . then ( ( ) = > two . close ( ) ) ;
2020-02-28 23:10:21 +00:00
2023-02-23 23:53:53 +00:00
await once ( two , 'closed' ) ;
2020-02-28 23:10:21 +00:00
} ;
const one = new BrowserWindow ( {
width : 600 ,
height : 400 ,
parent : parentWindow ,
modal : true ,
show : false
} ) ;
2023-02-23 23:53:53 +00:00
const oneShown = once ( one , 'show' ) ;
2020-02-28 23:10:21 +00:00
one . show ( ) ;
await oneShown ;
2023-02-23 23:53:53 +00:00
setTimeout ( 500 ) . then ( ( ) = > one . destroy ( ) ) ;
2020-02-28 23:10:21 +00:00
2023-02-23 23:53:53 +00:00
await once ( one , 'closed' ) ;
2020-02-28 23:10:21 +00:00
await createTwo ( ) ;
} ) ;
2022-07-19 10:31:49 +00:00
ifit ( process . platform !== 'darwin' ) ( 'can disable and enable a window' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . setEnabled ( false ) ;
expect ( w . isEnabled ( ) ) . to . be . false ( 'w.isEnabled()' ) ;
w . setEnabled ( true ) ;
expect ( w . isEnabled ( ) ) . to . be . true ( '!w.isEnabled()' ) ;
} ) ;
2020-02-28 23:10:21 +00:00
ifit ( process . platform !== 'darwin' ) ( 'disables parent window' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
const c = new BrowserWindow ( { show : false , parent : w , modal : true } ) ;
expect ( w . isEnabled ( ) ) . to . be . true ( 'w.isEnabled' ) ;
c . show ( ) ;
expect ( w . isEnabled ( ) ) . to . be . false ( 'w.isEnabled' ) ;
} ) ;
2020-02-28 23:10:21 +00:00
2020-06-30 22:10:36 +00:00
ifit ( process . platform !== 'darwin' ) ( 're-enables an enabled parent window when closed' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
const c = new BrowserWindow ( { show : false , parent : w , modal : true } ) ;
2023-02-23 23:53:53 +00:00
const closed = once ( c , 'closed' ) ;
2019-07-16 04:13:32 +00:00
c . show ( ) ;
c . close ( ) ;
2020-06-30 22:10:36 +00:00
await closed ;
expect ( w . isEnabled ( ) ) . to . be . true ( 'w.isEnabled' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-02-28 23:10:21 +00:00
2020-06-30 22:10:36 +00:00
ifit ( process . platform !== 'darwin' ) ( 'does not re-enable a disabled parent window when closed' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
const c = new BrowserWindow ( { show : false , parent : w , modal : true } ) ;
2023-02-23 23:53:53 +00:00
const closed = once ( c , 'closed' ) ;
2019-07-16 04:13:32 +00:00
w . setEnabled ( false ) ;
c . show ( ) ;
c . close ( ) ;
2020-06-30 22:10:36 +00:00
await closed ;
expect ( w . isEnabled ( ) ) . to . be . false ( 'w.isEnabled' ) ;
2019-07-16 04:13:32 +00:00
} ) ;
2020-02-28 23:10:21 +00:00
ifit ( process . platform !== 'darwin' ) ( 'disables parent window recursively' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-16 04:13:32 +00:00
const c = new BrowserWindow ( { show : false , parent : w , modal : true } ) ;
const c2 = new BrowserWindow ( { show : false , parent : w , modal : true } ) ;
c . show ( ) ;
expect ( w . isEnabled ( ) ) . to . be . false ( 'w.isEnabled' ) ;
c2 . show ( ) ;
expect ( w . isEnabled ( ) ) . to . be . false ( 'w.isEnabled' ) ;
c . destroy ( ) ;
expect ( w . isEnabled ( ) ) . to . be . false ( 'w.isEnabled' ) ;
c2 . destroy ( ) ;
expect ( w . isEnabled ( ) ) . to . be . true ( 'w.isEnabled' ) ;
} ) ;
} ) ;
} ) ;
2019-07-16 23:37:17 +00:00
describe ( 'window states' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'does not resize frameless windows when states change' , ( ) = > {
const w = new BrowserWindow ( {
frame : false ,
width : 300 ,
height : 200 ,
show : false
} ) ;
w . minimizable = false ;
w . minimizable = true ;
expect ( w . getSize ( ) ) . to . deep . equal ( [ 300 , 200 ] ) ;
w . resizable = false ;
w . resizable = true ;
expect ( w . getSize ( ) ) . to . deep . equal ( [ 300 , 200 ] ) ;
w . maximizable = false ;
w . maximizable = true ;
expect ( w . getSize ( ) ) . to . deep . equal ( [ 300 , 200 ] ) ;
w . fullScreenable = false ;
w . fullScreenable = true ;
expect ( w . getSize ( ) ) . to . deep . equal ( [ 300 , 200 ] ) ;
w . closable = false ;
w . closable = true ;
expect ( w . getSize ( ) ) . to . deep . equal ( [ 300 , 200 ] ) ;
} ) ;
describe ( 'resizable state' , ( ) = > {
2020-03-16 21:03:35 +00:00
it ( 'with properties' , ( ) = > {
it ( 'can be set with resizable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , resizable : false } ) ;
expect ( w . resizable ) . to . be . false ( 'resizable' ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
if ( process . platform === 'darwin' ) {
expect ( w . maximizable ) . to . to . true ( 'maximizable' ) ;
}
} ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . resizable ) . to . be . true ( 'resizable' ) ;
w . resizable = false ;
expect ( w . resizable ) . to . be . false ( 'resizable' ) ;
w . resizable = true ;
expect ( w . resizable ) . to . be . true ( 'resizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-03-16 21:03:35 +00:00
it ( 'with functions' , ( ) = > {
it ( 'can be set with resizable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , resizable : false } ) ;
expect ( w . isResizable ( ) ) . to . be . false ( 'resizable' ) ;
if ( process . platform === 'darwin' ) {
expect ( w . isMaximizable ( ) ) . to . to . true ( 'maximizable' ) ;
}
} ) ;
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isResizable ( ) ) . to . be . true ( 'resizable' ) ;
w . setResizable ( false ) ;
expect ( w . isResizable ( ) ) . to . be . false ( 'resizable' ) ;
w . setResizable ( true ) ;
expect ( w . isResizable ( ) ) . to . be . true ( 'resizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
it ( 'works for a frameless window' , ( ) = > {
const w = new BrowserWindow ( { show : false , frame : false } ) ;
expect ( w . resizable ) . to . be . true ( 'resizable' ) ;
if ( process . platform === 'win32' ) {
const w = new BrowserWindow ( { show : false , thickFrame : false } ) ;
expect ( w . resizable ) . to . be . false ( 'resizable' ) ;
}
} ) ;
2021-09-17 13:54:15 +00:00
// On Linux there is no "resizable" property of a window.
ifit ( process . platform !== 'linux' ) ( 'does affect maximizability when disabled and enabled' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . resizable ) . to . be . true ( 'resizable' ) ;
expect ( w . maximizable ) . to . be . true ( 'maximizable' ) ;
w . resizable = false ;
expect ( w . maximizable ) . to . be . false ( 'not maximizable' ) ;
w . resizable = true ;
expect ( w . maximizable ) . to . be . true ( 'maximizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
ifit ( process . platform === 'win32' ) ( 'works for a window smaller than 64x64' , ( ) = > {
const w = new BrowserWindow ( {
show : false ,
frame : false ,
resizable : false ,
transparent : true
} ) ;
w . setContentSize ( 60 , 60 ) ;
expectBoundsEqual ( w . getContentSize ( ) , [ 60 , 60 ] ) ;
w . setContentSize ( 30 , 30 ) ;
expectBoundsEqual ( w . getContentSize ( ) , [ 30 , 30 ] ) ;
w . setContentSize ( 10 , 10 ) ;
expectBoundsEqual ( w . getContentSize ( ) , [ 10 , 10 ] ) ;
} ) ;
2023-11-22 06:21:18 +00:00
ifit ( process . platform === 'win32' ) ( 'do not change window with frame bounds when maximized' , ( ) = > {
const w = new BrowserWindow ( {
show : true ,
frame : true ,
thickFrame : true
} ) ;
expect ( w . isResizable ( ) ) . to . be . true ( 'resizable' ) ;
w . maximize ( ) ;
expect ( w . isMaximized ( ) ) . to . be . true ( 'maximized' ) ;
const bounds = w . getBounds ( ) ;
w . setResizable ( false ) ;
expectBoundsEqual ( w . getBounds ( ) , bounds ) ;
w . setResizable ( true ) ;
expectBoundsEqual ( w . getBounds ( ) , bounds ) ;
} ) ;
ifit ( process . platform === 'win32' ) ( 'do not change window without frame bounds when maximized' , ( ) = > {
const w = new BrowserWindow ( {
show : true ,
frame : false ,
thickFrame : true
} ) ;
expect ( w . isResizable ( ) ) . to . be . true ( 'resizable' ) ;
w . maximize ( ) ;
expect ( w . isMaximized ( ) ) . to . be . true ( 'maximized' ) ;
const bounds = w . getBounds ( ) ;
w . setResizable ( false ) ;
expectBoundsEqual ( w . getBounds ( ) , bounds ) ;
w . setResizable ( true ) ;
expectBoundsEqual ( w . getBounds ( ) , bounds ) ;
} ) ;
ifit ( process . platform === 'win32' ) ( 'do not change window transparent without frame bounds when maximized' , ( ) = > {
const w = new BrowserWindow ( {
show : true ,
frame : false ,
thickFrame : true ,
transparent : true
} ) ;
expect ( w . isResizable ( ) ) . to . be . true ( 'resizable' ) ;
w . maximize ( ) ;
expect ( w . isMaximized ( ) ) . to . be . true ( 'maximized' ) ;
const bounds = w . getBounds ( ) ;
w . setResizable ( false ) ;
expectBoundsEqual ( w . getBounds ( ) , bounds ) ;
w . setResizable ( true ) ;
expectBoundsEqual ( w . getBounds ( ) , bounds ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
describe ( 'loading main frame state' , ( ) = > {
2023-02-19 09:24:24 +00:00
let server : http.Server ;
let serverUrl : string ;
2019-07-16 23:37:17 +00:00
2023-02-20 11:30:57 +00:00
before ( async ( ) = > {
2019-07-16 23:37:17 +00:00
server = http . createServer ( ( request , response ) = > {
response . end ( ) ;
} ) ;
2023-02-20 11:30:57 +00:00
serverUrl = ( await listen ( server ) ) . url ;
2019-07-16 23:37:17 +00:00
} ) ;
after ( ( ) = > {
server . close ( ) ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'is true when the main frame is loading' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2020-06-30 22:10:36 +00:00
2023-02-23 23:53:53 +00:00
const didStartLoading = once ( w . webContents , 'did-start-loading' ) ;
2019-07-16 23:37:17 +00:00
w . webContents . loadURL ( serverUrl ) ;
2020-06-30 22:10:36 +00:00
await didStartLoading ;
expect ( w . webContents . isLoadingMainFrame ( ) ) . to . be . true ( 'isLoadingMainFrame' ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'is false when only a subframe is loading' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2020-06-30 22:10:36 +00:00
2023-02-23 23:53:53 +00:00
const didStopLoading = once ( w . webContents , 'did-stop-loading' ) ;
2019-07-16 23:37:17 +00:00
w . webContents . loadURL ( serverUrl ) ;
2020-06-30 22:10:36 +00:00
await didStopLoading ;
expect ( w . webContents . isLoadingMainFrame ( ) ) . to . be . false ( 'isLoadingMainFrame' ) ;
2023-02-23 23:53:53 +00:00
const didStartLoading = once ( w . webContents , 'did-start-loading' ) ;
2020-06-30 22:10:36 +00:00
w . webContents . executeJavaScript ( `
var iframe = document . createElement ( 'iframe' )
iframe . src = '${serverUrl}/page2'
document . body . appendChild ( iframe )
` );
await didStartLoading ;
expect ( w . webContents . isLoadingMainFrame ( ) ) . to . be . false ( 'isLoadingMainFrame' ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'is true when navigating to pages from the same origin' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2020-06-30 22:10:36 +00:00
2023-02-23 23:53:53 +00:00
const didStopLoading = once ( w . webContents , 'did-stop-loading' ) ;
2019-07-16 23:37:17 +00:00
w . webContents . loadURL ( serverUrl ) ;
2020-06-30 22:10:36 +00:00
await didStopLoading ;
expect ( w . webContents . isLoadingMainFrame ( ) ) . to . be . false ( 'isLoadingMainFrame' ) ;
2023-02-23 23:53:53 +00:00
const didStartLoading = once ( w . webContents , 'did-start-loading' ) ;
2020-06-30 22:10:36 +00:00
w . webContents . loadURL ( ` ${ serverUrl } /page2 ` ) ;
await didStartLoading ;
expect ( w . webContents . isLoadingMainFrame ( ) ) . to . be . true ( 'isLoadingMainFrame' ) ;
2019-07-16 23:37:17 +00:00
} ) ;
} ) ;
} ) ;
ifdescribe ( process . platform !== 'linux' ) ( 'window states (excluding Linux)' , ( ) = > {
// Not implemented on Linux.
afterEach ( closeAllWindows ) ;
2020-03-16 21:03:35 +00:00
describe ( 'movable state' , ( ) = > {
it ( 'with properties' , ( ) = > {
it ( 'can be set with movable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , movable : false } ) ;
expect ( w . movable ) . to . be . false ( 'movable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . movable ) . to . be . true ( 'movable' ) ;
w . movable = false ;
expect ( w . movable ) . to . be . false ( 'movable' ) ;
w . movable = true ;
expect ( w . movable ) . to . be . true ( 'movable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-03-16 21:03:35 +00:00
it ( 'with functions' , ( ) = > {
it ( 'can be set with movable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , movable : false } ) ;
expect ( w . isMovable ( ) ) . to . be . false ( 'movable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isMovable ( ) ) . to . be . true ( 'movable' ) ;
w . setMovable ( false ) ;
expect ( w . isMovable ( ) ) . to . be . false ( 'movable' ) ;
w . setMovable ( true ) ;
expect ( w . isMovable ( ) ) . to . be . true ( 'movable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
} ) ;
2020-04-01 15:22:32 +00:00
describe ( 'visibleOnAllWorkspaces state' , ( ) = > {
it ( 'with properties' , ( ) = > {
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . visibleOnAllWorkspaces ) . to . be . false ( ) ;
w . visibleOnAllWorkspaces = true ;
expect ( w . visibleOnAllWorkspaces ) . to . be . true ( ) ;
} ) ;
} ) ;
it ( 'with functions' , ( ) = > {
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isVisibleOnAllWorkspaces ( ) ) . to . be . false ( ) ;
w . setVisibleOnAllWorkspaces ( true ) ;
expect ( w . isVisibleOnAllWorkspaces ( ) ) . to . be . true ( ) ;
} ) ;
} ) ;
} ) ;
ifdescribe ( process . platform === 'darwin' ) ( 'documentEdited state' , ( ) = > {
it ( 'with properties' , ( ) = > {
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . documentEdited ) . to . be . false ( ) ;
w . documentEdited = true ;
expect ( w . documentEdited ) . to . be . true ( ) ;
} ) ;
} ) ;
it ( 'with functions' , ( ) = > {
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isDocumentEdited ( ) ) . to . be . false ( ) ;
w . setDocumentEdited ( true ) ;
expect ( w . isDocumentEdited ( ) ) . to . be . true ( ) ;
} ) ;
} ) ;
} ) ;
ifdescribe ( process . platform === 'darwin' ) ( 'representedFilename' , ( ) = > {
it ( 'with properties' , ( ) = > {
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . representedFilename ) . to . eql ( '' ) ;
w . representedFilename = 'a name' ;
expect ( w . representedFilename ) . to . eql ( 'a name' ) ;
} ) ;
} ) ;
it ( 'with functions' , ( ) = > {
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . getRepresentedFilename ( ) ) . to . eql ( '' ) ;
w . setRepresentedFilename ( 'a name' ) ;
expect ( w . getRepresentedFilename ( ) ) . to . eql ( 'a name' ) ;
} ) ;
} ) ;
} ) ;
describe ( 'native window title' , ( ) = > {
it ( 'with properties' , ( ) = > {
it ( 'can be set with title constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , title : 'mYtItLe' } ) ;
expect ( w . title ) . to . eql ( 'mYtItLe' ) ;
} ) ;
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . title ) . to . eql ( 'Electron Test Main' ) ;
w . title = 'NEW TITLE' ;
expect ( w . title ) . to . eql ( 'NEW TITLE' ) ;
} ) ;
} ) ;
it ( 'with functions' , ( ) = > {
it ( 'can be set with minimizable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , title : 'mYtItLe' } ) ;
expect ( w . getTitle ( ) ) . to . eql ( 'mYtItLe' ) ;
} ) ;
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . getTitle ( ) ) . to . eql ( 'Electron Test Main' ) ;
w . setTitle ( 'NEW TITLE' ) ;
expect ( w . getTitle ( ) ) . to . eql ( 'NEW TITLE' ) ;
} ) ;
} ) ;
} ) ;
2020-03-16 21:03:35 +00:00
describe ( 'minimizable state' , ( ) = > {
it ( 'with properties' , ( ) = > {
it ( 'can be set with minimizable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , minimizable : false } ) ;
expect ( w . minimizable ) . to . be . false ( 'minimizable' ) ;
} ) ;
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . minimizable ) . to . be . true ( 'minimizable' ) ;
w . minimizable = false ;
expect ( w . minimizable ) . to . be . false ( 'minimizable' ) ;
w . minimizable = true ;
expect ( w . minimizable ) . to . be . true ( 'minimizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-03-16 21:03:35 +00:00
it ( 'with functions' , ( ) = > {
it ( 'can be set with minimizable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , minimizable : false } ) ;
expect ( w . isMinimizable ( ) ) . to . be . false ( 'movable' ) ;
} ) ;
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isMinimizable ( ) ) . to . be . true ( 'isMinimizable' ) ;
w . setMinimizable ( false ) ;
expect ( w . isMinimizable ( ) ) . to . be . false ( 'isMinimizable' ) ;
w . setMinimizable ( true ) ;
expect ( w . isMinimizable ( ) ) . to . be . true ( 'isMinimizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
} ) ;
describe ( 'maximizable state (property)' , ( ) = > {
2020-03-16 21:03:35 +00:00
it ( 'with properties' , ( ) = > {
it ( 'can be set with maximizable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , maximizable : false } ) ;
expect ( w . maximizable ) . to . be . false ( 'maximizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . maximizable ) . to . be . true ( 'maximizable' ) ;
w . maximizable = false ;
expect ( w . maximizable ) . to . be . false ( 'maximizable' ) ;
w . maximizable = true ;
expect ( w . maximizable ) . to . be . true ( 'maximizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
it ( 'is not affected when changing other states' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . maximizable = false ;
expect ( w . maximizable ) . to . be . false ( 'maximizable' ) ;
w . minimizable = false ;
expect ( w . maximizable ) . to . be . false ( 'maximizable' ) ;
w . closable = false ;
expect ( w . maximizable ) . to . be . false ( 'maximizable' ) ;
2020-03-20 20:28:31 +00:00
2020-03-16 21:03:35 +00:00
w . maximizable = true ;
expect ( w . maximizable ) . to . be . true ( 'maximizable' ) ;
w . closable = true ;
expect ( w . maximizable ) . to . be . true ( 'maximizable' ) ;
w . fullScreenable = false ;
expect ( w . maximizable ) . to . be . true ( 'maximizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-03-16 21:03:35 +00:00
it ( 'with functions' , ( ) = > {
it ( 'can be set with maximizable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , maximizable : false } ) ;
expect ( w . isMaximizable ( ) ) . to . be . false ( 'isMaximizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isMaximizable ( ) ) . to . be . true ( 'isMaximizable' ) ;
w . setMaximizable ( false ) ;
expect ( w . isMaximizable ( ) ) . to . be . false ( 'isMaximizable' ) ;
w . setMaximizable ( true ) ;
expect ( w . isMaximizable ( ) ) . to . be . true ( 'isMaximizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
it ( 'is not affected when changing other states' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . setMaximizable ( false ) ;
expect ( w . isMaximizable ( ) ) . to . be . false ( 'isMaximizable' ) ;
w . setMinimizable ( false ) ;
expect ( w . isMaximizable ( ) ) . to . be . false ( 'isMaximizable' ) ;
w . setClosable ( false ) ;
expect ( w . isMaximizable ( ) ) . to . be . false ( 'isMaximizable' ) ;
2020-03-20 20:28:31 +00:00
2020-03-16 21:03:35 +00:00
w . setMaximizable ( true ) ;
expect ( w . isMaximizable ( ) ) . to . be . true ( 'isMaximizable' ) ;
w . setClosable ( true ) ;
expect ( w . isMaximizable ( ) ) . to . be . true ( 'isMaximizable' ) ;
w . setFullScreenable ( false ) ;
expect ( w . isMaximizable ( ) ) . to . be . true ( 'isMaximizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
} ) ;
2020-03-16 21:03:35 +00:00
ifdescribe ( process . platform === 'win32' ) ( 'maximizable state' , ( ) = > {
it ( 'with properties' , ( ) = > {
it ( 'is reset to its former state' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . maximizable = false ;
w . resizable = false ;
w . resizable = true ;
expect ( w . maximizable ) . to . be . false ( 'maximizable' ) ;
w . maximizable = true ;
w . resizable = false ;
w . resizable = true ;
expect ( w . maximizable ) . to . be . true ( 'maximizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-03-16 21:03:35 +00:00
it ( 'with functions' , ( ) = > {
it ( 'is reset to its former state' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . setMaximizable ( false ) ;
w . setResizable ( false ) ;
w . setResizable ( true ) ;
expect ( w . isMaximizable ( ) ) . to . be . false ( 'isMaximizable' ) ;
w . setMaximizable ( true ) ;
w . setResizable ( false ) ;
w . setResizable ( true ) ;
expect ( w . isMaximizable ( ) ) . to . be . true ( 'isMaximizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
} ) ;
2020-04-01 15:22:32 +00:00
ifdescribe ( process . platform !== 'darwin' ) ( 'menuBarVisible state' , ( ) = > {
describe ( 'with properties' , ( ) = > {
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . menuBarVisible ) . to . be . true ( ) ;
w . menuBarVisible = false ;
expect ( w . menuBarVisible ) . to . be . false ( ) ;
w . menuBarVisible = true ;
expect ( w . menuBarVisible ) . to . be . true ( ) ;
2020-03-16 21:03:35 +00:00
} ) ;
2020-04-01 15:22:32 +00:00
} ) ;
2019-07-16 23:37:17 +00:00
2020-04-01 15:22:32 +00:00
describe ( 'with functions' , ( ) = > {
2020-03-16 21:03:35 +00:00
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
2020-04-01 15:22:32 +00:00
expect ( w . isMenuBarVisible ( ) ) . to . be . true ( 'isMenuBarVisible' ) ;
w . setMenuBarVisibility ( false ) ;
expect ( w . isMenuBarVisible ( ) ) . to . be . false ( 'isMenuBarVisible' ) ;
w . setMenuBarVisibility ( true ) ;
expect ( w . isMenuBarVisible ( ) ) . to . be . true ( 'isMenuBarVisible' ) ;
2020-03-16 21:03:35 +00:00
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-04-01 15:22:32 +00:00
} ) ;
2019-07-16 23:37:17 +00:00
2023-06-08 10:19:34 +00:00
ifdescribe ( process . platform !== 'darwin' ) ( 'when fullscreen state is changed' , ( ) = > {
it ( 'correctly remembers state prior to fullscreen change' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isMenuBarVisible ( ) ) . to . be . true ( 'isMenuBarVisible' ) ;
w . setMenuBarVisibility ( false ) ;
expect ( w . isMenuBarVisible ( ) ) . to . be . false ( 'isMenuBarVisible' ) ;
const enterFS = once ( w , 'enter-full-screen' ) ;
w . setFullScreen ( true ) ;
await enterFS ;
expect ( w . fullScreen ) . to . be . true ( 'not fullscreen' ) ;
const exitFS = once ( w , 'leave-full-screen' ) ;
w . setFullScreen ( false ) ;
await exitFS ;
expect ( w . fullScreen ) . to . be . false ( 'not fullscreen' ) ;
expect ( w . isMenuBarVisible ( ) ) . to . be . false ( 'isMenuBarVisible' ) ;
} ) ;
it ( 'correctly remembers state prior to fullscreen change with autoHide' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . autoHideMenuBar ) . to . be . false ( 'autoHideMenuBar' ) ;
w . autoHideMenuBar = true ;
expect ( w . autoHideMenuBar ) . to . be . true ( 'autoHideMenuBar' ) ;
w . setMenuBarVisibility ( false ) ;
expect ( w . isMenuBarVisible ( ) ) . to . be . false ( 'isMenuBarVisible' ) ;
const enterFS = once ( w , 'enter-full-screen' ) ;
w . setFullScreen ( true ) ;
await enterFS ;
expect ( w . fullScreen ) . to . be . true ( 'not fullscreen' ) ;
const exitFS = once ( w , 'leave-full-screen' ) ;
w . setFullScreen ( false ) ;
await exitFS ;
expect ( w . fullScreen ) . to . be . false ( 'not fullscreen' ) ;
expect ( w . isMenuBarVisible ( ) ) . to . be . false ( 'isMenuBarVisible' ) ;
} ) ;
} ) ;
2020-04-01 15:22:32 +00:00
ifdescribe ( process . platform === 'darwin' ) ( 'fullscreenable state' , ( ) = > {
2020-03-16 21:03:35 +00:00
it ( 'with functions' , ( ) = > {
it ( 'can be set with fullscreenable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , fullscreenable : false } ) ;
expect ( w . isFullScreenable ( ) ) . to . be . false ( 'isFullScreenable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isFullScreenable ( ) ) . to . be . true ( 'isFullScreenable' ) ;
w . setFullScreenable ( false ) ;
expect ( w . isFullScreenable ( ) ) . to . be . false ( 'isFullScreenable' ) ;
w . setFullScreenable ( true ) ;
expect ( w . isFullScreenable ( ) ) . to . be . true ( 'isFullScreenable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2023-08-24 20:54:08 +00:00
it ( 'does not open non-fullscreenable child windows in fullscreen if parent is fullscreen' , async ( ) = > {
const w = new BrowserWindow ( ) ;
const enterFS = once ( w , 'enter-full-screen' ) ;
w . setFullScreen ( true ) ;
await enterFS ;
const child = new BrowserWindow ( { parent : w , resizable : false , fullscreenable : false } ) ;
const shown = once ( child , 'show' ) ;
await shown ;
expect ( child . resizable ) . to . be . false ( 'resizable' ) ;
expect ( child . fullScreen ) . to . be . false ( 'fullscreen' ) ;
expect ( child . fullScreenable ) . to . be . false ( 'fullscreenable' ) ;
} ) ;
it ( 'is set correctly with different resizable values' , async ( ) = > {
const w1 = new BrowserWindow ( {
resizable : false ,
fullscreenable : false
} ) ;
const w2 = new BrowserWindow ( {
resizable : true ,
fullscreenable : false
} ) ;
const w3 = new BrowserWindow ( {
fullscreenable : false
} ) ;
expect ( w1 . isFullScreenable ( ) ) . to . be . false ( 'isFullScreenable' ) ;
expect ( w2 . isFullScreenable ( ) ) . to . be . false ( 'isFullScreenable' ) ;
expect ( w3 . isFullScreenable ( ) ) . to . be . false ( 'isFullScreenable' ) ;
} ) ;
2024-01-05 17:15:35 +00:00
it ( 'does not disable maximize button if window is resizable' , ( ) = > {
const w = new BrowserWindow ( {
resizable : true ,
fullscreenable : false
} ) ;
expect ( w . isMaximizable ( ) ) . to . be . true ( 'isMaximizable' ) ;
w . setResizable ( false ) ;
expect ( w . isMaximizable ( ) ) . to . be . false ( 'isMaximizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2022-11-01 20:43:42 +00:00
ifdescribe ( process . platform === 'darwin' ) ( 'isHiddenInMissionControl state' , ( ) = > {
it ( 'with functions' , ( ) = > {
it ( 'can be set with ignoreMissionControl constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , hiddenInMissionControl : true } ) ;
expect ( w . isHiddenInMissionControl ( ) ) . to . be . true ( 'isHiddenInMissionControl' ) ;
} ) ;
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isHiddenInMissionControl ( ) ) . to . be . false ( 'isHiddenInMissionControl' ) ;
w . setHiddenInMissionControl ( true ) ;
expect ( w . isHiddenInMissionControl ( ) ) . to . be . true ( 'isHiddenInMissionControl' ) ;
w . setHiddenInMissionControl ( false ) ;
expect ( w . isHiddenInMissionControl ( ) ) . to . be . false ( 'isHiddenInMissionControl' ) ;
} ) ;
} ) ;
} ) ;
2019-07-16 23:37:17 +00:00
// fullscreen events are dispatched eagerly and twiddling things too fast can confuse poor Electron
ifdescribe ( process . platform === 'darwin' ) ( 'kiosk state' , ( ) = > {
2020-04-01 15:22:32 +00:00
it ( 'with properties' , ( ) = > {
it ( 'can be set with a constructor property' , ( ) = > {
const w = new BrowserWindow ( { kiosk : true } ) ;
expect ( w . kiosk ) . to . be . true ( ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-04-01 15:22:32 +00:00
2020-06-30 22:10:36 +00:00
it ( 'can be changed ' , async ( ) = > {
2020-04-01 15:22:32 +00:00
const w = new BrowserWindow ( ) ;
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2020-04-01 15:22:32 +00:00
w . kiosk = true ;
2020-06-30 22:10:36 +00:00
expect ( w . isKiosk ( ) ) . to . be . true ( 'isKiosk' ) ;
await enterFullScreen ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2020-06-30 22:10:36 +00:00
w . kiosk = false ;
expect ( w . isKiosk ( ) ) . to . be . false ( 'isKiosk' ) ;
await leaveFullScreen ;
2020-04-01 15:22:32 +00:00
} ) ;
} ) ;
it ( 'with functions' , ( ) = > {
it ( 'can be set with a constructor property' , ( ) = > {
const w = new BrowserWindow ( { kiosk : true } ) ;
expect ( w . isKiosk ( ) ) . to . be . true ( ) ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'can be changed ' , async ( ) = > {
2020-04-01 15:22:32 +00:00
const w = new BrowserWindow ( ) ;
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2020-04-01 15:22:32 +00:00
w . setKiosk ( true ) ;
expect ( w . isKiosk ( ) ) . to . be . true ( 'isKiosk' ) ;
2020-06-30 22:10:36 +00:00
await enterFullScreen ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2020-06-30 22:10:36 +00:00
w . setKiosk ( false ) ;
expect ( w . isKiosk ( ) ) . to . be . false ( 'isKiosk' ) ;
await leaveFullScreen ;
2019-07-16 23:37:17 +00:00
} ) ;
} ) ;
} ) ;
ifdescribe ( process . platform === 'darwin' ) ( 'fullscreen state with resizable set' , ( ) = > {
2022-06-03 07:47:19 +00:00
it ( 'resizable flag should be set to false and restored' , async ( ) = > {
2019-07-16 23:37:17 +00:00
const w = new BrowserWindow ( { resizable : false } ) ;
2022-06-03 07:47:19 +00:00
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2019-07-16 23:37:17 +00:00
w . setFullScreen ( true ) ;
2020-06-30 22:10:36 +00:00
await enterFullScreen ;
2022-06-03 07:47:19 +00:00
expect ( w . resizable ) . to . be . false ( 'resizable' ) ;
2020-06-30 22:10:36 +00:00
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2020-06-30 22:10:36 +00:00
w . setFullScreen ( false ) ;
await leaveFullScreen ;
expect ( w . resizable ) . to . be . false ( 'resizable' ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2022-06-03 07:47:19 +00:00
it ( 'default resizable flag should be restored after entering/exiting fullscreen' , async ( ) = > {
const w = new BrowserWindow ( ) ;
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2022-06-03 07:47:19 +00:00
w . setFullScreen ( true ) ;
await enterFullScreen ;
expect ( w . resizable ) . to . be . false ( 'resizable' ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2022-06-03 07:47:19 +00:00
w . setFullScreen ( false ) ;
await leaveFullScreen ;
expect ( w . resizable ) . to . be . true ( 'resizable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
ifdescribe ( process . platform === 'darwin' ) ( 'fullscreen state' , ( ) = > {
2020-09-17 23:40:07 +00:00
it ( 'should not cause a crash if called when exiting fullscreen' , async ( ) = > {
const w = new BrowserWindow ( ) ;
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2020-09-17 23:40:07 +00:00
w . setFullScreen ( true ) ;
await enterFullScreen ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2020-09-17 23:40:07 +00:00
2023-02-23 23:53:53 +00:00
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2020-09-17 23:40:07 +00:00
w . setFullScreen ( false ) ;
await leaveFullScreen ;
} ) ;
2022-08-01 20:52:58 +00:00
it ( 'should be able to load a URL while transitioning to fullscreen' , async ( ) = > {
const w = new BrowserWindow ( { fullscreen : true } ) ;
w . loadFile ( path . join ( fixtures , 'pages' , 'c.html' ) ) ;
2023-02-23 23:53:53 +00:00
const load = once ( w . webContents , 'did-finish-load' ) ;
const enterFS = once ( w , 'enter-full-screen' ) ;
2022-08-01 20:52:58 +00:00
await Promise . all ( [ enterFS , load ] ) ;
expect ( w . fullScreen ) . to . be . true ( ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2022-08-01 20:52:58 +00:00
2023-02-23 23:53:53 +00:00
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2022-08-01 20:52:58 +00:00
w . setFullScreen ( false ) ;
await leaveFullScreen ;
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'can be changed with setFullScreen method' , async ( ) = > {
2019-07-16 23:37:17 +00:00
const w = new BrowserWindow ( ) ;
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2019-07-16 23:37:17 +00:00
w . setFullScreen ( true ) ;
2020-06-30 22:10:36 +00:00
await enterFullScreen ;
expect ( w . isFullScreen ( ) ) . to . be . true ( 'isFullScreen' ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2020-06-30 22:10:36 +00:00
w . setFullScreen ( false ) ;
await leaveFullScreen ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'isFullScreen' ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2021-04-21 14:56:25 +00:00
it ( 'handles several transitions starting with fullscreen' , async ( ) = > {
const w = new BrowserWindow ( { fullscreen : true , show : true } ) ;
expect ( w . isFullScreen ( ) ) . to . be . true ( 'not fullscreen' ) ;
w . setFullScreen ( false ) ;
w . setFullScreen ( true ) ;
const enterFullScreen = emittedNTimes ( w , 'enter-full-screen' , 2 ) ;
await enterFullScreen ;
expect ( w . isFullScreen ( ) ) . to . be . true ( 'not fullscreen' ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2021-04-21 14:56:25 +00:00
w . setFullScreen ( false ) ;
await leaveFullScreen ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'is fullscreen' ) ;
} ) ;
2022-06-07 16:59:50 +00:00
it ( 'handles several HTML fullscreen transitions' , async ( ) = > {
const w = new BrowserWindow ( ) ;
await w . loadFile ( path . join ( fixtures , 'pages' , 'a.html' ) ) ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'is fullscreen' ) ;
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
2022-06-07 16:59:50 +00:00
await w . webContents . executeJavaScript ( 'document.getElementById("div").requestFullscreen()' , true ) ;
await enterFullScreen ;
await w . webContents . executeJavaScript ( 'document.exitFullscreen()' , true ) ;
await leaveFullScreen ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'is fullscreen' ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( ) ;
2022-06-07 16:59:50 +00:00
await w . webContents . executeJavaScript ( 'document.getElementById("div").requestFullscreen()' , true ) ;
await enterFullScreen ;
await w . webContents . executeJavaScript ( 'document.exitFullscreen()' , true ) ;
await leaveFullScreen ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'is fullscreen' ) ;
} ) ;
2021-04-21 14:56:25 +00:00
it ( 'handles several transitions in close proximity' , async ( ) = > {
const w = new BrowserWindow ( ) ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'is fullscreen' ) ;
2022-06-07 16:59:50 +00:00
const enterFS = emittedNTimes ( w , 'enter-full-screen' , 2 ) ;
const leaveFS = emittedNTimes ( w , 'leave-full-screen' , 2 ) ;
2021-04-21 14:56:25 +00:00
w . setFullScreen ( true ) ;
w . setFullScreen ( false ) ;
w . setFullScreen ( true ) ;
2022-06-07 16:59:50 +00:00
w . setFullScreen ( false ) ;
2021-04-21 14:56:25 +00:00
2022-06-07 16:59:50 +00:00
await Promise . all ( [ enterFS , leaveFS ] ) ;
2021-04-21 14:56:25 +00:00
2022-06-07 16:59:50 +00:00
expect ( w . isFullScreen ( ) ) . to . be . false ( 'not fullscreen' ) ;
} ) ;
it ( 'handles several chromium-initiated transitions in close proximity' , async ( ) = > {
const w = new BrowserWindow ( ) ;
await w . loadFile ( path . join ( fixtures , 'pages' , 'a.html' ) ) ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'is fullscreen' ) ;
let enterCount = 0 ;
let exitCount = 0 ;
const done = new Promise < void > ( resolve = > {
const checkDone = ( ) = > {
if ( enterCount === 2 && exitCount === 2 ) resolve ( ) ;
} ;
w . webContents . on ( 'enter-html-full-screen' , ( ) = > {
enterCount ++ ;
checkDone ( ) ;
} ) ;
w . webContents . on ( 'leave-html-full-screen' , ( ) = > {
exitCount ++ ;
checkDone ( ) ;
} ) ;
} ) ;
await w . webContents . executeJavaScript ( 'document.getElementById("div").requestFullscreen()' , true ) ;
await w . webContents . executeJavaScript ( 'document.exitFullscreen()' ) ;
await w . webContents . executeJavaScript ( 'document.getElementById("div").requestFullscreen()' , true ) ;
await w . webContents . executeJavaScript ( 'document.exitFullscreen()' ) ;
await done ;
2021-04-21 14:56:25 +00:00
} ) ;
2023-02-21 11:11:34 +00:00
it ( 'handles HTML fullscreen transitions when fullscreenable is false' , async ( ) = > {
const w = new BrowserWindow ( { fullscreenable : false } ) ;
await w . loadFile ( path . join ( fixtures , 'pages' , 'a.html' ) ) ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'is fullscreen' ) ;
let enterCount = 0 ;
let exitCount = 0 ;
const done = new Promise < void > ( ( resolve , reject ) = > {
const checkDone = ( ) = > {
if ( enterCount === 2 && exitCount === 2 ) resolve ( ) ;
} ;
w . webContents . on ( 'enter-html-full-screen' , async ( ) = > {
enterCount ++ ;
if ( w . isFullScreen ( ) ) reject ( new Error ( 'w.isFullScreen should be false' ) ) ;
const isFS = await w . webContents . executeJavaScript ( '!!document.fullscreenElement' ) ;
if ( ! isFS ) reject ( new Error ( 'Document should have fullscreen element' ) ) ;
checkDone ( ) ;
} ) ;
w . webContents . on ( 'leave-html-full-screen' , ( ) = > {
exitCount ++ ;
if ( w . isFullScreen ( ) ) reject ( new Error ( 'w.isFullScreen should be false' ) ) ;
checkDone ( ) ;
} ) ;
} ) ;
await w . webContents . executeJavaScript ( 'document.getElementById("div").requestFullscreen()' , true ) ;
await w . webContents . executeJavaScript ( 'document.exitFullscreen()' ) ;
await w . webContents . executeJavaScript ( 'document.getElementById("div").requestFullscreen()' , true ) ;
await w . webContents . executeJavaScript ( 'document.exitFullscreen()' ) ;
await expect ( done ) . to . eventually . be . fulfilled ( ) ;
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'does not crash when exiting simpleFullScreen (properties)' , async ( ) = > {
2019-09-12 17:38:16 +00:00
const w = new BrowserWindow ( ) ;
w . setSimpleFullScreen ( true ) ;
2023-02-23 23:53:53 +00:00
await setTimeout ( 1000 ) ;
2020-07-01 19:14:38 +00:00
w . setFullScreen ( ! w . isFullScreen ( ) ) ;
2019-09-12 17:38:16 +00:00
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'does not crash when exiting simpleFullScreen (functions)' , async ( ) = > {
2020-04-01 15:22:32 +00:00
const w = new BrowserWindow ( ) ;
w . simpleFullScreen = true ;
2023-02-23 23:53:53 +00:00
await setTimeout ( 1000 ) ;
2020-07-01 19:14:38 +00:00
w . setFullScreen ( ! w . isFullScreen ( ) ) ;
2020-04-01 15:22:32 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'should not be changed by setKiosk method' , async ( ) = > {
2019-07-16 23:37:17 +00:00
const w = new BrowserWindow ( ) ;
2023-05-09 16:28:37 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
w . setKiosk ( true ) ;
await enterFullScreen ;
expect ( w . isFullScreen ( ) ) . to . be . true ( 'isFullScreen' ) ;
const leaveFullScreen = once ( w , 'leave-full-screen' ) ;
w . setKiosk ( false ) ;
await leaveFullScreen ;
expect ( w . isFullScreen ( ) ) . to . be . false ( 'isFullScreen' ) ;
} ) ;
it ( 'should stay fullscreen if fullscreen before kiosk' , async ( ) = > {
const w = new BrowserWindow ( ) ;
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2019-07-16 23:37:17 +00:00
w . setFullScreen ( true ) ;
2020-06-30 22:10:36 +00:00
await enterFullScreen ;
expect ( w . isFullScreen ( ) ) . to . be . true ( 'isFullScreen' ) ;
2023-05-09 16:28:37 +00:00
2020-06-30 22:10:36 +00:00
w . setKiosk ( true ) ;
2023-05-09 16:28:37 +00:00
2020-06-30 22:10:36 +00:00
w . setKiosk ( false ) ;
2023-05-09 16:28:37 +00:00
// Wait enough time for a fullscreen change to take effect.
await setTimeout ( 2000 ) ;
2020-06-30 22:10:36 +00:00
expect ( w . isFullScreen ( ) ) . to . be . true ( 'isFullScreen' ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2021-07-09 20:38:25 +00:00
2023-04-26 08:13:36 +00:00
it ( 'multiple windows inherit correct fullscreen state' , async ( ) = > {
2021-07-09 20:38:25 +00:00
const w = new BrowserWindow ( ) ;
2023-02-23 23:53:53 +00:00
const enterFullScreen = once ( w , 'enter-full-screen' ) ;
2021-07-09 20:38:25 +00:00
w . setFullScreen ( true ) ;
await enterFullScreen ;
expect ( w . isFullScreen ( ) ) . to . be . true ( 'isFullScreen' ) ;
2023-04-26 08:13:36 +00:00
await setTimeout ( 1000 ) ;
2021-07-12 06:19:30 +00:00
const w2 = new BrowserWindow ( { show : false } ) ;
2023-02-23 23:53:53 +00:00
const enterFullScreen2 = once ( w2 , 'enter-full-screen' ) ;
2021-07-12 06:19:30 +00:00
w2 . show ( ) ;
await enterFullScreen2 ;
2021-07-09 20:38:25 +00:00
expect ( w2 . isFullScreen ( ) ) . to . be . true ( 'isFullScreen' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-03-16 21:03:35 +00:00
describe ( 'closable state' , ( ) = > {
it ( 'with properties' , ( ) = > {
it ( 'can be set with closable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , closable : false } ) ;
expect ( w . closable ) . to . be . false ( 'closable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . closable ) . to . be . true ( 'closable' ) ;
w . closable = false ;
expect ( w . closable ) . to . be . false ( 'closable' ) ;
w . closable = true ;
expect ( w . closable ) . to . be . true ( 'closable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-03-16 21:03:35 +00:00
it ( 'with functions' , ( ) = > {
it ( 'can be set with closable constructor option' , ( ) = > {
const w = new BrowserWindow ( { show : false , closable : false } ) ;
expect ( w . isClosable ( ) ) . to . be . false ( 'isClosable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
2020-03-16 21:03:35 +00:00
it ( 'can be changed' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . isClosable ( ) ) . to . be . true ( 'isClosable' ) ;
w . setClosable ( false ) ;
expect ( w . isClosable ( ) ) . to . be . false ( 'isClosable' ) ;
w . setClosable ( true ) ;
expect ( w . isClosable ( ) ) . to . be . true ( 'isClosable' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
} ) ;
describe ( 'hasShadow state' , ( ) = > {
2020-04-01 15:22:32 +00:00
it ( 'with properties' , ( ) = > {
it ( 'returns a boolean on all platforms' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
expect ( w . shadow ) . to . be . a ( 'boolean' ) ;
} ) ;
// On Windows there's no shadow by default & it can't be changed dynamically.
it ( 'can be changed with hasShadow option' , ( ) = > {
const hasShadow = process . platform !== 'darwin' ;
const w = new BrowserWindow ( { show : false , hasShadow } ) ;
expect ( w . shadow ) . to . equal ( hasShadow ) ;
} ) ;
2019-08-08 22:49:43 +00:00
2020-04-01 15:22:32 +00:00
it ( 'can be changed with setHasShadow method' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . shadow = false ;
expect ( w . shadow ) . to . be . false ( 'hasShadow' ) ;
w . shadow = true ;
expect ( w . shadow ) . to . be . true ( 'hasShadow' ) ;
w . shadow = false ;
expect ( w . shadow ) . to . be . false ( 'hasShadow' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
2020-04-01 15:22:32 +00:00
describe ( 'with functions' , ( ) = > {
it ( 'returns a boolean on all platforms' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
const hasShadow = w . hasShadow ( ) ;
expect ( hasShadow ) . to . be . a ( 'boolean' ) ;
} ) ;
// On Windows there's no shadow by default & it can't be changed dynamically.
it ( 'can be changed with hasShadow option' , ( ) = > {
const hasShadow = process . platform !== 'darwin' ;
const w = new BrowserWindow ( { show : false , hasShadow } ) ;
expect ( w . hasShadow ( ) ) . to . equal ( hasShadow ) ;
} ) ;
it ( 'can be changed with setHasShadow method' , ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . setHasShadow ( false ) ;
expect ( w . hasShadow ( ) ) . to . be . false ( 'hasShadow' ) ;
w . setHasShadow ( true ) ;
expect ( w . hasShadow ( ) ) . to . be . true ( 'hasShadow' ) ;
w . setHasShadow ( false ) ;
expect ( w . hasShadow ( ) ) . to . be . false ( 'hasShadow' ) ;
} ) ;
2019-07-16 23:37:17 +00:00
} ) ;
} ) ;
} ) ;
2019-08-15 06:51:15 +00:00
describe ( 'window.getMediaSourceId()' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'returns valid source id' , async ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2023-02-23 23:53:53 +00:00
const shown = once ( w , 'show' ) ;
2019-08-15 06:51:15 +00:00
w . show ( ) ;
await shown ;
// Check format 'window:1234:0'.
const sourceId = w . getMediaSourceId ( ) ;
expect ( sourceId ) . to . match ( /^window:\d+:\d+$/ ) ;
} ) ;
} ) ;
2019-07-26 14:09:33 +00:00
ifdescribe ( ! process . env . ELECTRON_SKIP_NATIVE_MODULE_TESTS ) ( 'window.getNativeWindowHandle()' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'returns valid handle' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2023-09-25 10:43:57 +00:00
const isValidWindow = require ( '@electron-ci/is-valid-window' ) ;
2019-07-26 14:09:33 +00:00
expect ( isValidWindow ( w . getNativeWindowHandle ( ) ) ) . to . be . true ( 'is valid window' ) ;
} ) ;
} ) ;
ifdescribe ( process . platform === 'darwin' ) ( 'previewFile' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'opens the path in Quick Look on macOS' , ( ) = > {
2019-11-01 20:37:02 +00:00
const w = new BrowserWindow ( { show : false } ) ;
2019-07-26 14:09:33 +00:00
expect ( ( ) = > {
w . previewFile ( __filename ) ;
w . closeFilePreview ( ) ;
} ) . to . not . throw ( ) ;
} ) ;
2023-03-14 13:41:34 +00:00
it ( 'should not call BrowserWindow show event' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
const shown = once ( w , 'show' ) ;
w . show ( ) ;
await shown ;
let showCalled = false ;
w . on ( 'show' , ( ) = > {
showCalled = true ;
} ) ;
w . previewFile ( __filename ) ;
await setTimeout ( 500 ) ;
expect ( showCalled ) . to . equal ( false , 'should not have called show twice' ) ;
} ) ;
2019-07-26 14:09:33 +00:00
} ) ;
2022-08-06 23:02:04 +00:00
// TODO (jkleinsc) renable these tests on mas arm64
ifdescribe ( ! process . mas || process . arch !== 'arm64' ) ( 'contextIsolation option with and without sandbox option' , ( ) = > {
2019-07-26 14:09:33 +00:00
const expectedContextData = {
preloadContext : {
preloadProperty : 'number' ,
pageProperty : 'undefined' ,
typeofRequire : 'function' ,
typeofProcess : 'object' ,
typeofArrayPush : 'function' ,
typeofFunctionApply : 'function' ,
typeofPreloadExecuteJavaScriptProperty : 'undefined'
} ,
pageContext : {
preloadProperty : 'undefined' ,
pageProperty : 'string' ,
typeofRequire : 'undefined' ,
typeofProcess : 'undefined' ,
typeofArrayPush : 'number' ,
typeofFunctionApply : 'boolean' ,
typeofPreloadExecuteJavaScriptProperty : 'number' ,
typeofOpenedWindow : 'object'
}
} ;
afterEach ( closeAllWindows ) ;
it ( 'separates the page context from the Electron/preload context' , async ( ) = > {
const iw = new BrowserWindow ( {
show : false ,
webPreferences : {
contextIsolation : true ,
preload : path.join ( fixtures , 'api' , 'isolated-preload.js' )
}
} ) ;
2023-02-23 23:53:53 +00:00
const p = once ( ipcMain , 'isolated-world' ) ;
2019-07-26 14:09:33 +00:00
iw . loadFile ( path . join ( fixtures , 'api' , 'isolated.html' ) ) ;
const [ , data ] = await p ;
expect ( data ) . to . deep . equal ( expectedContextData ) ;
} ) ;
it ( 'recreates the contexts on reload' , async ( ) = > {
const iw = new BrowserWindow ( {
show : false ,
webPreferences : {
contextIsolation : true ,
preload : path.join ( fixtures , 'api' , 'isolated-preload.js' )
}
} ) ;
await iw . loadFile ( path . join ( fixtures , 'api' , 'isolated.html' ) ) ;
2023-02-23 23:53:53 +00:00
const isolatedWorld = once ( ipcMain , 'isolated-world' ) ;
2019-07-26 14:09:33 +00:00
iw . webContents . reload ( ) ;
const [ , data ] = await isolatedWorld ;
expect ( data ) . to . deep . equal ( expectedContextData ) ;
} ) ;
it ( 'enables context isolation on child windows' , async ( ) = > {
const iw = new BrowserWindow ( {
show : false ,
webPreferences : {
contextIsolation : true ,
preload : path.join ( fixtures , 'api' , 'isolated-preload.js' )
}
} ) ;
2023-06-22 18:38:52 +00:00
const browserWindowCreated = once ( app , 'browser-window-created' ) as Promise < [ any , BrowserWindow ] > ;
2019-07-26 14:09:33 +00:00
iw . loadFile ( path . join ( fixtures , 'pages' , 'window-open.html' ) ) ;
const [ , window ] = await browserWindowCreated ;
2023-06-22 18:38:52 +00:00
expect ( window . webContents . getLastWebPreferences ( ) ! . contextIsolation ) . to . be . true ( 'contextIsolation' ) ;
2019-07-26 14:09:33 +00:00
} ) ;
it ( 'separates the page context from the Electron/preload context with sandbox on' , async ( ) = > {
const ws = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true ,
contextIsolation : true ,
preload : path.join ( fixtures , 'api' , 'isolated-preload.js' )
}
} ) ;
2023-02-23 23:53:53 +00:00
const p = once ( ipcMain , 'isolated-world' ) ;
2019-07-26 14:09:33 +00:00
ws . loadFile ( path . join ( fixtures , 'api' , 'isolated.html' ) ) ;
const [ , data ] = await p ;
expect ( data ) . to . deep . equal ( expectedContextData ) ;
} ) ;
it ( 'recreates the contexts on reload with sandbox on' , async ( ) = > {
const ws = new BrowserWindow ( {
show : false ,
webPreferences : {
sandbox : true ,
contextIsolation : true ,
preload : path.join ( fixtures , 'api' , 'isolated-preload.js' )
}
} ) ;
await ws . loadFile ( path . join ( fixtures , 'api' , 'isolated.html' ) ) ;
2023-02-23 23:53:53 +00:00
const isolatedWorld = once ( ipcMain , 'isolated-world' ) ;
2019-07-26 14:09:33 +00:00
ws . webContents . reload ( ) ;
const [ , data ] = await isolatedWorld ;
expect ( data ) . to . deep . equal ( expectedContextData ) ;
} ) ;
it ( 'supports fetch api' , async ( ) = > {
const fetchWindow = new BrowserWindow ( {
show : false ,
webPreferences : {
contextIsolation : true ,
preload : path.join ( fixtures , 'api' , 'isolated-fetch-preload.js' )
}
} ) ;
2023-02-23 23:53:53 +00:00
const p = once ( ipcMain , 'isolated-fetch-error' ) ;
2019-07-26 14:09:33 +00:00
fetchWindow . loadURL ( 'about:blank' ) ;
const [ , error ] = await p ;
expect ( error ) . to . equal ( 'Failed to fetch' ) ;
} ) ;
it ( 'doesn\'t break ipc serialization' , async ( ) = > {
const iw = new BrowserWindow ( {
show : false ,
webPreferences : {
contextIsolation : true ,
preload : path.join ( fixtures , 'api' , 'isolated-preload.js' )
}
} ) ;
2023-02-23 23:53:53 +00:00
const p = once ( ipcMain , 'isolated-world' ) ;
2019-07-26 14:09:33 +00:00
iw . loadURL ( 'about:blank' ) ;
iw . webContents . executeJavaScript ( `
const opened = window . open ( )
openedLocation = opened . location . href
opened . close ( )
window . postMessage ( { openedLocation } , '*' )
` );
const [ , data ] = await p ;
2020-05-27 20:50:54 +00:00
expect ( data . pageContext . openedLocation ) . to . equal ( 'about:blank' ) ;
2019-07-26 14:09:33 +00:00
} ) ;
2021-03-18 21:00:19 +00:00
it ( 'reports process.contextIsolated' , async ( ) = > {
2021-03-17 18:23:29 +00:00
const iw = new BrowserWindow ( {
show : false ,
webPreferences : {
contextIsolation : true ,
preload : path.join ( fixtures , 'api' , 'isolated-process.js' )
}
} ) ;
2023-02-23 23:53:53 +00:00
const p = once ( ipcMain , 'context-isolation' ) ;
2021-03-17 18:23:29 +00:00
iw . loadURL ( 'about:blank' ) ;
const [ , contextIsolation ] = await p ;
expect ( contextIsolation ) . to . be . true ( 'contextIsolation' ) ;
} ) ;
2019-07-26 14:09:33 +00:00
} ) ;
2021-04-21 20:59:11 +00:00
it ( 'reloading does not cause Node.js module API hangs after reload' , ( done ) = > {
const w = new BrowserWindow ( {
show : false ,
webPreferences : {
nodeIntegration : true ,
contextIsolation : false
}
} ) ;
2020-10-13 16:19:44 +00:00
2021-04-21 20:59:11 +00:00
let count = 0 ;
ipcMain . on ( 'async-node-api-done' , ( ) = > {
if ( count === 3 ) {
ipcMain . removeAllListeners ( 'async-node-api-done' ) ;
done ( ) ;
} else {
count ++ ;
w . reload ( ) ;
}
2020-10-13 16:19:44 +00:00
} ) ;
2021-04-21 20:59:11 +00:00
w . loadFile ( path . join ( fixtures , 'pages' , 'send-after-node.html' ) ) ;
2020-10-13 16:19:44 +00:00
} ) ;
2020-03-02 07:51:02 +00:00
describe ( 'window.webContents.focus()' , ( ) = > {
afterEach ( closeAllWindows ) ;
2020-06-30 22:10:36 +00:00
it ( 'focuses window' , async ( ) = > {
2020-03-02 07:51:02 +00:00
const w1 = new BrowserWindow ( { x : 100 , y : 300 , width : 300 , height : 200 } ) ;
w1 . loadURL ( 'about:blank' ) ;
const w2 = new BrowserWindow ( { x : 300 , y : 300 , width : 300 , height : 200 } ) ;
w2 . loadURL ( 'about:blank' ) ;
2023-02-23 23:53:53 +00:00
const w1Focused = once ( w1 , 'focus' ) ;
2020-03-02 07:51:02 +00:00
w1 . webContents . focus ( ) ;
2021-11-24 08:45:59 +00:00
await w1Focused ;
2020-06-30 22:10:36 +00:00
expect ( w1 . webContents . isFocused ( ) ) . to . be . true ( 'focuses window' ) ;
2020-03-02 07:51:02 +00:00
} ) ;
} ) ;
2023-06-13 18:48:53 +00:00
describe ( 'offscreen rendering' , ( ) = > {
2019-07-26 14:09:33 +00:00
let w : BrowserWindow ;
beforeEach ( function ( ) {
w = new BrowserWindow ( {
width : 100 ,
height : 100 ,
show : false ,
webPreferences : {
backgroundThrottling : false ,
offscreen : true
}
} ) ;
} ) ;
afterEach ( closeAllWindows ) ;
2020-06-30 22:10:36 +00:00
it ( 'creates offscreen window with correct size' , async ( ) = > {
2023-06-22 18:38:52 +00:00
const paint = once ( w . webContents , 'paint' ) as Promise < [ any , Electron . Rectangle , Electron . NativeImage ] > ;
2019-07-26 14:09:33 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'offscreen-rendering.html' ) ) ;
2020-06-30 22:10:36 +00:00
const [ , , data ] = await paint ;
expect ( data . constructor . name ) . to . equal ( 'NativeImage' ) ;
expect ( data . isEmpty ( ) ) . to . be . false ( 'data is empty' ) ;
const size = data . getSize ( ) ;
const { scaleFactor } = screen . getPrimaryDisplay ( ) ;
expect ( size . width ) . to . be . closeTo ( 100 * scaleFactor , 2 ) ;
expect ( size . height ) . to . be . closeTo ( 100 * scaleFactor , 2 ) ;
2019-07-26 14:09:33 +00:00
} ) ;
it ( 'does not crash after navigation' , ( ) = > {
w . webContents . loadURL ( 'about:blank' ) ;
w . loadFile ( path . join ( fixtures , 'api' , 'offscreen-rendering.html' ) ) ;
} ) ;
describe ( 'window.webContents.isOffscreen()' , ( ) = > {
it ( 'is true for offscreen type' , ( ) = > {
w . loadFile ( path . join ( fixtures , 'api' , 'offscreen-rendering.html' ) ) ;
expect ( w . webContents . isOffscreen ( ) ) . to . be . true ( 'isOffscreen' ) ;
} ) ;
it ( 'is false for regular window' , ( ) = > {
const c = new BrowserWindow ( { show : false } ) ;
expect ( c . webContents . isOffscreen ( ) ) . to . be . false ( 'isOffscreen' ) ;
c . destroy ( ) ;
} ) ;
} ) ;
describe ( 'window.webContents.isPainting()' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'returns whether is currently painting' , async ( ) = > {
2023-06-22 18:38:52 +00:00
const paint = once ( w . webContents , 'paint' ) as Promise < [ any , Electron . Rectangle , Electron . NativeImage ] > ;
2019-07-26 14:09:33 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'offscreen-rendering.html' ) ) ;
2020-06-30 22:10:36 +00:00
await paint ;
expect ( w . webContents . isPainting ( ) ) . to . be . true ( 'isPainting' ) ;
2019-07-26 14:09:33 +00:00
} ) ;
} ) ;
describe ( 'window.webContents.stopPainting()' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'stops painting' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const domReady = once ( w . webContents , 'dom-ready' ) ;
2019-07-26 14:09:33 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'offscreen-rendering.html' ) ) ;
2020-06-30 22:10:36 +00:00
await domReady ;
w . webContents . stopPainting ( ) ;
expect ( w . webContents . isPainting ( ) ) . to . be . false ( 'isPainting' ) ;
2019-07-26 14:09:33 +00:00
} ) ;
} ) ;
describe ( 'window.webContents.startPainting()' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'starts painting' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const domReady = once ( w . webContents , 'dom-ready' ) ;
2019-07-26 14:09:33 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'offscreen-rendering.html' ) ) ;
2020-06-30 22:10:36 +00:00
await domReady ;
w . webContents . stopPainting ( ) ;
w . webContents . startPainting ( ) ;
2023-06-22 18:38:52 +00:00
await once ( w . webContents , 'paint' ) as [ any , Electron . Rectangle , Electron . NativeImage ] ;
2020-06-30 22:10:36 +00:00
expect ( w . webContents . isPainting ( ) ) . to . be . true ( 'isPainting' ) ;
2019-07-26 14:09:33 +00:00
} ) ;
} ) ;
2020-03-13 17:16:08 +00:00
describe ( 'frameRate APIs' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'has default frame rate (function)' , async ( ) = > {
2019-07-26 14:09:33 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'offscreen-rendering.html' ) ) ;
2023-06-22 18:38:52 +00:00
await once ( w . webContents , 'paint' ) as [ any , Electron . Rectangle , Electron . NativeImage ] ;
2020-06-30 22:10:36 +00:00
expect ( w . webContents . getFrameRate ( ) ) . to . equal ( 60 ) ;
2019-07-26 14:09:33 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'has default frame rate (property)' , async ( ) = > {
2020-03-13 17:16:08 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'offscreen-rendering.html' ) ) ;
2023-06-22 18:38:52 +00:00
await once ( w . webContents , 'paint' ) as [ any , Electron . Rectangle , Electron . NativeImage ] ;
2020-06-30 22:10:36 +00:00
expect ( w . webContents . frameRate ) . to . equal ( 60 ) ;
2020-03-13 17:16:08 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'sets custom frame rate (function)' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const domReady = once ( w . webContents , 'dom-ready' ) ;
2019-07-26 14:09:33 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'offscreen-rendering.html' ) ) ;
2020-06-30 22:10:36 +00:00
await domReady ;
w . webContents . setFrameRate ( 30 ) ;
2023-06-22 18:38:52 +00:00
await once ( w . webContents , 'paint' ) as [ any , Electron . Rectangle , Electron . NativeImage ] ;
2020-06-30 22:10:36 +00:00
expect ( w . webContents . getFrameRate ( ) ) . to . equal ( 30 ) ;
2019-07-26 14:09:33 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'sets custom frame rate (property)' , async ( ) = > {
2023-02-23 23:53:53 +00:00
const domReady = once ( w . webContents , 'dom-ready' ) ;
2019-07-26 14:09:33 +00:00
w . loadFile ( path . join ( fixtures , 'api' , 'offscreen-rendering.html' ) ) ;
2020-06-30 22:10:36 +00:00
await domReady ;
w . webContents . frameRate = 30 ;
2023-06-22 18:38:52 +00:00
await once ( w . webContents , 'paint' ) as [ any , Electron . Rectangle , Electron . NativeImage ] ;
2020-06-30 22:10:36 +00:00
expect ( w . webContents . frameRate ) . to . equal ( 30 ) ;
2019-07-26 14:09:33 +00:00
} ) ;
} ) ;
} ) ;
2021-09-07 08:18:43 +00:00
describe ( '"transparent" option' , ( ) = > {
afterEach ( closeAllWindows ) ;
2023-05-17 08:17:08 +00:00
ifit ( process . platform !== 'linux' ) ( 'correctly returns isMaximized() when the window is maximized then minimized' , async ( ) = > {
const w = new BrowserWindow ( {
frame : false ,
transparent : true
} ) ;
const maximize = once ( w , 'maximize' ) ;
w . maximize ( ) ;
await maximize ;
const minimize = once ( w , 'minimize' ) ;
w . minimize ( ) ;
await minimize ;
expect ( w . isMaximized ( ) ) . to . be . false ( ) ;
expect ( w . isMinimized ( ) ) . to . be . true ( ) ;
} ) ;
2021-09-07 08:18:43 +00:00
// Only applicable on Windows where transparent windows can't be maximized.
ifit ( process . platform === 'win32' ) ( 'can show maximized frameless window' , async ( ) = > {
const display = screen . getPrimaryDisplay ( ) ;
const w = new BrowserWindow ( {
. . . display . bounds ,
frame : false ,
transparent : true ,
show : true
} ) ;
w . loadURL ( 'about:blank' ) ;
2023-02-23 23:53:53 +00:00
await once ( w , 'ready-to-show' ) ;
2021-09-07 08:18:43 +00:00
expect ( w . isMaximized ( ) ) . to . be . true ( ) ;
// Fails when the transparent HWND is in an invalid maximized state.
expect ( w . getBounds ( ) ) . to . deep . equal ( display . workArea ) ;
const newBounds = { width : 256 , height : 256 , x : 0 , y : 0 } ;
w . setBounds ( newBounds ) ;
expect ( w . getBounds ( ) ) . to . deep . equal ( newBounds ) ;
} ) ;
2022-03-01 22:14:11 +00:00
2024-03-13 14:05:10 +00:00
// FIXME(codebytere): figure out why these are failing on macOS arm64.
ifit ( process . platform === 'darwin' && process . arch !== 'arm64' ) ( 'should not display a visible background' , async ( ) = > {
2022-03-01 22:14:11 +00:00
const display = screen . getPrimaryDisplay ( ) ;
const backgroundWindow = new BrowserWindow ( {
. . . display . bounds ,
frame : false ,
2022-10-11 17:11:58 +00:00
backgroundColor : HexColors.GREEN ,
2022-03-01 22:14:11 +00:00
hasShadow : false
} ) ;
await backgroundWindow . loadURL ( 'about:blank' ) ;
const foregroundWindow = new BrowserWindow ( {
. . . display . bounds ,
show : true ,
transparent : true ,
frame : false ,
hasShadow : false
} ) ;
2022-10-11 17:11:58 +00:00
const colorFile = path . join ( __dirname , 'fixtures' , 'pages' , 'half-background-color.html' ) ;
await foregroundWindow . loadFile ( colorFile ) ;
2022-03-01 22:14:11 +00:00
2023-02-23 23:53:53 +00:00
await setTimeout ( 1000 ) ;
2022-03-01 22:14:11 +00:00
2024-02-28 03:54:20 +00:00
const screenCapture = await ScreenCapture . createForDisplay ( display ) ;
await screenCapture . expectColorAtPointOnDisplayMatches (
HexColors . GREEN ,
( size ) = > ( {
x : size.width / 4 ,
y : size.height / 2
} )
) ;
await screenCapture . expectColorAtPointOnDisplayMatches (
HexColors . RED ,
( size ) = > ( {
x : size.width * 3 / 4 ,
y : size.height / 2
} )
) ;
2022-10-11 17:11:58 +00:00
} ) ;
2024-03-13 14:05:10 +00:00
// FIXME(codebytere): figure out why these are failing on macOS arm64.
ifit ( process . platform === 'darwin' && process . arch !== 'arm64' ) ( 'Allows setting a transparent window via CSS' , async ( ) = > {
2022-10-11 17:11:58 +00:00
const display = screen . getPrimaryDisplay ( ) ;
const backgroundWindow = new BrowserWindow ( {
. . . display . bounds ,
frame : false ,
backgroundColor : HexColors.PURPLE ,
hasShadow : false
} ) ;
await backgroundWindow . loadURL ( 'about:blank' ) ;
const foregroundWindow = new BrowserWindow ( {
. . . display . bounds ,
frame : false ,
transparent : true ,
hasShadow : false ,
webPreferences : {
contextIsolation : false ,
nodeIntegration : true
}
} ) ;
foregroundWindow . loadFile ( path . join ( __dirname , 'fixtures' , 'pages' , 'css-transparent.html' ) ) ;
2023-02-23 23:53:53 +00:00
await once ( ipcMain , 'set-transparent' ) ;
2022-10-11 17:11:58 +00:00
2023-10-10 15:13:07 +00:00
await setTimeout ( 1000 ) ;
2022-10-11 17:11:58 +00:00
2024-02-28 03:54:20 +00:00
const screenCapture = await ScreenCapture . createForDisplay ( display ) ;
await screenCapture . expectColorAtCenterMatches ( HexColors . PURPLE ) ;
2022-03-01 22:14:11 +00:00
} ) ;
2023-05-02 21:44:34 +00:00
// Linux and arm64 platforms (WOA and macOS) do not return any capture sources
ifit ( process . platform === 'darwin' && process . arch === 'x64' ) ( 'should not make background transparent if falsy' , async ( ) = > {
const display = screen . getPrimaryDisplay ( ) ;
for ( const transparent of [ false , undefined ] ) {
const window = new BrowserWindow ( {
. . . display . bounds ,
transparent
} ) ;
await once ( window , 'show' ) ;
await window . webContents . loadURL ( 'data:text/html,<head><meta name="color-scheme" content="dark"></head>' ) ;
2023-10-10 15:13:07 +00:00
await setTimeout ( 1000 ) ;
2024-02-28 03:54:20 +00:00
const screenCapture = await ScreenCapture . createForDisplay ( display ) ;
2023-05-02 21:44:34 +00:00
// color-scheme is set to dark so background should not be white
2024-02-28 03:54:20 +00:00
await screenCapture . expectColorAtCenterDoesNotMatch ( HexColors . WHITE ) ;
window . close ( ) ;
2023-05-02 21:44:34 +00:00
}
} ) ;
2022-03-01 22:14:11 +00:00
} ) ;
describe ( '"backgroundColor" option' , ( ) = > {
afterEach ( closeAllWindows ) ;
2022-11-21 15:24:26 +00:00
// Linux/WOA doesn't return any capture sources.
ifit ( process . platform === 'darwin' ) ( 'should display the set color' , async ( ) = > {
2022-03-01 22:14:11 +00:00
const display = screen . getPrimaryDisplay ( ) ;
const w = new BrowserWindow ( {
. . . display . bounds ,
show : true ,
2022-10-11 17:11:58 +00:00
backgroundColor : HexColors.BLUE
2022-03-01 22:14:11 +00:00
} ) ;
w . loadURL ( 'about:blank' ) ;
2023-02-23 23:53:53 +00:00
await once ( w , 'ready-to-show' ) ;
2022-03-01 22:14:11 +00:00
2023-10-10 15:13:07 +00:00
await setTimeout ( 1000 ) ;
2022-03-01 22:14:11 +00:00
2024-02-28 03:54:20 +00:00
const screenCapture = await ScreenCapture . createForDisplay ( display ) ;
await screenCapture . expectColorAtCenterMatches ( HexColors . BLUE ) ;
2022-03-01 22:14:11 +00:00
} ) ;
2021-09-07 08:18:43 +00:00
} ) ;
2024-01-31 09:29:17 +00:00
describe ( 'draggable regions' , ( ) = > {
afterEach ( closeAllWindows ) ;
ifit ( hasCapturableScreen ( ) ) ( 'should allow the window to be dragged when enabled' , async ( ) = > {
2024-05-01 01:13:38 +00:00
// FIXME: nut-js has been removed from npm; we need to find a replacement
2024-01-31 09:29:17 +00:00
// WOA fails to load libnut so we're using require to defer loading only
// on supported platforms.
// "@nut-tree\libnut-win32\build\Release\libnut.node is not a valid Win32 application."
2024-01-31 23:04:13 +00:00
// @ts-ignore: nut-js is an optional dependency so it may not be installed
2024-01-31 09:29:17 +00:00
const { mouse , straightTo , centerOf , Region , Button } = require ( '@nut-tree/nut-js' ) as typeof import ( '@nut-tree/nut-js' ) ;
const display = screen . getPrimaryDisplay ( ) ;
const w = new BrowserWindow ( {
x : 0 ,
y : 0 ,
width : display.bounds.width / 2 ,
height : display.bounds.height / 2 ,
frame : false ,
titleBarStyle : 'hidden'
} ) ;
const overlayHTML = path . join ( __dirname , 'fixtures' , 'pages' , 'overlay.html' ) ;
w . loadFile ( overlayHTML ) ;
await once ( w , 'ready-to-show' ) ;
const winBounds = w . getBounds ( ) ;
const titleBarHeight = 30 ;
const titleBarRegion = new Region ( winBounds . x , winBounds . y , winBounds . width , titleBarHeight ) ;
const screenRegion = new Region ( display . bounds . x , display . bounds . y , display . bounds . width , display . bounds . height ) ;
const startPos = w . getPosition ( ) ;
await mouse . setPosition ( await centerOf ( titleBarRegion ) ) ;
await mouse . pressButton ( Button . LEFT ) ;
await mouse . drag ( straightTo ( centerOf ( screenRegion ) ) ) ;
// Wait for move to complete
await Promise . race ( [
once ( w , 'move' ) ,
setTimeout ( 100 ) // fallback for possible race condition
] ) ;
const endPos = w . getPosition ( ) ;
expect ( startPos ) . to . not . deep . equal ( endPos ) ;
} ) ;
2024-02-21 03:10:43 +00:00
ifit ( hasCapturableScreen ( ) ) ( 'should allow the window to be dragged when no WCO and --webkit-app-region: drag enabled' , async ( ) = > {
2024-05-01 01:13:38 +00:00
// FIXME: nut-js has been removed from npm; we need to find a replacement
2024-02-21 03:10:43 +00:00
// @ts-ignore: nut-js is an optional dependency so it may not be installed
const { mouse , straightTo , centerOf , Region , Button } = require ( '@nut-tree/nut-js' ) as typeof import ( '@nut-tree/nut-js' ) ;
const display = screen . getPrimaryDisplay ( ) ;
const w = new BrowserWindow ( {
x : 0 ,
y : 0 ,
width : display.bounds.width / 2 ,
height : display.bounds.height / 2 ,
frame : false
} ) ;
const basePageHTML = path . join ( __dirname , 'fixtures' , 'pages' , 'base-page.html' ) ;
w . loadFile ( basePageHTML ) ;
await once ( w , 'ready-to-show' ) ;
await w . webContents . executeJavaScript ( `
const style = document . createElement ( 'style' ) ;
style . innerHTML = \ `
# titlebar {
background - color : red ;
height : 30px ;
width : 100 % ;
- webkit - user - select : none ;
- webkit - app - region : drag ;
position : fixed ;
top : 0 ;
left : 0 ;
z - index : 1000000000000 ;
}
\ ` ;
const titleBar = document . createElement ( 'title-bar' ) ;
titleBar . id = 'titlebar' ;
titleBar . textContent = 'test-titlebar' ;
document . body . append ( style ) ;
document . body . append ( titleBar ) ;
` );
// allow time for titlebar to finish loading
await setTimeout ( 2000 ) ;
const winBounds = w . getBounds ( ) ;
const titleBarHeight = 30 ;
const titleBarRegion = new Region ( winBounds . x , winBounds . y , winBounds . width , titleBarHeight ) ;
const screenRegion = new Region ( display . bounds . x , display . bounds . y , display . bounds . width , display . bounds . height ) ;
const startPos = w . getPosition ( ) ;
await mouse . setPosition ( await centerOf ( titleBarRegion ) ) ;
await mouse . pressButton ( Button . LEFT ) ;
await mouse . drag ( straightTo ( centerOf ( screenRegion ) ) ) ;
// Wait for move to complete
await Promise . race ( [
once ( w , 'move' ) ,
setTimeout ( 1000 ) // fallback for possible race condition
] ) ;
const endPos = w . getPosition ( ) ;
expect ( startPos ) . to . not . deep . equal ( endPos ) ;
} ) ;
2024-01-31 09:29:17 +00:00
} ) ;
2019-06-03 22:10:58 +00:00
} ) ;