2021-11-04 08:14:09 +00:00
import { assert , expect } from 'chai' ;
2023-06-15 14:42:27 +00:00
import * as cp from 'node:child_process' ;
import * as https from 'node:https' ;
import * as http from 'node:http' ;
import * as net from 'node:net' ;
2022-05-09 14:26:57 +00:00
import * as fs from 'fs-extra' ;
2023-06-15 14:42:27 +00:00
import * as path from 'node:path' ;
import { promisify } from 'node:util' ;
2023-10-08 23:55:16 +00:00
import { app , BrowserWindow , Menu , session , net as electronNet , WebContents , deprecate } from 'electron/main' ;
2023-01-25 21:01:25 +00:00
import { closeWindow , closeAllWindows } from './lib/window-helpers' ;
2023-02-20 11:30:57 +00:00
import { ifdescribe , ifit , listen , waitUntil } from './lib/spec-helpers' ;
2023-06-15 14:42:27 +00:00
import { once } from 'node:events' ;
2019-11-01 20:37:02 +00:00
import split = require ( 'split' )
2019-10-14 20:49:21 +00:00
2022-08-16 19:23:13 +00:00
const fixturesPath = path . resolve ( __dirname , 'fixtures' ) ;
2018-04-20 07:09:23 +00:00
2017-10-27 20:45:58 +00:00
describe ( 'electron module' , ( ) = > {
it ( 'does not expose internal modules to require' , ( ) = > {
2018-06-14 16:44:27 +00:00
expect ( ( ) = > {
2016-03-25 19:57:17 +00:00
require ( 'clipboard' ) ;
2018-06-14 16:44:27 +00:00
} ) . to . throw ( /Cannot find module 'clipboard'/ ) ;
2016-03-25 19:57:17 +00:00
} ) ;
2016-05-23 20:12:02 +00:00
2017-10-27 20:45:58 +00:00
describe ( 'require("electron")' , ( ) = > {
2019-03-10 22:38:44 +00:00
it ( 'always returns the internal electron module' , ( ) = > {
require ( 'electron' ) ;
2016-05-23 20:12:02 +00:00
} ) ;
} ) ;
2016-03-25 19:57:17 +00:00
} ) ;
2017-10-27 20:45:58 +00:00
describe ( 'app module' , ( ) = > {
2019-03-10 22:38:44 +00:00
let server : https.Server ;
let secureUrl : string ;
const certPath = path . join ( fixturesPath , 'certificates' ) ;
2016-12-02 17:34:16 +00:00
2023-02-20 11:30:57 +00:00
before ( async ( ) = > {
2016-12-02 17:34:16 +00:00
const options = {
key : fs.readFileSync ( path . join ( certPath , 'server.key' ) ) ,
cert : fs.readFileSync ( path . join ( certPath , 'server.pem' ) ) ,
ca : [
fs . readFileSync ( path . join ( certPath , 'rootCA.pem' ) ) ,
fs . readFileSync ( path . join ( certPath , 'intermediateCA.pem' ) )
] ,
requestCert : true ,
rejectUnauthorized : false
} ;
2017-10-27 20:45:58 +00:00
server = https . createServer ( options , ( req , res ) = > {
2019-03-10 22:38:44 +00:00
if ( ( req as any ) . client . authorized ) {
2016-12-02 17:34:16 +00:00
res . writeHead ( 200 ) ;
res . end ( '<title>authorized</title>' ) ;
} else {
res . writeHead ( 401 ) ;
res . end ( '<title>denied</title>' ) ;
}
} ) ;
2023-02-20 11:30:57 +00:00
secureUrl = ( await listen ( server ) ) . url ;
2016-12-02 17:34:16 +00:00
} ) ;
2018-06-14 16:44:27 +00:00
after ( done = > {
2018-03-07 05:40:27 +00:00
server . close ( ( ) = > done ( ) ) ;
2016-12-02 17:34:16 +00:00
} ) ;
2017-10-27 20:45:58 +00:00
describe ( 'app.getVersion()' , ( ) = > {
it ( 'returns the version field of package.json' , ( ) = > {
2018-06-14 16:44:27 +00:00
expect ( app . getVersion ( ) ) . to . equal ( '0.1.0' ) ;
2016-03-25 19:57:17 +00:00
} ) ;
} ) ;
2017-10-27 20:45:58 +00:00
describe ( 'app.setVersion(version)' , ( ) = > {
it ( 'overrides the version' , ( ) = > {
2018-06-14 16:44:27 +00:00
expect ( app . getVersion ( ) ) . to . equal ( '0.1.0' ) ;
2016-03-25 19:57:17 +00:00
app . setVersion ( 'test-version' ) ;
2018-06-14 16:44:27 +00:00
expect ( app . getVersion ( ) ) . to . equal ( 'test-version' ) ;
2016-03-25 19:57:17 +00:00
app . setVersion ( '0.1.0' ) ;
} ) ;
} ) ;
2020-03-18 17:06:41 +00:00
describe ( 'app name APIs' , ( ) = > {
it ( 'with properties' , ( ) = > {
it ( 'returns the name field of package.json' , ( ) = > {
expect ( app . name ) . to . equal ( 'Electron Test Main' ) ;
} ) ;
2019-04-30 20:55:33 +00:00
2020-03-18 17:06:41 +00:00
it ( 'overrides the name' , ( ) = > {
expect ( app . name ) . to . equal ( 'Electron Test Main' ) ;
2022-03-30 17:17:34 +00:00
app . name = 'electron-test-name' ;
2019-04-30 20:55:33 +00:00
2022-03-30 17:17:34 +00:00
expect ( app . name ) . to . equal ( 'electron-test-name' ) ;
2020-03-18 17:06:41 +00:00
app . name = 'Electron Test Main' ;
} ) ;
2019-04-30 20:55:33 +00:00
} ) ;
2020-03-18 17:06:41 +00:00
it ( 'with functions' , ( ) = > {
it ( 'returns the name field of package.json' , ( ) = > {
expect ( app . getName ( ) ) . to . equal ( 'Electron Test Main' ) ;
} ) ;
2016-03-25 19:57:17 +00:00
2020-03-18 17:06:41 +00:00
it ( 'overrides the name' , ( ) = > {
expect ( app . getName ( ) ) . to . equal ( 'Electron Test Main' ) ;
2022-03-30 17:17:34 +00:00
app . setName ( 'electron-test-name' ) ;
2018-06-14 16:44:27 +00:00
2022-03-30 17:17:34 +00:00
expect ( app . getName ( ) ) . to . equal ( 'electron-test-name' ) ;
2020-03-18 17:06:41 +00:00
app . setName ( 'Electron Test Main' ) ;
} ) ;
2016-03-25 19:57:17 +00:00
} ) ;
} ) ;
2017-10-27 20:45:58 +00:00
describe ( 'app.getLocale()' , ( ) = > {
it ( 'should not be empty' , ( ) = > {
2019-03-10 22:38:44 +00:00
expect ( app . getLocale ( ) ) . to . not . equal ( '' ) ;
2016-03-25 19:57:17 +00:00
} ) ;
} ) ;
2022-09-23 18:50:46 +00:00
describe ( 'app.getSystemLocale()' , ( ) = > {
it ( 'should not be empty' , ( ) = > {
expect ( app . getSystemLocale ( ) ) . to . not . equal ( '' ) ;
} ) ;
} ) ;
2022-11-09 15:50:43 +00:00
describe ( 'app.getPreferredSystemLanguages()' , ( ) = > {
ifit ( process . platform !== 'linux' ) ( 'should not be empty' , ( ) = > {
expect ( app . getPreferredSystemLanguages ( ) . length ) . to . not . equal ( 0 ) ;
} ) ;
ifit ( process . platform === 'linux' ) ( 'should be empty or contain C entry' , ( ) = > {
const languages = app . getPreferredSystemLanguages ( ) ;
if ( languages . length ) {
expect ( languages ) . to . not . include ( 'C' ) ;
}
} ) ;
} ) ;
2018-11-20 20:33:23 +00:00
describe ( 'app.getLocaleCountryCode()' , ( ) = > {
it ( 'should be empty or have length of two' , ( ) = > {
2021-06-21 05:05:28 +00:00
const localeCountryCode = app . getLocaleCountryCode ( ) ;
expect ( localeCountryCode ) . to . be . a ( 'string' ) ;
expect ( localeCountryCode . length ) . to . be . oneOf ( [ 0 , 2 ] ) ;
2018-11-20 20:33:23 +00:00
} ) ;
} ) ;
2018-05-08 06:15:31 +00:00
describe ( 'app.isPackaged' , ( ) = > {
2022-06-16 07:46:11 +00:00
it ( 'should be false during tests' , ( ) = > {
2019-03-15 00:22:42 +00:00
expect ( app . isPackaged ) . to . equal ( false ) ;
2018-05-08 06:15:31 +00:00
} ) ;
} ) ;
2019-10-30 23:38:21 +00:00
ifdescribe ( process . platform === 'darwin' ) ( 'app.isInApplicationsFolder()' , ( ) = > {
2017-10-27 20:45:58 +00:00
it ( 'should be false during tests' , ( ) = > {
2019-03-10 22:38:44 +00:00
expect ( app . isInApplicationsFolder ( ) ) . to . equal ( false ) ;
2017-08-31 14:37:12 +00:00
} ) ;
} ) ;
2021-04-09 07:09:17 +00:00
describe ( 'app.exit(exitCode)' , ( ) = > {
2019-03-10 22:38:44 +00:00
let appProcess : cp.ChildProcess | null = null ;
2016-03-25 19:57:17 +00:00
2017-10-27 20:45:58 +00:00
afterEach ( ( ) = > {
2019-03-10 22:38:44 +00:00
if ( appProcess ) appProcess . kill ( ) ;
2016-03-25 19:57:17 +00:00
} ) ;
2018-08-26 13:54:51 +00:00
it ( 'emits a process exit event with the code' , async ( ) = > {
2019-03-10 22:38:44 +00:00
const appPath = path . join ( fixturesPath , 'api' , 'quit-app' ) ;
const electronPath = process . execPath ;
2017-10-27 20:45:58 +00:00
let output = '' ;
2018-06-14 16:44:27 +00:00
2019-03-10 22:38:44 +00:00
appProcess = cp . spawn ( electronPath , [ appPath ] ) ;
2019-07-01 18:25:45 +00:00
if ( appProcess && appProcess . stdout ) {
appProcess . stdout . on ( 'data' , data = > { output += data ; } ) ;
}
2023-02-23 23:53:53 +00:00
const [ code ] = await once ( appProcess , 'exit' ) ;
2018-06-14 16:44:27 +00:00
2018-08-26 13:54:51 +00:00
if ( process . platform !== 'win32' ) {
expect ( output ) . to . include ( 'Exit event with code: 123' ) ;
}
expect ( code ) . to . equal ( 123 ) ;
2016-03-25 19:57:17 +00:00
} ) ;
2017-04-06 22:02:32 +00:00
2018-08-26 13:55:50 +00:00
it ( 'closes all windows' , async function ( ) {
2019-03-10 22:38:44 +00:00
const appPath = path . join ( fixturesPath , 'api' , 'exit-closes-all-windows-app' ) ;
const electronPath = process . execPath ;
2018-06-14 16:44:27 +00:00
2019-03-10 22:38:44 +00:00
appProcess = cp . spawn ( electronPath , [ appPath ] ) ;
2023-02-23 23:53:53 +00:00
const [ code , signal ] = await once ( appProcess , 'exit' ) ;
2018-08-26 13:54:51 +00:00
expect ( signal ) . to . equal ( null , 'exit signal should be null, if you see this please tag @MarshallOfSound' ) ;
expect ( code ) . to . equal ( 123 , 'exit code should be 123, if you see this please tag @MarshallOfSound' ) ;
2017-04-06 22:02:32 +00:00
} ) ;
2018-01-11 22:50:35 +00:00
2023-04-04 13:48:51 +00:00
ifit ( [ 'darwin' , 'linux' ] . includes ( process . platform ) ) ( 'exits gracefully' , async function ( ) {
2019-03-10 22:38:44 +00:00
const electronPath = process . execPath ;
const appPath = path . join ( fixturesPath , 'api' , 'singleton' ) ;
appProcess = cp . spawn ( electronPath , [ appPath ] ) ;
2018-03-07 03:01:17 +00:00
// Singleton will send us greeting data to let us know it's running.
// After that, ask it to exit gracefully and confirm that it does.
2019-07-01 18:25:45 +00:00
if ( appProcess && appProcess . stdout ) {
2019-11-01 20:37:02 +00:00
appProcess . stdout . on ( 'data' , ( ) = > appProcess ! . kill ( ) ) ;
2019-07-01 18:25:45 +00:00
}
2023-02-23 23:53:53 +00:00
const [ code , signal ] = await once ( appProcess , 'exit' ) ;
2018-08-26 13:54:51 +00:00
const message = ` code: \ n ${ code } \ nsignal: \ n ${ signal } ` ;
expect ( code ) . to . equal ( 0 , message ) ;
2019-03-10 22:38:44 +00:00
expect ( signal ) . to . equal ( null , message ) ;
2018-01-11 22:50:35 +00:00
} ) ;
2016-03-25 19:57:17 +00:00
} ) ;
2016-02-17 01:09:41 +00:00
2020-02-05 19:12:25 +00:00
ifdescribe ( process . platform === 'darwin' ) ( 'app.setActivationPolicy' , ( ) = > {
it ( 'throws an error on invalid application policies' , ( ) = > {
expect ( ( ) = > {
app . setActivationPolicy ( 'terrible' as any ) ;
} ) . to . throw ( /Invalid activation policy: must be one of 'regular', 'accessory', or 'prohibited'/ ) ;
} ) ;
} ) ;
2021-04-09 07:09:17 +00:00
describe ( 'app.requestSingleInstanceLock' , ( ) = > {
2021-11-04 08:14:09 +00:00
interface SingleInstanceLockTestArgs {
args : string [ ] ;
expectedAdditionalData : unknown ;
}
2020-06-30 22:10:36 +00:00
it ( 'prevents the second launch of app' , async function ( ) {
2022-05-23 05:20:54 +00:00
this . timeout ( 120000 ) ;
const appPath = path . join ( fixturesPath , 'api' , 'singleton-data' ) ;
2019-03-10 22:38:44 +00:00
const first = cp . spawn ( process . execPath , [ appPath ] ) ;
2023-02-23 23:53:53 +00:00
await once ( first . stdout , 'data' ) ;
2017-09-25 02:19:25 +00:00
// Start second app when received output.
2020-06-30 22:10:36 +00:00
const second = cp . spawn ( process . execPath , [ appPath ] ) ;
2023-02-23 23:53:53 +00:00
const [ code2 ] = await once ( second , 'exit' ) ;
2020-06-30 22:10:36 +00:00
expect ( code2 ) . to . equal ( 1 ) ;
2023-02-23 23:53:53 +00:00
const [ code1 ] = await once ( first , 'exit' ) ;
2020-06-30 22:10:36 +00:00
expect ( code1 ) . to . equal ( 0 ) ;
2017-09-20 02:58:10 +00:00
} ) ;
2019-03-12 15:56:28 +00:00
2022-04-04 01:39:55 +00:00
it ( 'returns true when setting non-existent user data folder' , async function ( ) {
const appPath = path . join ( fixturesPath , 'api' , 'singleton-userdata' ) ;
const instance = cp . spawn ( process . execPath , [ appPath ] ) ;
2023-02-23 23:53:53 +00:00
const [ code ] = await once ( instance , 'exit' ) ;
2022-04-04 01:39:55 +00:00
expect ( code ) . to . equal ( 0 ) ;
} ) ;
2021-11-04 08:14:09 +00:00
async function testArgumentPassing ( testArgs : SingleInstanceLockTestArgs ) {
const appPath = path . join ( fixturesPath , 'api' , 'singleton-data' ) ;
const first = cp . spawn ( process . execPath , [ appPath , . . . testArgs . args ] ) ;
2023-02-23 23:53:53 +00:00
const firstExited = once ( first , 'exit' ) ;
2019-03-12 15:56:28 +00:00
// Wait for the first app to boot.
const firstStdoutLines = first . stdout . pipe ( split ( ) ) ;
2023-02-23 23:53:53 +00:00
while ( ( await once ( firstStdoutLines , 'data' ) ) . toString ( ) !== 'started' ) {
2019-03-12 15:56:28 +00:00
// wait.
}
2023-02-23 23:53:53 +00:00
const additionalDataPromise = once ( firstStdoutLines , 'data' ) ;
2020-03-20 20:28:31 +00:00
2021-11-04 08:14:09 +00:00
const secondInstanceArgs = [ process . execPath , appPath , . . . testArgs . args , '--some-switch' , 'some-arg' ] ;
2019-03-13 22:09:28 +00:00
const second = cp . spawn ( secondInstanceArgs [ 0 ] , secondInstanceArgs . slice ( 1 ) ) ;
2023-02-23 23:53:53 +00:00
const secondExited = once ( second , 'exit' ) ;
2021-11-04 08:14:09 +00:00
const [ code2 ] = await secondExited ;
2019-03-12 15:56:28 +00:00
expect ( code2 ) . to . equal ( 1 ) ;
const [ code1 ] = await firstExited ;
expect ( code1 ) . to . equal ( 0 ) ;
2021-11-04 08:14:09 +00:00
const dataFromSecondInstance = await additionalDataPromise ;
const [ args , additionalData ] = dataFromSecondInstance [ 0 ] . toString ( 'ascii' ) . split ( '||' ) ;
2021-10-15 01:32:32 +00:00
const secondInstanceArgsReceived : string [ ] = JSON . parse ( args . toString ( 'ascii' ) ) ;
const secondInstanceDataReceived = JSON . parse ( additionalData . toString ( 'ascii' ) ) ;
2021-09-03 21:16:33 +00:00
// Ensure secondInstanceArgs is a subset of secondInstanceArgsReceived
for ( const arg of secondInstanceArgs ) {
expect ( secondInstanceArgsReceived ) . to . include ( arg ,
` argument ${ arg } is missing from received second args ` ) ;
}
2021-11-04 08:14:09 +00:00
expect ( secondInstanceDataReceived ) . to . be . deep . equal ( testArgs . expectedAdditionalData ,
` received data ${ JSON . stringify ( secondInstanceDataReceived ) } is not equal to expected data ${ JSON . stringify ( testArgs . expectedAdditionalData ) } . ` ) ;
2021-10-15 01:32:32 +00:00
}
2022-05-23 05:20:54 +00:00
it ( 'passes arguments to the second-instance event no additional data' , async ( ) = > {
2021-11-04 08:14:09 +00:00
await testArgumentPassing ( {
args : [ ] ,
2022-05-23 05:20:54 +00:00
expectedAdditionalData : null
2021-11-04 08:14:09 +00:00
} ) ;
} ) ;
2022-05-23 05:20:54 +00:00
it ( 'sends and receives JSON object data' , async ( ) = > {
const expectedAdditionalData = {
level : 1 ,
testkey : 'testvalue1' ,
inner : {
level : 2 ,
testkey : 'testvalue2'
}
} ;
2021-11-04 08:14:09 +00:00
await testArgumentPassing ( {
args : [ '--send-data' ] ,
2022-05-23 05:20:54 +00:00
expectedAdditionalData
2021-11-04 08:14:09 +00:00
} ) ;
2021-10-15 01:32:32 +00:00
} ) ;
2021-11-04 08:14:09 +00:00
it ( 'sends and receives numerical data' , async ( ) = > {
await testArgumentPassing ( {
2022-05-23 05:20:54 +00:00
args : [ '--send-data' , '--data-content=2' ] ,
expectedAdditionalData : 2
2021-11-04 08:14:09 +00:00
} ) ;
} ) ;
it ( 'sends and receives string data' , async ( ) = > {
await testArgumentPassing ( {
2022-05-23 05:20:54 +00:00
args : [ '--send-data' , '--data-content="data"' ] ,
expectedAdditionalData : 'data'
2021-11-04 08:14:09 +00:00
} ) ;
} ) ;
it ( 'sends and receives boolean data' , async ( ) = > {
await testArgumentPassing ( {
2022-05-23 05:20:54 +00:00
args : [ '--send-data' , '--data-content=false' ] ,
expectedAdditionalData : false
2021-11-04 08:14:09 +00:00
} ) ;
} ) ;
it ( 'sends and receives array data' , async ( ) = > {
await testArgumentPassing ( {
2022-05-23 05:20:54 +00:00
args : [ '--send-data' , '--data-content=[2, 3, 4]' ] ,
expectedAdditionalData : [ 2 , 3 , 4 ]
2021-11-04 08:14:09 +00:00
} ) ;
} ) ;
it ( 'sends and receives mixed array data' , async ( ) = > {
await testArgumentPassing ( {
2022-05-23 05:20:54 +00:00
args : [ '--send-data' , '--data-content=["2", true, 4]' ] ,
expectedAdditionalData : [ '2' , true , 4 ]
2021-11-04 08:14:09 +00:00
} ) ;
} ) ;
it ( 'sends and receives null data' , async ( ) = > {
await testArgumentPassing ( {
2022-05-23 05:20:54 +00:00
args : [ '--send-data' , '--data-content=null' ] ,
expectedAdditionalData : null
2021-11-04 08:14:09 +00:00
} ) ;
} ) ;
it ( 'cannot send or receive undefined data' , async ( ) = > {
try {
await testArgumentPassing ( {
args : [ '--send-ack' , '--ack-content="undefined"' , '--prevent-default' , '--send-data' , '--data-content="undefined"' ] ,
2022-05-23 05:20:54 +00:00
expectedAdditionalData : undefined
2021-11-04 08:14:09 +00:00
} ) ;
assert ( false ) ;
2023-07-27 14:53:45 +00:00
} catch {
2021-11-04 08:14:09 +00:00
// This is expected.
}
2019-03-12 15:56:28 +00:00
} ) ;
2017-09-20 02:58:10 +00:00
} ) ;
2021-04-09 07:09:17 +00:00
describe ( 'app.relaunch' , ( ) = > {
2019-03-10 22:38:44 +00:00
let server : net.Server | null = null ;
2016-06-29 16:37:10 +00:00
const socketPath = process . platform === 'win32' ? '\\\\.\\pipe\\electron-app-relaunch' : '/tmp/electron-app-relaunch' ;
2016-06-03 03:12:20 +00:00
2018-06-14 16:44:27 +00:00
beforeEach ( done = > {
2016-06-29 16:37:10 +00:00
fs . unlink ( socketPath , ( ) = > {
2016-06-03 03:12:20 +00:00
server = net . createServer ( ) ;
server . listen ( socketPath ) ;
done ( ) ;
} ) ;
} ) ;
2017-10-27 20:45:58 +00:00
afterEach ( ( done ) = > {
2019-03-10 22:38:44 +00:00
server ! . close ( ( ) = > {
2016-06-03 03:12:20 +00:00
if ( process . platform === 'win32' ) {
done ( ) ;
} else {
2017-10-27 20:45:58 +00:00
fs . unlink ( socketPath , ( ) = > done ( ) ) ;
2016-06-03 03:12:20 +00:00
}
} ) ;
} ) ;
it ( 'relaunches the app' , function ( done ) {
2016-11-29 22:31:57 +00:00
this . timeout ( 120000 ) ;
2016-06-03 03:12:20 +00:00
let state = 'none' ;
2019-03-10 22:38:44 +00:00
server ! . once ( 'error' , error = > done ( error ) ) ;
server ! . on ( 'connection' , client = > {
2018-06-14 16:44:27 +00:00
client . once ( 'data' , data = > {
2022-08-08 08:12:06 +00:00
if ( String ( data ) === '--first' && state === 'none' ) {
2016-06-03 03:12:20 +00:00
state = 'first-launch' ;
2022-08-08 08:12:06 +00:00
} else if ( String ( data ) === '--second' && state === 'first-launch' ) {
state = 'second-launch' ;
} else if ( String ( data ) === '--third' && state === 'second-launch' ) {
2016-06-03 03:12:20 +00:00
done ( ) ;
} else {
2021-03-02 17:34:41 +00:00
done ( ` Unexpected state: " ${ state } ", data: " ${ data } " ` ) ;
2016-06-03 03:12:20 +00:00
}
} ) ;
} ) ;
2019-03-10 22:38:44 +00:00
const appPath = path . join ( fixturesPath , 'api' , 'relaunch' ) ;
2022-08-08 08:12:06 +00:00
const child = cp . spawn ( process . execPath , [ appPath , '--first' ] ) ;
2021-03-02 17:34:41 +00:00
child . stdout . on ( 'data' , ( c ) = > console . log ( c . toString ( ) ) ) ;
child . stderr . on ( 'data' , ( c ) = > console . log ( c . toString ( ) ) ) ;
2021-03-07 07:30:43 +00:00
child . on ( 'exit' , ( code , signal ) = > {
2021-03-02 17:34:41 +00:00
if ( code !== 0 ) {
2021-03-07 07:30:43 +00:00
console . log ( ` Process exited with code " ${ code } " signal " ${ signal } " ` ) ;
2021-03-02 17:34:41 +00:00
}
} ) ;
2016-06-03 03:12:20 +00:00
} ) ;
} ) ;
2023-04-04 13:48:51 +00:00
ifdescribe ( process . platform === 'darwin' ) ( 'app.setUserActivity(type, userInfo)' , ( ) = > {
2017-10-27 20:45:58 +00:00
it ( 'sets the current activity' , ( ) = > {
2018-09-13 16:10:51 +00:00
app . setUserActivity ( 'com.electron.testActivity' , { testData : '123' } ) ;
2018-06-14 16:44:27 +00:00
expect ( app . getCurrentActivityType ( ) ) . to . equal ( 'com.electron.testActivity' ) ;
2016-05-03 22:51:31 +00:00
} ) ;
} ) ;
2020-01-31 23:25:01 +00:00
describe ( 'certificate-error event' , ( ) = > {
afterEach ( closeAllWindows ) ;
it ( 'is emitted when visiting a server with a self-signed cert' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . loadURL ( secureUrl ) ;
2023-02-23 23:53:53 +00:00
await once ( app , 'certificate-error' ) ;
2020-01-31 23:25:01 +00:00
} ) ;
2021-06-23 23:40:51 +00:00
describe ( 'when denied' , ( ) = > {
before ( ( ) = > {
app . on ( 'certificate-error' , ( event , webContents , url , error , certificate , callback ) = > {
callback ( false ) ;
} ) ;
} ) ;
after ( ( ) = > {
app . removeAllListeners ( 'certificate-error' ) ;
} ) ;
it ( 'causes did-fail-load' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . loadURL ( secureUrl ) ;
2023-02-23 23:53:53 +00:00
await once ( w . webContents , 'did-fail-load' ) ;
2021-06-23 23:40:51 +00:00
} ) ;
} ) ;
2020-01-31 23:25:01 +00:00
} ) ;
2019-03-10 22:38:44 +00:00
// xdescribe('app.importCertificate', () => {
// let w = null
// before(function () {
// if (process.platform !== 'linux') {
// this.skip()
// }
// })
// afterEach(() => closeWindow(w).then(() => { w = null }))
// it('can import certificate into platform cert store', done => {
// const options = {
// certificate: path.join(certPath, 'client.p12'),
// password: 'electron'
// }
// w = new BrowserWindow({
// show: false,
// webPreferences: {
// nodeIntegration: true
// }
// })
// w.webContents.on('did-finish-load', () => {
// expect(w.webContents.getTitle()).to.equal('authorized')
// done()
// })
// ipcRenderer.once('select-client-certificate', (event, webContentsId, list) => {
// expect(webContentsId).to.equal(w.webContents.id)
// expect(list).to.have.lengthOf(1)
// expect(list[0]).to.deep.equal({
// issuerName: 'Intermediate CA',
// subjectName: 'Client Cert',
// issuer: { commonName: 'Intermediate CA' },
// subject: { commonName: 'Client Cert' }
// })
// event.sender.send('client-certificate-response', list[0])
// })
// app.importCertificate(options, result => {
// expect(result).toNotExist()
// ipcRenderer.sendSync('set-client-certificate-option', false)
// w.loadURL(secureUrl)
// })
// })
// })
2016-04-18 16:23:44 +00:00
2017-10-27 20:45:58 +00:00
describe ( 'BrowserWindow events' , ( ) = > {
2019-03-10 22:38:44 +00:00
let w : BrowserWindow = null as any ;
2016-02-17 01:09:41 +00:00
2023-10-08 23:55:16 +00:00
afterEach ( ( ) = > {
deprecate . setHandler ( null ) ;
closeWindow ( w ) . then ( ( ) = > { w = null as any ; } ) ;
} ) ;
2016-03-25 19:57:17 +00:00
2020-05-20 20:18:48 +00:00
it ( 'should emit browser-window-focus event when window is focused' , async ( ) = > {
2023-06-22 18:38:52 +00:00
const emitted = once ( app , 'browser-window-focus' ) as Promise < [ any , BrowserWindow ] > ;
2017-10-27 20:45:58 +00:00
w = new BrowserWindow ( { show : false } ) ;
2016-03-25 19:57:17 +00:00
w . emit ( 'focus' ) ;
2020-05-20 20:18:48 +00:00
const [ , window ] = await emitted ;
expect ( window . id ) . to . equal ( w . id ) ;
2016-03-25 19:57:17 +00:00
} ) ;
2022-06-16 07:46:11 +00:00
it ( 'should emit browser-window-blur event when window is blurred' , async ( ) = > {
2023-06-22 18:38:52 +00:00
const emitted = once ( app , 'browser-window-blur' ) as Promise < [ any , BrowserWindow ] > ;
2017-10-27 20:45:58 +00:00
w = new BrowserWindow ( { show : false } ) ;
2016-03-25 19:57:17 +00:00
w . emit ( 'blur' ) ;
2020-05-20 20:18:48 +00:00
const [ , window ] = await emitted ;
expect ( window . id ) . to . equal ( w . id ) ;
2016-03-25 19:57:17 +00:00
} ) ;
2020-05-20 20:18:48 +00:00
it ( 'should emit browser-window-created event when window is created' , async ( ) = > {
2023-06-22 18:38:52 +00:00
const emitted = once ( app , 'browser-window-created' ) as Promise < [ any , BrowserWindow ] > ;
2017-10-27 20:45:58 +00:00
w = new BrowserWindow ( { show : false } ) ;
2020-05-20 20:18:48 +00:00
const [ , window ] = await emitted ;
expect ( window . id ) . to . equal ( w . id ) ;
2016-06-13 16:05:04 +00:00
} ) ;
2020-05-20 20:18:48 +00:00
it ( 'should emit web-contents-created event when a webContents is created' , async ( ) = > {
2023-06-22 18:38:52 +00:00
const emitted = once ( app , 'web-contents-created' ) as Promise < [ any , WebContents ] > ;
2017-10-27 20:45:58 +00:00
w = new BrowserWindow ( { show : false } ) ;
2020-05-20 20:18:48 +00:00
const [ , webContents ] = await emitted ;
expect ( webContents . id ) . to . equal ( w . webContents . id ) ;
2016-03-25 19:57:17 +00:00
} ) ;
2018-10-18 03:36:45 +00:00
2020-05-20 20:18:48 +00:00
// FIXME: re-enable this test on win32.
ifit ( process . platform !== 'win32' ) ( 'should emit renderer-process-crashed event when renderer crashes' , async ( ) = > {
2019-03-11 23:17:24 +00:00
w = new BrowserWindow ( {
show : false ,
webPreferences : {
2021-03-01 21:52:29 +00:00
nodeIntegration : true ,
contextIsolation : false
2019-03-11 23:17:24 +00:00
}
} ) ;
await w . loadURL ( 'about:blank' ) ;
2023-10-08 23:55:16 +00:00
const messages : string [ ] = [ ] ;
deprecate . setHandler ( message = > messages . push ( message ) ) ;
const emitted = once ( app , 'renderer-process-crashed' ) as Promise < [ any , WebContents , boolean ] > ;
2019-03-11 23:17:24 +00:00
w . webContents . executeJavaScript ( 'process.crash()' ) ;
2023-10-08 23:55:16 +00:00
const [ , webContents , killed ] = await emitted ;
2019-03-11 23:17:24 +00:00
expect ( webContents ) . to . equal ( w . webContents ) ;
2023-10-08 23:55:16 +00:00
expect ( killed ) . to . be . false ( ) ;
expect ( messages ) . to . deep . equal ( [ '\'renderer-process-crashed event\' is deprecated and will be removed. Please use \'render-process-gone event\' instead.' ] ) ;
2019-03-11 23:17:24 +00:00
} ) ;
2020-05-20 20:18:48 +00:00
// FIXME: re-enable this test on win32.
ifit ( process . platform !== 'win32' ) ( 'should emit render-process-gone event when renderer crashes' , async ( ) = > {
2020-05-17 15:05:05 +00:00
w = new BrowserWindow ( {
show : false ,
webPreferences : {
2021-03-01 21:52:29 +00:00
nodeIntegration : true ,
contextIsolation : false
2020-05-17 15:05:05 +00:00
}
} ) ;
await w . loadURL ( 'about:blank' ) ;
2023-06-22 18:38:52 +00:00
const emitted = once ( app , 'render-process-gone' ) as Promise < [ any , WebContents , Electron . RenderProcessGoneDetails ] > ;
2020-05-17 15:05:05 +00:00
w . webContents . executeJavaScript ( 'process.crash()' ) ;
2020-05-20 20:18:48 +00:00
const [ , webContents , details ] = await emitted ;
2020-05-17 15:05:05 +00:00
expect ( webContents ) . to . equal ( w . webContents ) ;
expect ( details . reason ) . to . be . oneOf ( [ 'crashed' , 'abnormal-exit' ] ) ;
} ) ;
2016-03-25 19:57:17 +00:00
} ) ;
2016-06-29 17:47:20 +00:00
2019-04-25 22:44:54 +00:00
describe ( 'app.badgeCount' , ( ) = > {
2017-11-15 21:05:46 +00:00
const platformIsNotSupported =
( process . platform === 'win32' ) ||
( process . platform === 'linux' && ! app . isUnityRunning ( ) ) ;
2016-07-01 13:18:39 +00:00
2017-11-15 21:05:46 +00:00
const expectedBadgeCount = 42 ;
2019-04-25 22:44:54 +00:00
after ( ( ) = > { app . badgeCount = 0 ; } ) ;
2016-10-06 17:29:55 +00:00
2021-01-21 05:45:06 +00:00
ifdescribe ( ! platformIsNotSupported ) ( 'on supported platform' , ( ) = > {
describe ( 'with properties' , ( ) = > {
2020-03-18 17:06:41 +00:00
it ( 'sets a badge count' , function ( ) {
app . badgeCount = expectedBadgeCount ;
expect ( app . badgeCount ) . to . equal ( expectedBadgeCount ) ;
} ) ;
} ) ;
2017-11-15 21:05:46 +00:00
2021-01-21 05:45:06 +00:00
describe ( 'with functions' , ( ) = > {
it ( 'sets a numerical badge count' , function ( ) {
2020-03-18 17:06:41 +00:00
app . setBadgeCount ( expectedBadgeCount ) ;
expect ( app . getBadgeCount ( ) ) . to . equal ( expectedBadgeCount ) ;
} ) ;
2021-01-21 05:45:06 +00:00
it ( 'sets an non numeric (dot) badge count' , function ( ) {
app . setBadgeCount ( ) ;
// Badge count should be zero when non numeric (dot) is requested
expect ( app . getBadgeCount ( ) ) . to . equal ( 0 ) ;
} ) ;
2017-11-15 21:05:46 +00:00
} ) ;
2016-07-01 13:18:39 +00:00
} ) ;
2021-01-21 05:45:06 +00:00
ifdescribe ( process . platform !== 'win32' && platformIsNotSupported ) ( 'on unsupported platform' , ( ) = > {
describe ( 'with properties' , ( ) = > {
2020-03-18 17:06:41 +00:00
it ( 'does not set a badge count' , function ( ) {
app . badgeCount = 9999 ;
expect ( app . badgeCount ) . to . equal ( 0 ) ;
} ) ;
} ) ;
2021-01-21 05:45:06 +00:00
describe ( 'with functions' , ( ) = > {
2020-03-18 17:06:41 +00:00
it ( 'does not set a badge count)' , function ( ) {
app . setBadgeCount ( 9999 ) ;
expect ( app . getBadgeCount ( ) ) . to . equal ( 0 ) ;
} ) ;
2017-11-15 21:05:46 +00:00
} ) ;
2016-06-29 17:47:20 +00:00
} ) ;
} ) ;
2016-07-06 20:34:14 +00:00
2021-01-21 23:36:52 +00:00
ifdescribe ( process . platform !== 'linux' && ! process . mas ) ( 'app.get/setLoginItemSettings API' , function ( ) {
2017-02-02 16:01:47 +00:00
const updateExe = path . resolve ( path . dirname ( process . execPath ) , '..' , 'Update.exe' ) ;
const processStartArgs = [
'--processStart' , ` " ${ path . basename ( process . execPath ) } " ` ,
2020-03-20 15:12:18 +00:00
'--process-start-args' , '"--hidden"'
2017-02-02 16:01:47 +00:00
] ;
2020-11-17 20:13:08 +00:00
const regAddArgs = [
'ADD' ,
'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run' ,
'/v' ,
'additionalEntry' ,
'/t' ,
'REG_BINARY' ,
'/f' ,
'/d'
] ;
2017-02-02 16:01:47 +00:00
2017-10-27 20:45:58 +00:00
beforeEach ( ( ) = > {
2018-09-13 16:10:51 +00:00
app . setLoginItemSettings ( { openAtLogin : false } ) ;
app . setLoginItemSettings ( { openAtLogin : false , path : updateExe , args : processStartArgs } ) ;
2020-11-17 20:13:08 +00:00
app . setLoginItemSettings ( { name : 'additionalEntry' , openAtLogin : false } ) ;
2016-07-06 20:57:20 +00:00
} ) ;
2017-10-27 20:45:58 +00:00
afterEach ( ( ) = > {
2018-09-13 16:10:51 +00:00
app . setLoginItemSettings ( { openAtLogin : false } ) ;
app . setLoginItemSettings ( { openAtLogin : false , path : updateExe , args : processStartArgs } ) ;
2020-11-17 20:13:08 +00:00
app . setLoginItemSettings ( { name : 'additionalEntry' , openAtLogin : false } ) ;
2016-07-06 20:34:14 +00:00
} ) ;
2020-07-29 17:08:37 +00:00
ifit ( process . platform !== 'win32' ) ( 'sets and returns the app as a login item' , function ( ) {
2018-09-13 16:10:51 +00:00
app . setLoginItemSettings ( { openAtLogin : true } ) ;
2019-01-31 17:59:32 +00:00
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( {
openAtLogin : true ,
openAsHidden : false ,
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false
} ) ;
2016-07-06 20:34:14 +00:00
} ) ;
2017-01-26 20:24:33 +00:00
2020-07-29 17:08:37 +00:00
ifit ( process . platform === 'win32' ) ( 'sets and returns the app as a login item (windows)' , function ( ) {
2020-11-17 20:13:08 +00:00
app . setLoginItemSettings ( { openAtLogin : true , enabled : true } ) ;
2020-07-29 17:08:37 +00:00
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( {
openAtLogin : true ,
openAsHidden : false ,
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false ,
executableWillLaunchAtLogin : true ,
launchItems : [ {
name : 'electron.app.Electron' ,
path : process.execPath ,
args : [ ] ,
scope : 'user' ,
enabled : true
} ]
} ) ;
2020-11-17 20:13:08 +00:00
app . setLoginItemSettings ( { openAtLogin : false } ) ;
app . setLoginItemSettings ( { openAtLogin : true , enabled : false } ) ;
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( {
openAtLogin : true ,
openAsHidden : false ,
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false ,
executableWillLaunchAtLogin : false ,
launchItems : [ {
name : 'electron.app.Electron' ,
path : process.execPath ,
args : [ ] ,
scope : 'user' ,
enabled : false
} ]
} ) ;
2020-07-29 17:08:37 +00:00
} ) ;
ifit ( process . platform !== 'win32' ) ( 'adds a login item that loads in hidden mode' , function ( ) {
2018-10-13 07:52:19 +00:00
app . setLoginItemSettings ( { openAtLogin : true , openAsHidden : true } ) ;
2019-01-31 17:59:32 +00:00
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( {
openAtLogin : true ,
openAsHidden : process.platform === 'darwin' && ! process . mas , // Only available on macOS
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false
} ) ;
2020-07-29 17:08:37 +00:00
} ) ;
ifit ( process . platform === 'win32' ) ( 'adds a login item that loads in hidden mode (windows)' , function ( ) {
app . setLoginItemSettings ( { openAtLogin : true , openAsHidden : true } ) ;
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( {
openAtLogin : true ,
openAsHidden : false ,
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false ,
executableWillLaunchAtLogin : true ,
launchItems : [ {
name : 'electron.app.Electron' ,
path : process.execPath ,
args : [ ] ,
scope : 'user' ,
enabled : true
} ]
} ) ;
2018-10-13 07:52:19 +00:00
} ) ;
2018-11-06 19:31:32 +00:00
it ( 'correctly sets and unsets the LoginItem' , function ( ) {
2019-03-10 22:38:44 +00:00
expect ( app . getLoginItemSettings ( ) . openAtLogin ) . to . equal ( false ) ;
2018-11-06 19:31:32 +00:00
app . setLoginItemSettings ( { openAtLogin : true } ) ;
2019-03-10 22:38:44 +00:00
expect ( app . getLoginItemSettings ( ) . openAtLogin ) . to . equal ( true ) ;
2018-11-06 19:31:32 +00:00
app . setLoginItemSettings ( { openAtLogin : false } ) ;
2019-03-10 22:38:44 +00:00
expect ( app . getLoginItemSettings ( ) . openAtLogin ) . to . equal ( false ) ;
2018-11-06 19:31:32 +00:00
} ) ;
2023-04-04 13:48:51 +00:00
ifit ( process . platform === 'darwin' ) ( 'correctly sets and unsets the LoginItem as hidden' , function ( ) {
2019-03-10 22:38:44 +00:00
expect ( app . getLoginItemSettings ( ) . openAtLogin ) . to . equal ( false ) ;
expect ( app . getLoginItemSettings ( ) . openAsHidden ) . to . equal ( false ) ;
2018-10-12 22:19:27 +00:00
app . setLoginItemSettings ( { openAtLogin : true , openAsHidden : true } ) ;
2019-03-10 22:38:44 +00:00
expect ( app . getLoginItemSettings ( ) . openAtLogin ) . to . equal ( true ) ;
expect ( app . getLoginItemSettings ( ) . openAsHidden ) . to . equal ( true ) ;
2018-10-12 22:19:27 +00:00
app . setLoginItemSettings ( { openAtLogin : true , openAsHidden : false } ) ;
2019-03-10 22:38:44 +00:00
expect ( app . getLoginItemSettings ( ) . openAtLogin ) . to . equal ( true ) ;
expect ( app . getLoginItemSettings ( ) . openAsHidden ) . to . equal ( false ) ;
2018-10-12 22:19:27 +00:00
} ) ;
2020-07-29 17:08:37 +00:00
ifit ( process . platform === 'win32' ) ( 'allows you to pass a custom executable and arguments' , function ( ) {
app . setLoginItemSettings ( { openAtLogin : true , path : updateExe , args : processStartArgs , enabled : true } ) ;
expect ( app . getLoginItemSettings ( ) . openAtLogin ) . to . equal ( false ) ;
const openAtLoginTrueEnabledTrue = app . getLoginItemSettings ( {
path : updateExe ,
args : processStartArgs
} ) ;
expect ( openAtLoginTrueEnabledTrue . openAtLogin ) . to . equal ( true ) ;
expect ( openAtLoginTrueEnabledTrue . executableWillLaunchAtLogin ) . to . equal ( true ) ;
app . setLoginItemSettings ( { openAtLogin : true , path : updateExe , args : processStartArgs , enabled : false } ) ;
const openAtLoginTrueEnabledFalse = app . getLoginItemSettings ( {
path : updateExe ,
args : processStartArgs
} ) ;
2017-01-26 20:24:33 +00:00
2020-07-29 17:08:37 +00:00
expect ( openAtLoginTrueEnabledFalse . openAtLogin ) . to . equal ( true ) ;
expect ( openAtLoginTrueEnabledFalse . executableWillLaunchAtLogin ) . to . equal ( false ) ;
2017-01-26 20:35:46 +00:00
2020-07-29 17:08:37 +00:00
app . setLoginItemSettings ( { openAtLogin : false , path : updateExe , args : processStartArgs , enabled : false } ) ;
const openAtLoginFalseEnabledFalse = app . getLoginItemSettings ( {
2018-06-14 16:44:27 +00:00
path : updateExe ,
args : processStartArgs
2020-07-29 17:08:37 +00:00
} ) ;
expect ( openAtLoginFalseEnabledFalse . openAtLogin ) . to . equal ( false ) ;
expect ( openAtLoginFalseEnabledFalse . executableWillLaunchAtLogin ) . to . equal ( false ) ;
} ) ;
ifit ( process . platform === 'win32' ) ( 'allows you to pass a custom name' , function ( ) {
app . setLoginItemSettings ( { openAtLogin : true } ) ;
app . setLoginItemSettings ( { openAtLogin : true , name : 'additionalEntry' , enabled : false } ) ;
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( {
openAtLogin : true ,
openAsHidden : false ,
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false ,
executableWillLaunchAtLogin : true ,
launchItems : [ {
name : 'additionalEntry' ,
path : process.execPath ,
args : [ ] ,
scope : 'user' ,
enabled : false
} , {
name : 'electron.app.Electron' ,
path : process.execPath ,
args : [ ] ,
scope : 'user' ,
enabled : true
} ]
} ) ;
app . setLoginItemSettings ( { openAtLogin : false , name : 'additionalEntry' } ) ;
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( {
openAtLogin : true ,
openAsHidden : false ,
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false ,
executableWillLaunchAtLogin : true ,
launchItems : [ {
name : 'electron.app.Electron' ,
path : process.execPath ,
args : [ ] ,
scope : 'user' ,
enabled : true
} ]
} ) ;
2017-01-26 20:24:33 +00:00
} ) ;
2020-11-17 20:13:08 +00:00
ifit ( process . platform === 'win32' ) ( 'finds launch items independent of args' , function ( ) {
app . setLoginItemSettings ( { openAtLogin : true , args : [ 'arg1' ] } ) ;
app . setLoginItemSettings ( { openAtLogin : true , name : 'additionalEntry' , enabled : false , args : [ 'arg2' ] } ) ;
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( {
openAtLogin : false ,
openAsHidden : false ,
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false ,
executableWillLaunchAtLogin : true ,
launchItems : [ {
name : 'additionalEntry' ,
path : process.execPath ,
args : [ 'arg2' ] ,
scope : 'user' ,
enabled : false
} , {
name : 'electron.app.Electron' ,
path : process.execPath ,
args : [ 'arg1' ] ,
scope : 'user' ,
enabled : true
} ]
} ) ;
} ) ;
ifit ( process . platform === 'win32' ) ( 'finds launch items independent of path quotation or casing' , function ( ) {
const expectation = {
openAtLogin : false ,
openAsHidden : false ,
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false ,
executableWillLaunchAtLogin : true ,
launchItems : [ {
name : 'additionalEntry' ,
path : 'C:\\electron\\myapp.exe' ,
args : [ 'arg1' ] ,
scope : 'user' ,
enabled : true
} ]
} ;
app . setLoginItemSettings ( { openAtLogin : true , name : 'additionalEntry' , enabled : true , path : 'C:\\electron\\myapp.exe' , args : [ 'arg1' ] } ) ;
expect ( app . getLoginItemSettings ( { path : '"C:\\electron\\MYAPP.exe"' } ) ) . to . deep . equal ( expectation ) ;
app . setLoginItemSettings ( { openAtLogin : false , name : 'additionalEntry' } ) ;
app . setLoginItemSettings ( { openAtLogin : true , name : 'additionalEntry' , enabled : true , path : '"C:\\electron\\MYAPP.exe"' , args : [ 'arg1' ] } ) ;
expect ( app . getLoginItemSettings ( { path : 'C:\\electron\\myapp.exe' } ) ) . to . deep . equal ( {
. . . expectation ,
launchItems : [
{
name : 'additionalEntry' ,
path : 'C:\\electron\\MYAPP.exe' ,
args : [ 'arg1' ] ,
scope : 'user' ,
enabled : true
}
]
} ) ;
} ) ;
ifit ( process . platform === 'win32' ) ( 'detects disabled by TaskManager' , async function ( ) {
app . setLoginItemSettings ( { openAtLogin : true , name : 'additionalEntry' , enabled : true , args : [ 'arg1' ] } ) ;
const appProcess = cp . spawn ( 'reg' , [ . . . regAddArgs , '030000000000000000000000' ] ) ;
2023-02-23 23:53:53 +00:00
await once ( appProcess , 'exit' ) ;
2020-11-17 20:13:08 +00:00
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( {
openAtLogin : false ,
openAsHidden : false ,
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false ,
executableWillLaunchAtLogin : false ,
launchItems : [ {
name : 'additionalEntry' ,
path : process.execPath ,
args : [ 'arg1' ] ,
scope : 'user' ,
enabled : false
} ]
} ) ;
} ) ;
ifit ( process . platform === 'win32' ) ( 'detects enabled by TaskManager' , async function ( ) {
const expectation = {
openAtLogin : false ,
openAsHidden : false ,
wasOpenedAtLogin : false ,
wasOpenedAsHidden : false ,
restoreState : false ,
executableWillLaunchAtLogin : true ,
launchItems : [ {
name : 'additionalEntry' ,
path : process.execPath ,
args : [ 'arg1' ] ,
scope : 'user' ,
enabled : true
} ]
} ;
app . setLoginItemSettings ( { openAtLogin : true , name : 'additionalEntry' , enabled : false , args : [ 'arg1' ] } ) ;
let appProcess = cp . spawn ( 'reg' , [ . . . regAddArgs , '020000000000000000000000' ] ) ;
2023-02-23 23:53:53 +00:00
await once ( appProcess , 'exit' ) ;
2020-11-17 20:13:08 +00:00
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( expectation ) ;
app . setLoginItemSettings ( { openAtLogin : true , name : 'additionalEntry' , enabled : false , args : [ 'arg1' ] } ) ;
appProcess = cp . spawn ( 'reg' , [ . . . regAddArgs , '000000000000000000000000' ] ) ;
2023-02-23 23:53:53 +00:00
await once ( appProcess , 'exit' ) ;
2020-11-17 20:13:08 +00:00
expect ( app . getLoginItemSettings ( ) ) . to . deep . equal ( expectation ) ;
} ) ;
2016-07-06 20:34:14 +00:00
} ) ;
2016-07-11 21:32:24 +00:00
2020-03-18 17:06:41 +00:00
ifdescribe ( process . platform !== 'linux' ) ( 'accessibilitySupportEnabled property' , ( ) = > {
it ( 'with properties' , ( ) = > {
it ( 'can set accessibility support enabled' , ( ) = > {
expect ( app . accessibilitySupportEnabled ) . to . eql ( false ) ;
2019-04-05 02:49:04 +00:00
2020-03-18 17:06:41 +00:00
app . accessibilitySupportEnabled = true ;
expect ( app . accessibilitySupportEnabled ) . to . eql ( true ) ;
} ) ;
} ) ;
2019-04-05 02:49:04 +00:00
2020-03-18 17:06:41 +00:00
it ( 'with functions' , ( ) = > {
it ( 'can set accessibility support enabled' , ( ) = > {
expect ( app . isAccessibilitySupportEnabled ( ) ) . to . eql ( false ) ;
app . setAccessibilitySupportEnabled ( true ) ;
expect ( app . isAccessibilitySupportEnabled ( ) ) . to . eql ( true ) ;
} ) ;
2016-07-11 21:32:24 +00:00
} ) ;
} ) ;
2016-10-06 16:57:25 +00:00
2021-04-09 07:09:17 +00:00
describe ( 'getAppPath' , ( ) = > {
2019-06-19 21:34:22 +00:00
it ( 'works for directories with package.json' , async ( ) = > {
const { appPath } = await runTestApp ( 'app-path' ) ;
expect ( appPath ) . to . equal ( path . resolve ( fixturesPath , 'api/app-path' ) ) ;
} ) ;
it ( 'works for directories with index.js' , async ( ) = > {
const { appPath } = await runTestApp ( 'app-path/lib' ) ;
expect ( appPath ) . to . equal ( path . resolve ( fixturesPath , 'api/app-path/lib' ) ) ;
} ) ;
it ( 'works for files without extension' , async ( ) = > {
const { appPath } = await runTestApp ( 'app-path/lib/index' ) ;
expect ( appPath ) . to . equal ( path . resolve ( fixturesPath , 'api/app-path/lib' ) ) ;
} ) ;
it ( 'works for files' , async ( ) = > {
const { appPath } = await runTestApp ( 'app-path/lib/index.js' ) ;
expect ( appPath ) . to . equal ( path . resolve ( fixturesPath , 'api/app-path/lib' ) ) ;
} ) ;
} ) ;
2017-10-27 20:45:58 +00:00
describe ( 'getPath(name)' , ( ) = > {
it ( 'returns paths that exist' , ( ) = > {
2018-06-14 16:44:27 +00:00
const paths = [
fs . existsSync ( app . getPath ( 'exe' ) ) ,
fs . existsSync ( app . getPath ( 'home' ) ) ,
fs . existsSync ( app . getPath ( 'temp' ) )
] ;
expect ( paths ) . to . deep . equal ( [ true , true , true ] ) ;
2016-10-06 16:57:25 +00:00
} ) ;
2017-10-27 20:45:58 +00:00
it ( 'throws an error when the name is invalid' , ( ) = > {
2018-06-14 16:44:27 +00:00
expect ( ( ) = > {
2019-07-26 23:11:22 +00:00
app . getPath ( 'does-not-exist' as any ) ;
2018-06-14 16:44:27 +00:00
} ) . to . throw ( /Failed to get 'does-not-exist' path/ ) ;
2016-10-06 16:57:25 +00:00
} ) ;
2017-10-27 20:45:58 +00:00
it ( 'returns the overridden path' , ( ) = > {
2016-10-06 16:57:25 +00:00
app . setPath ( 'music' , __dirname ) ;
2018-06-14 16:44:27 +00:00
expect ( app . getPath ( 'music' ) ) . to . equal ( __dirname ) ;
2016-10-06 16:57:25 +00:00
} ) ;
2020-05-13 02:27:56 +00:00
if ( process . platform === 'win32' ) {
it ( 'gets the folder for recent files' , ( ) = > {
const recent = app . getPath ( 'recent' ) ;
2022-06-16 07:46:11 +00:00
// We expect that one of our test machines have overridden this
2020-05-13 02:27:56 +00:00
// to be something crazy, it'll always include the word "Recent"
// unless people have been registry-hacking like crazy
expect ( recent ) . to . include ( 'Recent' ) ;
} ) ;
it ( 'can override the recent files path' , ( ) = > {
app . setPath ( 'recent' , 'C:\\fake-path' ) ;
expect ( app . getPath ( 'recent' ) ) . to . equal ( 'C:\\fake-path' ) ;
} ) ;
}
2021-07-14 20:10:37 +00:00
it ( 'uses the app name in getPath(userData)' , ( ) = > {
expect ( app . getPath ( 'userData' ) ) . to . include ( app . name ) ;
} ) ;
2016-10-06 16:57:25 +00:00
} ) ;
2016-12-02 17:34:16 +00:00
2019-05-28 17:37:54 +00:00
describe ( 'setPath(name, path)' , ( ) = > {
2020-03-10 16:03:52 +00:00
it ( 'throws when a relative path is passed' , ( ) = > {
const badPath = 'hey/hi/hello' ;
expect ( ( ) = > {
app . setPath ( 'music' , badPath ) ;
} ) . to . throw ( /Path must be absolute/ ) ;
} ) ;
2019-05-28 17:37:54 +00:00
it ( 'does not create a new directory by default' , ( ) = > {
const badPath = path . join ( __dirname , 'music' ) ;
2019-10-30 23:38:21 +00:00
expect ( fs . existsSync ( badPath ) ) . to . be . false ( ) ;
2019-05-28 17:37:54 +00:00
app . setPath ( 'music' , badPath ) ;
2019-10-30 23:38:21 +00:00
expect ( fs . existsSync ( badPath ) ) . to . be . false ( ) ;
2019-05-28 17:37:54 +00:00
2019-07-26 23:11:22 +00:00
expect ( ( ) = > { app . getPath ( badPath as any ) ; } ) . to . throw ( ) ;
2019-05-28 17:37:54 +00:00
} ) ;
2022-05-09 14:26:57 +00:00
describe ( 'sessionData' , ( ) = > {
const appPath = path . join ( __dirname , 'fixtures' , 'apps' , 'set-path' ) ;
const appName = fs . readJsonSync ( path . join ( appPath , 'package.json' ) ) . name ;
const userDataPath = path . join ( app . getPath ( 'appData' ) , appName ) ;
const tempBrowserDataPath = path . join ( app . getPath ( 'temp' ) , appName ) ;
const sessionFiles = [
'Preferences' ,
'Code Cache' ,
'Local Storage' ,
'IndexedDB' ,
'Service Worker'
] ;
const hasSessionFiles = ( dir : string ) = > {
for ( const file of sessionFiles ) {
if ( ! fs . existsSync ( path . join ( dir , file ) ) ) {
return false ;
}
}
return true ;
} ;
beforeEach ( ( ) = > {
fs . removeSync ( userDataPath ) ;
fs . removeSync ( tempBrowserDataPath ) ;
} ) ;
it ( 'writes to userData by default' , ( ) = > {
expect ( hasSessionFiles ( userDataPath ) ) . to . equal ( false ) ;
cp . spawnSync ( process . execPath , [ appPath ] ) ;
expect ( hasSessionFiles ( userDataPath ) ) . to . equal ( true ) ;
} ) ;
it ( 'can be changed' , ( ) = > {
expect ( hasSessionFiles ( userDataPath ) ) . to . equal ( false ) ;
cp . spawnSync ( process . execPath , [ appPath , 'sessionData' , tempBrowserDataPath ] ) ;
expect ( hasSessionFiles ( userDataPath ) ) . to . equal ( false ) ;
expect ( hasSessionFiles ( tempBrowserDataPath ) ) . to . equal ( true ) ;
} ) ;
it ( 'changing userData affects default sessionData' , ( ) = > {
expect ( hasSessionFiles ( userDataPath ) ) . to . equal ( false ) ;
cp . spawnSync ( process . execPath , [ appPath , 'userData' , tempBrowserDataPath ] ) ;
expect ( hasSessionFiles ( userDataPath ) ) . to . equal ( false ) ;
expect ( hasSessionFiles ( tempBrowserDataPath ) ) . to . equal ( true ) ;
} ) ;
} ) ;
2019-05-28 17:37:54 +00:00
} ) ;
2020-03-10 16:03:52 +00:00
describe ( 'setAppLogsPath(path)' , ( ) = > {
it ( 'throws when a relative path is passed' , ( ) = > {
const badPath = 'hey/hi/hello' ;
expect ( ( ) = > {
app . setAppLogsPath ( badPath ) ;
} ) . to . throw ( /Path must be absolute/ ) ;
} ) ;
} ) ;
2023-04-04 13:48:51 +00:00
ifdescribe ( process . platform !== 'linux' ) ( 'select-client-certificate event' , ( ) = > {
2019-03-10 22:38:44 +00:00
let w : BrowserWindow ;
2016-12-02 17:34:16 +00:00
2018-03-09 05:43:49 +00:00
before ( function ( ) {
2020-01-31 23:25:01 +00:00
session . fromPartition ( 'empty-certificate' ) . setCertificateVerifyProc ( ( req , cb ) = > { cb ( 0 ) ; } ) ;
2018-03-09 05:43:49 +00:00
} ) ;
2017-10-27 20:45:58 +00:00
beforeEach ( ( ) = > {
2016-12-02 17:34:16 +00:00
w = new BrowserWindow ( {
show : false ,
webPreferences : {
2019-01-07 19:19:27 +00:00
nodeIntegration : true ,
2016-12-02 17:34:16 +00:00
partition : 'empty-certificate'
}
} ) ;
} ) ;
2019-03-10 22:38:44 +00:00
afterEach ( ( ) = > closeWindow ( w ) . then ( ( ) = > { w = null as any ; } ) ) ;
2016-12-02 17:34:16 +00:00
2020-01-31 23:25:01 +00:00
after ( ( ) = > session . fromPartition ( 'empty-certificate' ) . setCertificateVerifyProc ( null ) ) ;
2019-03-10 22:38:44 +00:00
it ( 'can respond with empty certificate list' , async ( ) = > {
app . once ( 'select-client-certificate' , function ( event , webContents , url , list , callback ) {
console . log ( 'select-client-certificate emitted' ) ;
event . preventDefault ( ) ;
callback ( ) ;
2016-12-02 17:34:16 +00:00
} ) ;
2019-03-10 22:38:44 +00:00
await w . webContents . loadURL ( secureUrl ) ;
expect ( w . webContents . getTitle ( ) ) . to . equal ( 'denied' ) ;
2016-12-02 17:34:16 +00:00
} ) ;
} ) ;
2017-02-02 16:11:34 +00:00
2023-04-04 13:48:51 +00:00
ifdescribe ( process . platform === 'win32' ) ( 'setAsDefaultProtocolClient(protocol, path, args)' , ( ) = > {
2017-02-02 16:41:14 +00:00
const protocol = 'electron-test' ;
2017-02-02 16:11:34 +00:00
const updateExe = path . resolve ( path . dirname ( process . execPath ) , '..' , 'Update.exe' ) ;
const processStartArgs = [
'--processStart' , ` " ${ path . basename ( process . execPath ) } " ` ,
2020-03-20 15:12:18 +00:00
'--process-start-args' , '"--hidden"'
2017-02-02 16:11:34 +00:00
] ;
2019-03-10 22:38:44 +00:00
let Winreg : any ;
let classesKey : any ;
2017-12-05 19:28:39 +00:00
2017-11-15 21:05:46 +00:00
before ( function ( ) {
2023-04-04 13:48:51 +00:00
Winreg = require ( 'winreg' ) ;
2017-12-05 19:28:39 +00:00
2023-04-04 13:48:51 +00:00
classesKey = new Winreg ( {
hive : Winreg.HKCU ,
key : '\\Software\\Classes\\'
} ) ;
2017-11-15 21:05:46 +00:00
} ) ;
2017-12-05 19:31:40 +00:00
after ( function ( done ) {
2017-12-06 01:07:22 +00:00
if ( process . platform !== 'win32' ) {
done ( ) ;
} else {
2017-12-05 20:14:19 +00:00
const protocolKey = new Winreg ( {
hive : Winreg.HKCU ,
key : ` \\ Software \\ Classes \\ ${ protocol } `
} ) ;
2017-12-05 19:31:40 +00:00
2017-12-05 20:14:19 +00:00
// The last test leaves the registry dirty,
// delete the protocol key for those of us who test at home
protocolKey . destroy ( ( ) = > done ( ) ) ;
2017-12-05 21:20:34 +00:00
}
2017-12-05 19:31:40 +00:00
} ) ;
2017-02-02 16:11:34 +00:00
beforeEach ( ( ) = > {
2017-02-02 16:41:14 +00:00
app . removeAsDefaultProtocolClient ( protocol ) ;
app . removeAsDefaultProtocolClient ( protocol , updateExe , processStartArgs ) ;
2017-02-02 16:11:34 +00:00
} ) ;
afterEach ( ( ) = > {
2017-02-02 16:41:14 +00:00
app . removeAsDefaultProtocolClient ( protocol ) ;
2019-03-10 22:38:44 +00:00
expect ( app . isDefaultProtocolClient ( protocol ) ) . to . equal ( false ) ;
2018-06-14 16:44:27 +00:00
2017-02-02 16:41:14 +00:00
app . removeAsDefaultProtocolClient ( protocol , updateExe , processStartArgs ) ;
2019-03-10 22:38:44 +00:00
expect ( app . isDefaultProtocolClient ( protocol , updateExe , processStartArgs ) ) . to . equal ( false ) ;
2017-02-02 16:11:34 +00:00
} ) ;
it ( 'sets the app as the default protocol client' , ( ) = > {
2019-03-10 22:38:44 +00:00
expect ( app . isDefaultProtocolClient ( protocol ) ) . to . equal ( false ) ;
2017-02-02 16:41:14 +00:00
app . setAsDefaultProtocolClient ( protocol ) ;
2019-03-10 22:38:44 +00:00
expect ( app . isDefaultProtocolClient ( protocol ) ) . to . equal ( true ) ;
2017-02-02 16:11:34 +00:00
} ) ;
it ( 'allows a custom path and args to be specified' , ( ) = > {
2019-03-10 22:38:44 +00:00
expect ( app . isDefaultProtocolClient ( protocol , updateExe , processStartArgs ) ) . to . equal ( false ) ;
2017-02-02 16:41:14 +00:00
app . setAsDefaultProtocolClient ( protocol , updateExe , processStartArgs ) ;
2018-06-14 16:44:27 +00:00
2019-03-10 22:38:44 +00:00
expect ( app . isDefaultProtocolClient ( protocol , updateExe , processStartArgs ) ) . to . equal ( true ) ;
expect ( app . isDefaultProtocolClient ( protocol ) ) . to . equal ( false ) ;
2017-02-02 16:11:34 +00:00
} ) ;
2017-12-05 19:28:39 +00:00
2020-07-01 19:14:38 +00:00
it ( 'creates a registry entry for the protocol class' , async ( ) = > {
2017-12-05 19:28:39 +00:00
app . setAsDefaultProtocolClient ( protocol ) ;
2017-12-05 19:38:19 +00:00
2020-07-01 19:14:38 +00:00
const keys = await promisify ( classesKey . keys ) . call ( classesKey ) as any [ ] ;
2023-08-02 17:43:45 +00:00
const exists = keys . some ( key = > key . key . includes ( protocol ) ) ;
2020-07-01 19:14:38 +00:00
expect ( exists ) . to . equal ( true ) ;
2017-12-05 19:28:39 +00:00
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'completely removes a registry entry for the protocol class' , async ( ) = > {
2017-12-05 19:28:39 +00:00
app . setAsDefaultProtocolClient ( protocol ) ;
app . removeAsDefaultProtocolClient ( protocol ) ;
2017-12-05 19:38:19 +00:00
2020-07-01 19:14:38 +00:00
const keys = await promisify ( classesKey . keys ) . call ( classesKey ) as any [ ] ;
2023-08-02 17:43:45 +00:00
const exists = keys . some ( key = > key . key . includes ( protocol ) ) ;
2020-07-01 19:14:38 +00:00
expect ( exists ) . to . equal ( false ) ;
2017-12-05 19:28:39 +00:00
} ) ;
2020-07-01 19:14:38 +00:00
it ( 'only unsets a class registry key if it contains other data' , async ( ) = > {
2017-12-05 19:28:39 +00:00
app . setAsDefaultProtocolClient ( protocol ) ;
const protocolKey = new Winreg ( {
hive : Winreg.HKCU ,
key : ` \\ Software \\ Classes \\ ${ protocol } `
} ) ;
2020-07-01 19:14:38 +00:00
await promisify ( protocolKey . set ) . call ( protocolKey , 'test-value' , 'REG_BINARY' , '123' ) ;
app . removeAsDefaultProtocolClient ( protocol ) ;
2017-12-05 19:38:19 +00:00
2020-07-01 19:14:38 +00:00
const keys = await promisify ( classesKey . keys ) . call ( classesKey ) as any [ ] ;
2023-08-02 17:43:45 +00:00
const exists = keys . some ( key = > key . key . includes ( protocol ) ) ;
2020-07-01 19:14:38 +00:00
expect ( exists ) . to . equal ( true ) ;
2017-12-05 19:28:39 +00:00
} ) ;
2019-11-07 01:50:33 +00:00
it ( 'sets the default client such that getApplicationNameForProtocol returns Electron' , ( ) = > {
app . setAsDefaultProtocolClient ( protocol ) ;
expect ( app . getApplicationNameForProtocol ( ` ${ protocol } :// ` ) ) . to . equal ( 'Electron' ) ;
} ) ;
} ) ;
describe ( 'getApplicationNameForProtocol()' , ( ) = > {
2023-04-04 13:48:51 +00:00
// TODO: Linux CI doesn't have registered http & https handlers
ifit ( ! ( process . env . CI && process . platform === 'linux' ) ) ( 'returns application names for common protocols' , function ( ) {
2019-11-07 01:50:33 +00:00
// We can't expect particular app names here, but these protocols should
// at least have _something_ registered. Except on our Linux CI
// environment apparently.
const protocols = [
'http://' ,
'https://'
] ;
2023-08-31 14:36:43 +00:00
for ( const protocol of protocols ) {
2019-11-07 01:50:33 +00:00
expect ( app . getApplicationNameForProtocol ( protocol ) ) . to . not . equal ( '' ) ;
2023-08-31 14:36:43 +00:00
}
2019-11-07 01:50:33 +00:00
} ) ;
it ( 'returns an empty string for a bogus protocol' , ( ) = > {
expect ( app . getApplicationNameForProtocol ( 'bogus-protocol://' ) ) . to . equal ( '' ) ;
} ) ;
} ) ;
2020-06-30 19:22:30 +00:00
ifdescribe ( process . platform !== 'linux' ) ( 'getApplicationInfoForProtocol()' , ( ) = > {
it ( 'returns promise rejection for a bogus protocol' , async function ( ) {
await expect (
app . getApplicationInfoForProtocol ( 'bogus-protocol://' )
) . to . eventually . be . rejectedWith (
'Unable to retrieve installation path to app'
) ;
} ) ;
it ( 'returns resolved promise with appPath, displayName and icon' , async function ( ) {
const appInfo = await app . getApplicationInfoForProtocol ( 'https://' ) ;
expect ( appInfo . path ) . not . to . be . undefined ( ) ;
expect ( appInfo . name ) . not . to . be . undefined ( ) ;
expect ( appInfo . icon ) . not . to . be . undefined ( ) ;
} ) ;
} ) ;
2019-11-07 01:50:33 +00:00
describe ( 'isDefaultProtocolClient()' , ( ) = > {
it ( 'returns false for a bogus protocol' , ( ) = > {
expect ( app . isDefaultProtocolClient ( 'bogus-protocol://' ) ) . to . equal ( false ) ;
} ) ;
2017-02-02 16:11:34 +00:00
} ) ;
2016-11-06 10:59:17 +00:00
2021-03-16 21:02:47 +00:00
ifdescribe ( process . platform === 'win32' ) ( 'app launch through uri' , ( ) = > {
2020-06-30 22:10:36 +00:00
it ( 'does not launch for argument following a URL' , async ( ) = > {
2019-03-10 22:38:44 +00:00
const appPath = path . join ( fixturesPath , 'api' , 'quit-app' ) ;
2018-01-22 22:49:30 +00:00
// App should exit with non 123 code.
2019-03-10 22:38:44 +00:00
const first = cp . spawn ( process . execPath , [ appPath , 'electron-test:?' , 'abc' ] ) ;
2023-02-23 23:53:53 +00:00
const [ code ] = await once ( first , 'exit' ) ;
2020-06-30 22:10:36 +00:00
expect ( code ) . to . not . equal ( 123 ) ;
2018-01-22 22:49:30 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'launches successfully for argument following a file path' , async ( ) = > {
2019-03-10 22:38:44 +00:00
const appPath = path . join ( fixturesPath , 'api' , 'quit-app' ) ;
2018-01-22 22:49:30 +00:00
// App should exit with code 123.
2019-03-10 22:38:44 +00:00
const first = cp . spawn ( process . execPath , [ appPath , 'e:\\abc' , 'abc' ] ) ;
2023-02-23 23:53:53 +00:00
const [ code ] = await once ( first , 'exit' ) ;
2020-06-30 22:10:36 +00:00
expect ( code ) . to . equal ( 123 ) ;
2018-01-22 22:49:30 +00:00
} ) ;
2020-06-30 22:10:36 +00:00
it ( 'launches successfully for multiple URIs following --' , async ( ) = > {
2019-03-10 22:38:44 +00:00
const appPath = path . join ( fixturesPath , 'api' , 'quit-app' ) ;
2018-05-22 16:51:03 +00:00
// App should exit with code 123.
2019-03-10 22:38:44 +00:00
const first = cp . spawn ( process . execPath , [ appPath , '--' , 'http://electronjs.org' , 'electron-test://testdata' ] ) ;
2023-02-23 23:53:53 +00:00
const [ code ] = await once ( first , 'exit' ) ;
2020-06-30 22:10:36 +00:00
expect ( code ) . to . equal ( 123 ) ;
2018-01-22 22:49:30 +00:00
} ) ;
} ) ;
2019-10-30 23:38:21 +00:00
// FIXME Get these specs running on Linux CI
ifdescribe ( process . platform !== 'linux' ) ( 'getFileIcon() API' , ( ) = > {
2016-11-10 18:34:30 +00:00
const iconPath = path . join ( __dirname , 'fixtures/assets/icon.ico' ) ;
2016-11-06 10:59:17 +00:00
const sizes = {
small : 16 ,
normal : 32 ,
2017-02-07 19:20:27 +00:00
large : process.platform === 'win32' ? 32 : 48
2016-11-06 11:03:16 +00:00
} ;
2016-11-06 10:59:17 +00:00
2018-12-05 16:50:12 +00:00
it ( 'fetches a non-empty icon' , async ( ) = > {
const icon = await app . getFileIcon ( iconPath ) ;
2019-03-10 22:38:44 +00:00
expect ( icon . isEmpty ( ) ) . to . equal ( false ) ;
2016-11-06 10:59:17 +00:00
} ) ;
2018-12-05 16:50:12 +00:00
it ( 'fetches normal icon size by default' , async ( ) = > {
const icon = await app . getFileIcon ( iconPath ) ;
const size = icon . getSize ( ) ;
2018-06-14 16:44:27 +00:00
2018-12-05 16:50:12 +00:00
expect ( size . height ) . to . equal ( sizes . normal ) ;
expect ( size . width ) . to . equal ( sizes . normal ) ;
2016-11-06 10:59:17 +00:00
} ) ;
2017-10-27 20:45:58 +00:00
describe ( 'size option' , ( ) = > {
2018-12-05 16:50:12 +00:00
it ( 'fetches a small icon' , async ( ) = > {
const icon = await app . getFileIcon ( iconPath , { size : 'small' } ) ;
const size = icon . getSize ( ) ;
expect ( size . height ) . to . equal ( sizes . small ) ;
expect ( size . width ) . to . equal ( sizes . small ) ;
2016-11-06 10:59:17 +00:00
} ) ;
2018-12-05 16:50:12 +00:00
it ( 'fetches a normal icon' , async ( ) = > {
const icon = await app . getFileIcon ( iconPath , { size : 'normal' } ) ;
const size = icon . getSize ( ) ;
expect ( size . height ) . to . equal ( sizes . normal ) ;
expect ( size . width ) . to . equal ( sizes . normal ) ;
2016-11-06 10:59:17 +00:00
} ) ;
2018-12-05 16:50:12 +00:00
it ( 'fetches a large icon' , async ( ) = > {
2017-02-07 18:16:09 +00:00
// macOS does not support large icons
2018-12-05 16:50:12 +00:00
if ( process . platform === 'darwin' ) return ;
2017-02-07 18:16:09 +00:00
2018-12-05 16:50:12 +00:00
const icon = await app . getFileIcon ( iconPath , { size : 'large' } ) ;
const size = icon . getSize ( ) ;
expect ( size . height ) . to . equal ( sizes . large ) ;
expect ( size . width ) . to . equal ( sizes . large ) ;
2016-11-06 10:59:17 +00:00
} ) ;
} ) ;
2017-04-27 15:38:17 +00:00
} ) ;
2017-04-27 04:04:53 +00:00
2018-08-09 18:35:29 +00:00
describe ( 'getAppMetrics() API' , ( ) = > {
2018-06-18 04:00:17 +00:00
it ( 'returns memory and cpu stats of all running electron processes' , ( ) = > {
2017-05-16 00:41:45 +00:00
const appMetrics = app . getAppMetrics ( ) ;
2018-06-14 16:44:27 +00:00
expect ( appMetrics ) . to . be . an ( 'array' ) . and . have . lengthOf . at . least ( 1 , 'App memory info object is not > 0' ) ;
2017-05-26 15:53:26 +00:00
const types = [ ] ;
2019-06-14 19:39:55 +00:00
for ( const entry of appMetrics ) {
expect ( entry . pid ) . to . be . above ( 0 , 'pid is not > 0' ) ;
expect ( entry . type ) . to . be . a ( 'string' ) . that . does . not . equal ( '' ) ;
expect ( entry . creationTime ) . to . be . a ( 'number' ) . that . is . greaterThan ( 0 ) ;
2018-06-14 16:44:27 +00:00
2019-06-14 19:39:55 +00:00
types . push ( entry . type ) ;
expect ( entry . cpu ) . to . have . ownProperty ( 'percentCPUUsage' ) . that . is . a ( 'number' ) ;
expect ( entry . cpu ) . to . have . ownProperty ( 'idleWakeupsPerSecond' ) . that . is . a ( 'number' ) ;
2019-07-23 20:41:59 +00:00
expect ( entry . memory ) . to . have . property ( 'workingSetSize' ) . that . is . greaterThan ( 0 ) ;
expect ( entry . memory ) . to . have . property ( 'peakWorkingSetSize' ) . that . is . greaterThan ( 0 ) ;
2020-10-19 11:55:47 +00:00
if ( entry . type === 'Utility' || entry . type === 'GPU' ) {
expect ( entry . serviceName ) . to . be . a ( 'string' ) . that . does . not . equal ( '' ) ;
}
2020-07-07 18:00:45 +00:00
if ( entry . type === 'Utility' ) {
expect ( entry ) . to . have . property ( 'name' ) . that . is . a ( 'string' ) ;
}
2019-07-23 20:41:59 +00:00
if ( process . platform === 'win32' ) {
expect ( entry . memory ) . to . have . property ( 'privateBytes' ) . that . is . greaterThan ( 0 ) ;
}
2019-06-14 19:39:55 +00:00
if ( process . platform !== 'linux' ) {
expect ( entry . sandboxed ) . to . be . a ( 'boolean' ) ;
}
if ( process . platform === 'win32' ) {
expect ( entry . integrityLevel ) . to . be . a ( 'string' ) ;
}
2017-05-04 20:43:45 +00:00
}
2017-05-26 15:53:26 +00:00
2017-05-26 17:10:56 +00:00
if ( process . platform === 'darwin' ) {
2018-06-14 16:44:27 +00:00
expect ( types ) . to . include ( 'GPU' ) ;
2017-05-26 16:14:17 +00:00
}
2018-06-14 16:44:27 +00:00
expect ( types ) . to . include ( 'Browser' ) ;
2017-04-27 04:04:53 +00:00
} ) ;
2016-11-06 10:59:17 +00:00
} ) ;
2017-05-30 20:00:00 +00:00
2017-10-27 20:45:58 +00:00
describe ( 'getGPUFeatureStatus() API' , ( ) = > {
it ( 'returns the graphic features statuses' , ( ) = > {
2017-05-30 20:00:00 +00:00
const features = app . getGPUFeatureStatus ( ) ;
2019-03-10 22:38:44 +00:00
expect ( features ) . to . have . ownProperty ( 'webgl' ) . that . is . a ( 'string' ) ;
expect ( features ) . to . have . ownProperty ( 'gpu_compositing' ) . that . is . a ( 'string' ) ;
2017-05-30 20:00:00 +00:00
} ) ;
} ) ;
2017-06-28 15:33:06 +00:00
2020-06-22 17:35:10 +00:00
// FIXME https://github.com/electron/electron/issues/24224
ifdescribe ( process . platform !== 'linux' ) ( 'getGPUInfo() API' , ( ) = > {
2019-03-10 22:38:44 +00:00
const appPath = path . join ( fixturesPath , 'api' , 'gpu-info.js' ) ;
2018-10-02 01:34:52 +00:00
2019-03-10 22:38:44 +00:00
const getGPUInfo = async ( type : string ) = > {
const appProcess = cp . spawn ( process . execPath , [ appPath , type ] ) ;
2018-10-02 01:34:52 +00:00
let gpuInfoData = '' ;
let errorData = '' ;
appProcess . stdout . on ( 'data' , ( data ) = > {
gpuInfoData += data ;
} ) ;
appProcess . stderr . on ( 'data' , ( data ) = > {
errorData += data ;
} ) ;
2023-02-23 23:53:53 +00:00
const [ exitCode ] = await once ( appProcess , 'exit' ) ;
2018-10-02 01:34:52 +00:00
if ( exitCode === 0 ) {
2021-06-22 19:17:16 +00:00
try {
const [ , json ] = /HERE COMES THE JSON: (.+) AND THERE IT WAS/ . exec ( gpuInfoData ) ! ;
// return info data on successful exit
return JSON . parse ( json ) ;
} catch ( e ) {
console . error ( 'Failed to interpret the following as JSON:' ) ;
console . error ( gpuInfoData ) ;
throw e ;
}
2018-10-02 01:34:52 +00:00
} else {
// return error if not clean exit
2023-07-31 08:39:37 +00:00
throw new Error ( errorData ) ;
2018-10-01 02:57:38 +00:00
}
2018-10-02 01:34:52 +00:00
} ;
2019-03-10 22:38:44 +00:00
const verifyBasicGPUInfo = async ( gpuInfo : any ) = > {
2018-10-02 01:34:52 +00:00
// Devices information is always present in the available info.
2019-03-10 22:38:44 +00:00
expect ( gpuInfo ) . to . have . ownProperty ( 'gpuDevice' )
2018-10-02 01:34:52 +00:00
. that . is . an ( 'array' )
2019-03-10 22:38:44 +00:00
. and . does . not . equal ( [ ] ) ;
2018-10-02 01:34:52 +00:00
const device = gpuInfo . gpuDevice [ 0 ] ;
expect ( device ) . to . be . an ( 'object' )
. and . to . have . property ( 'deviceId' )
. that . is . a ( 'number' )
. not . lessThan ( 0 ) ;
} ;
2018-10-01 02:57:38 +00:00
2018-10-02 01:34:52 +00:00
it ( 'succeeds with basic GPUInfo' , async ( ) = > {
const gpuInfo = await getGPUInfo ( 'basic' ) ;
await verifyBasicGPUInfo ( gpuInfo ) ;
2018-09-27 14:59:23 +00:00
} ) ;
2018-10-15 15:26:47 +00:00
it ( 'succeeds with complete GPUInfo' , async ( ) = > {
2018-10-02 01:34:52 +00:00
const completeInfo = await getGPUInfo ( 'complete' ) ;
2018-10-15 15:26:47 +00:00
if ( process . platform === 'linux' ) {
2018-10-08 04:06:50 +00:00
// For linux and macOS complete info is same as basic info
2018-10-02 01:34:52 +00:00
await verifyBasicGPUInfo ( completeInfo ) ;
const basicInfo = await getGPUInfo ( 'basic' ) ;
expect ( completeInfo ) . to . deep . equal ( basicInfo ) ;
} else {
// Gl version is present in the complete info.
2019-03-10 22:38:44 +00:00
expect ( completeInfo ) . to . have . ownProperty ( 'auxAttributes' )
2018-10-02 01:34:52 +00:00
. that . is . an ( 'object' ) ;
2020-03-03 21:35:05 +00:00
if ( completeInfo . gpuDevice . active ) {
expect ( completeInfo . auxAttributes ) . to . have . ownProperty ( 'glVersion' )
. that . is . a ( 'string' )
. and . does . not . equal ( [ ] ) ;
}
2018-10-02 01:34:52 +00:00
}
2018-09-27 14:59:23 +00:00
} ) ;
2018-10-02 01:34:52 +00:00
it ( 'fails for invalid info_type' , ( ) = > {
const invalidType = 'invalid' ;
2018-10-15 15:26:47 +00:00
const expectedErrorMessage = "Invalid info type. Use 'basic' or 'complete'" ;
2019-07-26 23:16:38 +00:00
return expect ( app . getGPUInfo ( invalidType as any ) ) . to . eventually . be . rejectedWith ( expectedErrorMessage ) ;
2018-09-27 14:59:23 +00:00
} ) ;
} ) ;
2023-04-04 13:48:51 +00:00
ifdescribe ( ! ( process . platform === 'linux' && ( process . arch === 'arm64' || process . arch === 'arm' ) ) ) ( 'sandbox options' , ( ) = > {
// Our ARM tests are run on VSTS rather than CircleCI, and the Docker
// setup on VSTS disallows syscalls that Chrome requires for setting up
// sandboxing.
// See:
// - https://docs.docker.com/engine/security/seccomp/#significant-syscalls-blocked-by-the-default-profile
// - https://chromium.googlesource.com/chromium/src/+/70.0.3538.124/sandbox/linux/services/credentials.cc#292
// - https://github.com/docker/docker-ce/blob/ba7dfc59ccfe97c79ee0d1379894b35417b40bca/components/engine/profiles/seccomp/seccomp_default.go#L497
// - https://blog.jessfraz.com/post/how-to-use-new-docker-seccomp-profiles/
//
// Adding `--cap-add SYS_ADMIN` or `--security-opt seccomp=unconfined`
// to the Docker invocation allows the syscalls that Chrome needs, but
// are probably more permissive than we'd like.
2019-03-10 22:38:44 +00:00
let appProcess : cp.ChildProcess = null as any ;
let server : net.Server = null as any ;
2017-06-28 16:27:19 +00:00
const socketPath = process . platform === 'win32' ? '\\\\.\\pipe\\electron-mixed-sandbox' : '/tmp/electron-mixed-sandbox' ;
2017-06-28 15:33:06 +00:00
2017-11-15 21:05:46 +00:00
beforeEach ( function ( done ) {
2017-06-28 16:27:19 +00:00
fs . unlink ( socketPath , ( ) = > {
server = net . createServer ( ) ;
server . listen ( socketPath ) ;
done ( ) ;
} ) ;
} ) ;
2018-06-14 16:44:27 +00:00
afterEach ( done = > {
2017-10-27 20:45:58 +00:00
if ( appProcess != null ) appProcess . kill ( ) ;
2017-06-28 16:27:19 +00:00
2023-02-03 01:40:30 +00:00
if ( server ) {
server . close ( ( ) = > {
if ( process . platform === 'win32' ) {
done ( ) ;
} else {
fs . unlink ( socketPath , ( ) = > done ( ) ) ;
}
} ) ;
} else {
done ( ) ;
}
2017-06-28 15:33:06 +00:00
} ) ;
2018-10-10 04:32:09 +00:00
describe ( 'when app.enableSandbox() is called' , ( ) = > {
2021-03-16 21:02:47 +00:00
it ( 'adds --enable-sandbox to all renderer processes' , done = > {
2019-03-10 22:38:44 +00:00
const appPath = path . join ( fixturesPath , 'api' , 'mixed-sandbox-app' ) ;
2022-02-10 02:58:52 +00:00
appProcess = cp . spawn ( process . execPath , [ appPath , '--app-enable-sandbox' ] , { stdio : 'inherit' } ) ;
2018-10-10 04:32:09 +00:00
server . once ( 'error' , error = > { done ( error ) ; } ) ;
server . on ( 'connection' , client = > {
2019-03-10 22:38:44 +00:00
client . once ( 'data' , ( data ) = > {
const argv = JSON . parse ( data . toString ( ) ) ;
2018-10-10 04:32:09 +00:00
expect ( argv . sandbox ) . to . include ( '--enable-sandbox' ) ;
expect ( argv . sandbox ) . to . not . include ( '--no-sandbox' ) ;
expect ( argv . noSandbox ) . to . include ( '--enable-sandbox' ) ;
expect ( argv . noSandbox ) . to . not . include ( '--no-sandbox' ) ;
2019-03-10 22:38:44 +00:00
expect ( argv . noSandboxDevtools ) . to . equal ( true ) ;
expect ( argv . sandboxDevtools ) . to . equal ( true ) ;
2018-10-10 04:32:09 +00:00
done ( ) ;
} ) ;
} ) ;
} ) ;
} ) ;
describe ( 'when the app is launched with --enable-sandbox' , ( ) = > {
2021-03-16 21:02:47 +00:00
it ( 'adds --enable-sandbox to all renderer processes' , done = > {
2019-03-10 22:38:44 +00:00
const appPath = path . join ( fixturesPath , 'api' , 'mixed-sandbox-app' ) ;
2022-02-10 02:58:52 +00:00
appProcess = cp . spawn ( process . execPath , [ appPath , '--enable-sandbox' ] , { stdio : 'inherit' } ) ;
2018-10-10 04:32:09 +00:00
server . once ( 'error' , error = > { done ( error ) ; } ) ;
server . on ( 'connection' , client = > {
client . once ( 'data' , data = > {
2019-03-10 22:38:44 +00:00
const argv = JSON . parse ( data . toString ( ) ) ;
2018-10-10 04:32:09 +00:00
expect ( argv . sandbox ) . to . include ( '--enable-sandbox' ) ;
expect ( argv . sandbox ) . to . not . include ( '--no-sandbox' ) ;
expect ( argv . noSandbox ) . to . include ( '--enable-sandbox' ) ;
expect ( argv . noSandbox ) . to . not . include ( '--no-sandbox' ) ;
2019-03-10 22:38:44 +00:00
expect ( argv . noSandboxDevtools ) . to . equal ( true ) ;
expect ( argv . sandboxDevtools ) . to . equal ( true ) ;
2018-10-10 04:32:09 +00:00
done ( ) ;
} ) ;
} ) ;
} ) ;
} ) ;
2017-06-28 15:33:06 +00:00
} ) ;
2017-07-13 22:27:03 +00:00
2017-10-27 20:45:58 +00:00
describe ( 'disableDomainBlockingFor3DAPIs() API' , ( ) = > {
it ( 'throws when called after app is ready' , ( ) = > {
2018-06-14 16:44:27 +00:00
expect ( ( ) = > {
2017-07-13 22:27:03 +00:00
app . disableDomainBlockingFor3DAPIs ( ) ;
2018-06-14 16:44:27 +00:00
} ) . to . throw ( /before app is ready/ ) ;
2017-07-13 22:27:03 +00:00
} ) ;
} ) ;
2018-02-27 06:15:06 +00:00
2022-03-30 01:34:07 +00:00
ifdescribe ( process . platform === 'darwin' ) ( 'app hide and show API' , ( ) = > {
describe ( 'app.isHidden' , ( ) = > {
it ( 'returns true when the app is hidden' , async ( ) = > {
app . hide ( ) ;
await expect (
waitUntil ( ( ) = > app . isHidden ( ) )
) . to . eventually . be . fulfilled ( ) ;
} ) ;
it ( 'returns false when the app is shown' , async ( ) = > {
app . show ( ) ;
await expect (
waitUntil ( ( ) = > ! app . isHidden ( ) )
) . to . eventually . be . fulfilled ( ) ;
} ) ;
} ) ;
} ) ;
2023-04-04 13:48:51 +00:00
ifdescribe ( process . platform === 'darwin' ) ( 'dock APIs' , ( ) = > {
2019-03-10 22:38:44 +00:00
after ( async ( ) = > {
await app . dock . show ( ) ;
} ) ;
2019-02-14 22:29:20 +00:00
describe ( 'dock.setMenu' , ( ) = > {
it ( 'can be retrieved via dock.getMenu' , ( ) = > {
expect ( app . dock . getMenu ( ) ) . to . equal ( null ) ;
const menu = new Menu ( ) ;
app . dock . setMenu ( menu ) ;
expect ( app . dock . getMenu ( ) ) . to . equal ( menu ) ;
} ) ;
2019-02-13 05:06:33 +00:00
2019-02-14 22:29:20 +00:00
it ( 'keeps references to the menu' , ( ) = > {
2019-02-13 05:06:33 +00:00
app . dock . setMenu ( new Menu ( ) ) ;
2020-06-23 03:32:45 +00:00
const v8Util = process . _linkedBinding ( 'electron_common_v8_util' ) ;
2019-02-13 05:06:33 +00:00
v8Util . requestGarbageCollectionForTesting ( ) ;
} ) ;
2018-02-27 06:15:06 +00:00
} ) ;
2021-01-04 20:58:31 +00:00
describe ( 'dock.setIcon' , ( ) = > {
it ( 'throws a descriptive error for a bad icon path' , ( ) = > {
const badPath = path . resolve ( 'I' , 'Do' , 'Not' , 'Exist' ) ;
expect ( ( ) = > {
app . dock . setIcon ( badPath ) ;
} ) . to . throw ( /Failed to load image from path (.+)/ ) ;
} ) ;
} ) ;
2019-02-14 22:29:20 +00:00
describe ( 'dock.bounce' , ( ) = > {
it ( 'should return -1 for unknown bounce type' , ( ) = > {
2019-03-10 22:38:44 +00:00
expect ( app . dock . bounce ( 'bad type' as any ) ) . to . equal ( - 1 ) ;
2019-02-14 22:29:20 +00:00
} ) ;
it ( 'should return a positive number for informational type' , ( ) = > {
const appHasFocus = ! ! BrowserWindow . getFocusedWindow ( ) ;
if ( ! appHasFocus ) {
expect ( app . dock . bounce ( 'informational' ) ) . to . be . at . least ( 0 ) ;
}
} ) ;
it ( 'should return a positive number for critical type' , ( ) = > {
const appHasFocus = ! ! BrowserWindow . getFocusedWindow ( ) ;
if ( ! appHasFocus ) {
expect ( app . dock . bounce ( 'critical' ) ) . to . be . at . least ( 0 ) ;
}
} ) ;
} ) ;
describe ( 'dock.cancelBounce' , ( ) = > {
it ( 'should not throw' , ( ) = > {
app . dock . cancelBounce ( app . dock . bounce ( 'critical' ) ) ;
} ) ;
} ) ;
describe ( 'dock.setBadge' , ( ) = > {
after ( ( ) = > {
app . dock . setBadge ( '' ) ;
} ) ;
it ( 'should not throw' , ( ) = > {
app . dock . setBadge ( '1' ) ;
} ) ;
it ( 'should be retrievable via getBadge' , ( ) = > {
app . dock . setBadge ( 'test' ) ;
expect ( app . dock . getBadge ( ) ) . to . equal ( 'test' ) ;
} ) ;
} ) ;
2020-09-03 11:46:24 +00:00
describe ( 'dock.hide' , ( ) = > {
it ( 'should not throw' , ( ) = > {
app . dock . hide ( ) ;
expect ( app . dock . isVisible ( ) ) . to . equal ( false ) ;
} ) ;
} ) ;
// Note that dock.show tests should run after dock.hide tests, to work
// around a bug of macOS.
// See https://github.com/electron/electron/pull/25269 for more.
2019-02-14 22:29:20 +00:00
describe ( 'dock.show' , ( ) = > {
it ( 'should not throw' , ( ) = > {
return app . dock . show ( ) . then ( ( ) = > {
expect ( app . dock . isVisible ( ) ) . to . equal ( true ) ;
} ) ;
2019-02-13 05:06:33 +00:00
} ) ;
it ( 'returns a Promise' , ( ) = > {
expect ( app . dock . show ( ) ) . to . be . a ( 'promise' ) ;
} ) ;
2019-03-10 22:38:44 +00:00
it ( 'eventually fulfills' , async ( ) = > {
await expect ( app . dock . show ( ) ) . to . eventually . be . fulfilled . equal ( undefined ) ;
2019-02-13 05:06:33 +00:00
} ) ;
2018-02-27 06:15:06 +00:00
} ) ;
} ) ;
2018-04-20 07:09:23 +00:00
describe ( 'whenReady' , ( ) = > {
it ( 'returns a Promise' , ( ) = > {
2018-06-14 16:44:27 +00:00
expect ( app . whenReady ( ) ) . to . be . a ( 'promise' ) ;
2018-04-20 07:09:23 +00:00
} ) ;
2019-03-15 00:22:42 +00:00
it ( 'becomes fulfilled if the app is already ready' , async ( ) = > {
2019-03-10 22:38:44 +00:00
expect ( app . isReady ( ) ) . to . equal ( true ) ;
2019-03-15 00:22:42 +00:00
await expect ( app . whenReady ( ) ) . to . be . eventually . fulfilled . equal ( undefined ) ;
2018-04-20 07:09:23 +00:00
} ) ;
} ) ;
2019-01-07 15:48:27 +00:00
2019-04-02 20:36:57 +00:00
describe ( 'app.applicationMenu' , ( ) = > {
it ( 'has the applicationMenu property' , ( ) = > {
expect ( app ) . to . have . property ( 'applicationMenu' ) ;
} ) ;
} ) ;
2019-01-07 15:48:27 +00:00
describe ( 'commandLine.hasSwitch' , ( ) = > {
it ( 'returns true when present' , ( ) = > {
app . commandLine . appendSwitch ( 'foobar1' ) ;
2019-03-10 22:38:44 +00:00
expect ( app . commandLine . hasSwitch ( 'foobar1' ) ) . to . equal ( true ) ;
2019-01-07 15:48:27 +00:00
} ) ;
it ( 'returns false when not present' , ( ) = > {
2019-03-10 22:38:44 +00:00
expect ( app . commandLine . hasSwitch ( 'foobar2' ) ) . to . equal ( false ) ;
2019-01-07 15:48:27 +00:00
} ) ;
} ) ;
2021-04-09 07:09:17 +00:00
describe ( 'commandLine.hasSwitch (existing argv)' , ( ) = > {
2019-01-07 15:48:27 +00:00
it ( 'returns true when present' , async ( ) = > {
2019-01-15 20:35:53 +00:00
const { hasSwitch } = await runTestApp ( 'command-line' , '--foobar' ) ;
2019-03-10 22:38:44 +00:00
expect ( hasSwitch ) . to . equal ( true ) ;
2019-01-07 15:48:27 +00:00
} ) ;
it ( 'returns false when not present' , async ( ) = > {
2019-01-15 20:35:53 +00:00
const { hasSwitch } = await runTestApp ( 'command-line' ) ;
2019-03-10 22:38:44 +00:00
expect ( hasSwitch ) . to . equal ( false ) ;
2019-01-07 15:48:27 +00:00
} ) ;
} ) ;
describe ( 'commandLine.getSwitchValue' , ( ) = > {
it ( 'returns the value when present' , ( ) = > {
app . commandLine . appendSwitch ( 'foobar' , 'æøåü' ) ;
expect ( app . commandLine . getSwitchValue ( 'foobar' ) ) . to . equal ( 'æøåü' ) ;
} ) ;
it ( 'returns an empty string when present without value' , ( ) = > {
app . commandLine . appendSwitch ( 'foobar1' ) ;
expect ( app . commandLine . getSwitchValue ( 'foobar1' ) ) . to . equal ( '' ) ;
} ) ;
it ( 'returns an empty string when not present' , ( ) = > {
expect ( app . commandLine . getSwitchValue ( 'foobar2' ) ) . to . equal ( '' ) ;
} ) ;
} ) ;
2021-04-09 07:09:17 +00:00
describe ( 'commandLine.getSwitchValue (existing argv)' , ( ) = > {
2019-01-07 15:48:27 +00:00
it ( 'returns the value when present' , async ( ) = > {
2019-01-15 20:35:53 +00:00
const { getSwitchValue } = await runTestApp ( 'command-line' , '--foobar=test' ) ;
2019-01-07 15:48:27 +00:00
expect ( getSwitchValue ) . to . equal ( 'test' ) ;
} ) ;
it ( 'returns an empty string when present without value' , async ( ) = > {
2019-01-15 20:35:53 +00:00
const { getSwitchValue } = await runTestApp ( 'command-line' , '--foobar' ) ;
2019-01-07 15:48:27 +00:00
expect ( getSwitchValue ) . to . equal ( '' ) ;
} ) ;
it ( 'returns an empty string when not present' , async ( ) = > {
2019-01-15 20:35:53 +00:00
const { getSwitchValue } = await runTestApp ( 'command-line' ) ;
2019-01-07 15:48:27 +00:00
expect ( getSwitchValue ) . to . equal ( '' ) ;
} ) ;
} ) ;
2020-05-21 15:53:44 +00:00
2021-10-06 20:45:58 +00:00
describe ( 'commandLine.removeSwitch' , ( ) = > {
it ( 'no-ops a non-existent switch' , async ( ) = > {
expect ( app . commandLine . hasSwitch ( 'foobar3' ) ) . to . equal ( false ) ;
app . commandLine . removeSwitch ( 'foobar3' ) ;
expect ( app . commandLine . hasSwitch ( 'foobar3' ) ) . to . equal ( false ) ;
} ) ;
it ( 'removes an existing switch' , async ( ) = > {
app . commandLine . appendSwitch ( 'foobar3' , 'test' ) ;
expect ( app . commandLine . hasSwitch ( 'foobar3' ) ) . to . equal ( true ) ;
app . commandLine . removeSwitch ( 'foobar3' ) ;
expect ( app . commandLine . hasSwitch ( 'foobar3' ) ) . to . equal ( false ) ;
} ) ;
} ) ;
2020-05-21 15:53:44 +00:00
ifdescribe ( process . platform === 'darwin' ) ( 'app.setSecureKeyboardEntryEnabled' , ( ) = > {
it ( 'changes Secure Keyboard Entry is enabled' , ( ) = > {
app . setSecureKeyboardEntryEnabled ( true ) ;
expect ( app . isSecureKeyboardEntryEnabled ( ) ) . to . equal ( true ) ;
app . setSecureKeyboardEntryEnabled ( false ) ;
expect ( app . isSecureKeyboardEntryEnabled ( ) ) . to . equal ( false ) ;
} ) ;
} ) ;
2021-08-31 18:55:30 +00:00
describe ( 'configureHostResolver' , ( ) = > {
after ( ( ) = > {
// Returns to the default configuration.
app . configureHostResolver ( { } ) ;
} ) ;
it ( 'fails on bad arguments' , ( ) = > {
expect ( ( ) = > {
( app . configureHostResolver as any ) ( ) ;
} ) . to . throw ( ) ;
expect ( ( ) = > {
app . configureHostResolver ( {
secureDnsMode : 'notAValidValue' as any
} ) ;
} ) . to . throw ( ) ;
expect ( ( ) = > {
app . configureHostResolver ( {
secureDnsServers : [ 123 as any ]
} ) ;
} ) . to . throw ( ) ;
} ) ;
it ( 'affects dns lookup behavior' , async ( ) = > {
// 1. resolve a domain name to check that things are working
await expect ( new Promise ( ( resolve , reject ) = > {
electronNet . request ( {
method : 'HEAD' ,
url : 'https://www.electronjs.org'
} ) . on ( 'response' , resolve )
. on ( 'error' , reject )
. end ( ) ;
} ) ) . to . eventually . be . fulfilled ( ) ;
// 2. change the host resolver configuration to something that will
// always fail
app . configureHostResolver ( {
secureDnsMode : 'secure' ,
secureDnsServers : [ 'https://127.0.0.1:1234' ]
} ) ;
// 3. check that resolving domain names now fails
await expect ( new Promise ( ( resolve , reject ) = > {
electronNet . request ( {
method : 'HEAD' ,
// Needs to be a slightly different domain to above, otherwise the
// response will come from the cache.
url : 'https://electronjs.org'
} ) . on ( 'response' , resolve )
. on ( 'error' , reject )
. end ( ) ;
} ) ) . to . eventually . be . rejectedWith ( /ERR_NAME_NOT_RESOLVED/ ) ;
} ) ;
} ) ;
2023-02-28 22:26:00 +00:00
describe ( 'about panel' , ( ) = > {
it ( 'app.setAboutPanelOptions() does not crash' , ( ) = > {
app . setAboutPanelOptions ( {
applicationName : 'electron!!' ,
version : '1.2.3'
} ) ;
} ) ;
2023-03-06 14:46:35 +00:00
it ( 'app.showAboutPanel() does not crash & runs asynchronously' , ( ) = > {
app . showAboutPanel ( ) ;
} ) ;
2023-02-28 22:26:00 +00:00
} ) ;
2019-01-15 20:35:53 +00:00
} ) ;
2019-01-07 15:48:27 +00:00
2021-04-09 07:09:17 +00:00
describe ( 'default behavior' , ( ) = > {
2019-01-15 20:35:53 +00:00
describe ( 'application menu' , ( ) = > {
it ( 'creates the default menu if the app does not set it' , async ( ) = > {
const result = await runTestApp ( 'default-menu' ) ;
expect ( result ) . to . equal ( false ) ;
} ) ;
2019-01-07 15:48:27 +00:00
2019-01-15 20:35:53 +00:00
it ( 'does not create the default menu if the app sets a custom menu' , async ( ) = > {
const result = await runTestApp ( 'default-menu' , '--custom-menu' ) ;
expect ( result ) . to . equal ( true ) ;
} ) ;
2019-01-07 15:48:27 +00:00
2019-01-15 20:35:53 +00:00
it ( 'does not create the default menu if the app sets a null menu' , async ( ) = > {
const result = await runTestApp ( 'default-menu' , '--null-menu' ) ;
expect ( result ) . to . equal ( true ) ;
} ) ;
} ) ;
describe ( 'window-all-closed' , ( ) = > {
2021-04-28 17:55:08 +00:00
afterEach ( closeAllWindows ) ;
2019-01-15 20:35:53 +00:00
it ( 'quits when the app does not handle the event' , async ( ) = > {
const result = await runTestApp ( 'window-all-closed' ) ;
expect ( result ) . to . equal ( false ) ;
} ) ;
2019-01-07 15:48:27 +00:00
2019-01-15 20:35:53 +00:00
it ( 'does not quit when the app handles the event' , async ( ) = > {
const result = await runTestApp ( 'window-all-closed' , '--handle-event' ) ;
expect ( result ) . to . equal ( true ) ;
} ) ;
2021-04-28 17:55:08 +00:00
it ( 'should omit closed windows from getAllWindows' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
const len = new Promise ( resolve = > {
app . on ( 'window-all-closed' , ( ) = > {
resolve ( BrowserWindow . getAllWindows ( ) . length ) ;
} ) ;
} ) ;
w . close ( ) ;
expect ( await len ) . to . equal ( 0 ) ;
} ) ;
2019-01-15 20:35:53 +00:00
} ) ;
2019-05-01 23:34:42 +00:00
describe ( 'user agent fallback' , ( ) = > {
let initialValue : string ;
before ( ( ) = > {
initialValue = app . userAgentFallback ! ;
} ) ;
it ( 'should have a reasonable default' , ( ) = > {
expect ( initialValue ) . to . include ( ` Electron/ ${ process . versions . electron } ` ) ;
expect ( initialValue ) . to . include ( ` Chrome/ ${ process . versions . chrome } ` ) ;
} ) ;
it ( 'should be overridable' , ( ) = > {
app . userAgentFallback = 'test-agent/123' ;
expect ( app . userAgentFallback ) . to . equal ( 'test-agent/123' ) ;
} ) ;
it ( 'should be restorable' , ( ) = > {
app . userAgentFallback = 'test-agent/123' ;
app . userAgentFallback = '' ;
expect ( app . userAgentFallback ) . to . equal ( initialValue ) ;
} ) ;
} ) ;
2019-05-31 22:47:18 +00:00
2019-11-11 17:47:01 +00:00
describe ( 'login event' , ( ) = > {
afterEach ( closeAllWindows ) ;
let server : http.Server ;
let serverUrl : string ;
2023-02-20 11:30:57 +00:00
before ( async ( ) = > {
2019-11-11 17:47:01 +00:00
server = http . createServer ( ( request , response ) = > {
if ( request . headers . authorization ) {
return response . end ( 'ok' ) ;
}
response
. writeHead ( 401 , { 'WWW-Authenticate' : 'Basic realm="Foo"' } )
. end ( ) ;
} ) ;
2023-02-20 11:30:57 +00:00
serverUrl = ( await listen ( server ) ) . url ;
2019-11-11 17:47:01 +00:00
} ) ;
it ( 'should emit a login event on app when a WebContents hits a 401' , async ( ) = > {
const w = new BrowserWindow ( { show : false } ) ;
w . loadURL ( serverUrl ) ;
2023-06-22 18:38:52 +00:00
const [ , webContents ] = await once ( app , 'login' ) as [ any , WebContents ] ;
2019-11-11 17:47:01 +00:00
expect ( webContents ) . to . equal ( w . webContents ) ;
} ) ;
} ) ;
2021-06-02 07:16:33 +00:00
describe ( 'running under ARM64 translation' , ( ) = > {
it ( 'does not throw an error' , ( ) = > {
if ( process . platform === 'darwin' || process . platform === 'win32' ) {
expect ( app . runningUnderARM64Translation ) . not . to . be . undefined ( ) ;
expect ( ( ) = > {
return app . runningUnderARM64Translation ;
} ) . not . to . throw ( ) ;
} else {
expect ( app . runningUnderARM64Translation ) . to . be . undefined ( ) ;
}
} ) ;
} ) ;
2016-03-25 19:57:17 +00:00
} ) ;
2019-01-15 20:35:53 +00:00
2019-03-10 22:38:44 +00:00
async function runTestApp ( name : string , . . . args : any [ ] ) {
const appPath = path . join ( fixturesPath , 'api' , name ) ;
const electronPath = process . execPath ;
2019-01-15 20:35:53 +00:00
const appProcess = cp . spawn ( electronPath , [ appPath , . . . args ] ) ;
let output = '' ;
appProcess . stdout . on ( 'data' , ( data ) = > { output += data ; } ) ;
2023-02-23 23:53:53 +00:00
await once ( appProcess . stdout , 'end' ) ;
2019-01-15 20:35:53 +00:00
return JSON . parse ( output ) ;
}