2020-08-26 16:34:29 +00:00
import { BrowserWindow , app } from 'electron/main' ;
2020-04-07 00:04:09 +00:00
import { shell } from 'electron/common' ;
2023-01-25 21:01:25 +00:00
import { closeAllWindows } from './lib/window-helpers' ;
2023-02-20 11:30:57 +00:00
import { ifdescribe , ifit , listen } from './lib/spec-helpers' ;
2023-06-15 14:42:27 +00:00
import * as http from 'node:http' ;
2024-06-28 17:13:46 +00:00
import * as fs from 'node:fs' ;
2023-06-15 14:42:27 +00:00
import * as os from 'node:os' ;
import * as path from 'node:path' ;
2020-08-26 16:34:29 +00:00
import { expect } from 'chai' ;
2023-06-15 14:42:27 +00:00
import { once } from 'node:events' ;
2019-09-04 18:12:31 +00:00
describe ( 'shell module' , ( ) = > {
describe ( 'shell.openExternal()' , ( ) = > {
2020-03-20 20:28:31 +00:00
let envVars : Record < string , string | undefined > = { } ;
2019-09-04 18:12:31 +00:00
beforeEach ( function ( ) {
envVars = {
display : process.env.DISPLAY ,
de : process.env.DE ,
browser : process.env.BROWSER
2020-03-20 20:28:31 +00:00
} ;
} ) ;
2019-09-04 18:12:31 +00:00
afterEach ( async ( ) = > {
// reset env vars to prevent side effects
if ( process . platform === 'linux' ) {
2020-03-20 20:28:31 +00:00
process . env . DE = envVars . de ;
process . env . BROWSER = envVars . browser ;
process . env . DISPLAY = envVars . display ;
2019-09-04 18:12:31 +00:00
}
2020-03-20 20:28:31 +00:00
} ) ;
afterEach ( closeAllWindows ) ;
2019-09-04 18:12:31 +00:00
2024-04-23 19:12:46 +00:00
async function urlOpened ( ) {
2020-03-20 20:28:31 +00:00
let url = 'http://127.0.0.1' ;
2021-01-22 19:25:47 +00:00
let requestReceived : Promise < any > ;
2019-09-04 18:12:31 +00:00
if ( process . platform === 'linux' ) {
2020-03-20 20:28:31 +00:00
process . env . BROWSER = '/bin/true' ;
process . env . DE = 'generic' ;
process . env . DISPLAY = '' ;
requestReceived = Promise . resolve ( ) ;
2019-09-04 18:12:31 +00:00
} else if ( process . platform === 'darwin' ) {
// On the Mac CI machines, Safari tries to ask for a password to the
// code signing keychain we set up to test code signing (see
// https://github.com/electron/electron/pull/19969#issuecomment-526278890),
// so use a blur event as a crude proxy.
2020-03-20 20:28:31 +00:00
const w = new BrowserWindow ( { show : true } ) ;
2023-02-23 23:53:53 +00:00
requestReceived = once ( w , 'blur' ) ;
2019-09-04 18:12:31 +00:00
} else {
const server = http . createServer ( ( req , res ) = > {
2020-03-20 20:28:31 +00:00
res . end ( ) ;
} ) ;
2023-02-20 11:30:57 +00:00
url = ( await listen ( server ) ) . url ;
2021-01-22 19:25:47 +00:00
requestReceived = new Promise < void > ( resolve = > server . on ( 'connection' , ( ) = > resolve ( ) ) ) ;
2019-09-04 18:12:31 +00:00
}
2024-04-23 19:12:46 +00:00
return { url , requestReceived } ;
}
2019-09-04 18:12:31 +00:00
2024-04-23 19:12:46 +00:00
it ( 'opens an external link' , async ( ) = > {
const { url , requestReceived } = await urlOpened ( ) ;
2021-01-22 19:25:47 +00:00
await Promise . all < void > ( [
2019-09-04 18:12:31 +00:00
shell . openExternal ( url ) ,
requestReceived
2020-03-20 20:28:31 +00:00
] ) ;
} ) ;
2024-04-23 19:12:46 +00:00
it ( 'opens an external link in the renderer' , async ( ) = > {
const { url , requestReceived } = await urlOpened ( ) ;
const w = new BrowserWindow ( { show : false , webPreferences : { sandbox : false , contextIsolation : false , nodeIntegration : true } } ) ;
await w . loadURL ( 'about:blank' ) ;
await Promise . all < void > ( [
w . webContents . executeJavaScript ( ` require("electron").shell.openExternal( ${ JSON . stringify ( url ) } ) ` ) ,
requestReceived
] ) ;
} ) ;
2020-03-20 20:28:31 +00:00
} ) ;
2020-08-26 16:34:29 +00:00
2020-09-02 17:32:33 +00:00
describe ( 'shell.trashItem()' , ( ) = > {
2021-04-22 20:46:41 +00:00
afterEach ( closeAllWindows ) ;
2020-09-02 17:32:33 +00:00
it ( 'moves an item to the trash' , async ( ) = > {
2024-06-28 17:13:46 +00:00
const dir = await fs . promises . mkdtemp ( path . resolve ( app . getPath ( 'temp' ) , 'electron-shell-spec-' ) ) ;
2020-09-02 17:32:33 +00:00
const filename = path . join ( dir , 'temp-to-be-deleted' ) ;
2024-06-28 17:13:46 +00:00
await fs . promises . writeFile ( filename , 'dummy-contents' ) ;
2020-09-02 17:32:33 +00:00
await shell . trashItem ( filename ) ;
expect ( fs . existsSync ( filename ) ) . to . be . false ( ) ;
} ) ;
it ( 'throws when called with a nonexistent path' , async ( ) = > {
const filename = path . join ( app . getPath ( 'temp' ) , 'does-not-exist' ) ;
await expect ( shell . trashItem ( filename ) ) . to . eventually . be . rejected ( ) ;
} ) ;
2021-04-22 20:46:41 +00:00
2021-04-27 21:35:31 +00:00
ifit ( ! ( process . platform === 'win32' && process . arch === 'ia32' ) ) ( 'works in the renderer process' , async ( ) = > {
2021-04-22 20:46:41 +00:00
const w = new BrowserWindow ( { show : false , webPreferences : { nodeIntegration : true , contextIsolation : false } } ) ;
w . loadURL ( 'about:blank' ) ;
await expect ( w . webContents . executeJavaScript ( 'require(\'electron\').shell.trashItem(\'does-not-exist\')' ) ) . to . be . rejectedWith ( /does-not-exist|Failed to move item|Failed to create FileOperation/ ) ;
} ) ;
2020-09-02 17:32:33 +00:00
} ) ;
2022-07-27 16:18:33 +00:00
const shortcutOptions = {
target : 'C:\\target' ,
description : 'description' ,
cwd : 'cwd' ,
args : 'args' ,
appUserModelId : 'appUserModelId' ,
icon : 'icon' ,
iconIndex : 1 ,
toastActivatorClsid : '{0E3CFA27-6FEA-410B-824F-A174B6E865E5}'
} ;
ifdescribe ( process . platform === 'win32' ) ( 'shell.readShortcutLink(shortcutPath)' , ( ) = > {
it ( 'throws when failed' , ( ) = > {
expect ( ( ) = > {
shell . readShortcutLink ( 'not-exist' ) ;
} ) . to . throw ( 'Failed to read shortcut link' ) ;
} ) ;
2022-08-16 19:23:13 +00:00
const fixtures = path . resolve ( __dirname , 'fixtures' ) ;
2022-07-27 16:18:33 +00:00
it ( 'reads all properties of a shortcut' , ( ) = > {
const shortcut = shell . readShortcutLink ( path . join ( fixtures , 'assets' , 'shortcut.lnk' ) ) ;
expect ( shortcut ) . to . deep . equal ( shortcutOptions ) ;
} ) ;
} ) ;
ifdescribe ( process . platform === 'win32' ) ( 'shell.writeShortcutLink(shortcutPath[, operation], options)' , ( ) = > {
const tmpShortcut = path . join ( os . tmpdir ( ) , ` ${ Date . now ( ) } .lnk ` ) ;
afterEach ( ( ) = > {
fs . unlinkSync ( tmpShortcut ) ;
} ) ;
it ( 'writes the shortcut' , ( ) = > {
expect ( shell . writeShortcutLink ( tmpShortcut , { target : 'C:\\' } ) ) . to . be . true ( ) ;
expect ( fs . existsSync ( tmpShortcut ) ) . to . be . true ( ) ;
} ) ;
it ( 'correctly sets the fields' , ( ) = > {
expect ( shell . writeShortcutLink ( tmpShortcut , shortcutOptions ) ) . to . be . true ( ) ;
expect ( shell . readShortcutLink ( tmpShortcut ) ) . to . deep . equal ( shortcutOptions ) ;
} ) ;
it ( 'updates the shortcut' , ( ) = > {
expect ( shell . writeShortcutLink ( tmpShortcut , 'update' , shortcutOptions ) ) . to . be . false ( ) ;
expect ( shell . writeShortcutLink ( tmpShortcut , 'create' , shortcutOptions ) ) . to . be . true ( ) ;
expect ( shell . readShortcutLink ( tmpShortcut ) ) . to . deep . equal ( shortcutOptions ) ;
const change = { target : 'D:\\' } ;
expect ( shell . writeShortcutLink ( tmpShortcut , 'update' , change ) ) . to . be . true ( ) ;
expect ( shell . readShortcutLink ( tmpShortcut ) ) . to . deep . equal ( { . . . shortcutOptions , . . . change } ) ;
} ) ;
it ( 'replaces the shortcut' , ( ) = > {
expect ( shell . writeShortcutLink ( tmpShortcut , 'replace' , shortcutOptions ) ) . to . be . false ( ) ;
expect ( shell . writeShortcutLink ( tmpShortcut , 'create' , shortcutOptions ) ) . to . be . true ( ) ;
expect ( shell . readShortcutLink ( tmpShortcut ) ) . to . deep . equal ( shortcutOptions ) ;
const change = {
target : 'D:\\' ,
description : 'description2' ,
cwd : 'cwd2' ,
args : 'args2' ,
appUserModelId : 'appUserModelId2' ,
icon : 'icon2' ,
iconIndex : 2 ,
toastActivatorClsid : '{C51A3996-CAD9-4934-848B-16285D4A1496}'
} ;
expect ( shell . writeShortcutLink ( tmpShortcut , 'replace' , change ) ) . to . be . true ( ) ;
expect ( shell . readShortcutLink ( tmpShortcut ) ) . to . deep . equal ( change ) ;
} ) ;
} ) ;
2020-03-20 20:28:31 +00:00
} ) ;