diff --git a/README.md b/README.md index 7cdc3f9..9618ed6 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ appWorkingDir | Optional working directory path for the application. prerun | An object containing either `script` or `command` key. The value of each key must be a valid PowerShell script or command to be executed prior to the WinAppDriver session startup. See [Power Shell commands execution](#power-shell-commands-execution) for more details. Example: `{script: 'Get-Process outlook -ErrorAction SilentlyContinue'}` postrun | An object containing either `script` or `command` key. The value of each key must be a valid PowerShell script or command to be executed after WinAppDriver session is stopped. See [Power Shell commands execution](#power-shell-commands-execution) for more details. isolatedScriptExecution | Whether PowerShell scripts are executed in an isolated session. Default is `false`. +appEnvironment | Optional object of custom environment variables to inject into the PowerShell session. The variables are only available for the lifetime of the session and do not affect the system environment. Example: `{"MY_VAR": "hello", "API_URL": "http://localhost:3000"}`. Please note that more capabilities will be added as the development of this driver progresses. Since it is still in its early stages, some features may be missing or subject to change. If you need a specific capability or encounter any issues, please feel free to open an issue. diff --git a/lib/commands/powershell.ts b/lib/commands/powershell.ts index ded7f2f..cf79005 100644 --- a/lib/commands/powershell.ts +++ b/lib/commands/powershell.ts @@ -12,7 +12,16 @@ const NULL_ROOT_ELEMENT = /* ps1 */ `$rootElement = $null`; const INIT_ELEMENT_TABLE = /* ps1 */ `$elementTable = New-Object System.Collections.Generic.Dictionary[[string]\`,[AutomationElement]]`; export async function startPowerShellSession(this: NovaWindowsDriver): Promise { - const powerShell = spawn('powershell.exe', ['-NoExit', '-Command', '-']); + const spawnEnv = this.caps.appEnvironment + ? { ...process.env, ...(this.caps.appEnvironment as Record) } + : process.env; + + if (this.caps.appEnvironment) { + const keys = Object.keys(this.caps.appEnvironment as Record); + this.log.info(`Applying appEnvironment variables to PowerShell session: ${keys.join(', ')}`); + } + + const powerShell = spawn('powershell.exe', ['-NoExit', '-Command', '-'], { env: spawnEnv }); powerShell.stdout.setEncoding('utf8'); powerShell.stderr.setEncoding('utf8'); @@ -93,7 +102,10 @@ export async function startPowerShellSession(this: NovaWindowsDriver): Promise { const magicNumber = 0xF2EE; - const powerShell = spawn('powershell.exe', ['-NoExit', '-Command', '-']); + const spawnEnv = this.caps.appEnvironment + ? { ...process.env, ...(this.caps.appEnvironment as Record) } + : process.env; + const powerShell = spawn('powershell.exe', ['-NoExit', '-Command', '-'], { env: spawnEnv }); try { powerShell.stdout.setEncoding('utf8'); powerShell.stdout.setEncoding('utf8'); diff --git a/lib/constraints.ts b/lib/constraints.ts index e2f82d6..7b466d5 100644 --- a/lib/constraints.ts +++ b/lib/constraints.ts @@ -36,6 +36,9 @@ export const UI_AUTOMATION_DRIVER_CONSTRAINTS = { isolatedScriptExecution: { isBoolean: true, }, + appEnvironment: { + isObject: true, + }, 'ms:waitForAppLaunch': { isNumber: true, }, diff --git a/test/e2e/session.e2e.ts b/test/e2e/session.e2e.ts index 788340f..9304a10 100644 --- a/test/e2e/session.e2e.ts +++ b/test/e2e/session.e2e.ts @@ -1,4 +1,4 @@ -import { existsSync, unlinkSync } from 'node:fs'; +import { existsSync, readFileSync, unlinkSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { beforeEach, describe, expect, it } from 'vitest'; @@ -136,6 +136,22 @@ describe('Session creation and capabilities', () => { if (existsSync(markerPath)) { unlinkSync(markerPath); } }); + it('passes appEnvironment variables into the PowerShell session', async () => { + const markerPath = join(tmpdir(), `novawindows-session-env-${Date.now()}.txt`); + const driver = await createRootSession({ + 'appium:appEnvironment': { NOVA_TEST_VAR: 'hello_from_env' }, + 'appium:prerun': { + script: `[System.IO.File]::WriteAllText('${markerPath}', $env:NOVA_TEST_VAR)`, + }, + }); + try { + expect(readFileSync(markerPath, 'utf8')).toBe('hello_from_env'); + } finally { + await quitSession(driver); + if (existsSync(markerPath)) { unlinkSync(markerPath); } + } + }); + it('throws when an unknown automationName is specified', async () => { const { remote } = await import('webdriverio'); await expect(