diff --git a/javascript/selenium-webdriver/chrome.js b/javascript/selenium-webdriver/chrome.js
index 9d644ba9666f6..6e2766a45f21f 100644
--- a/javascript/selenium-webdriver/chrome.js
+++ b/javascript/selenium-webdriver/chrome.js
@@ -128,6 +128,12 @@ const { Browser } = require('./lib/capabilities')
const chromium = require('./chromium')
const CHROME_CAPABILITY_KEY = 'goog:chromeOptions'
+/**
+ * Environment variable that defines the location of the ChromeDriver executable.
+ * @const {string}
+ */
+const CHROME_DRIVER_EXE_ENV_VAR = 'SE_CHROMEDRIVER'
+
/** @type {remote.DriverService} */
/**
@@ -138,14 +144,16 @@ const CHROME_CAPABILITY_KEY = 'goog:chromeOptions'
class ServiceBuilder extends chromium.ServiceBuilder {
/**
* @param {string=} opt_exe Path to the server executable to use. If omitted,
- * the builder will attempt to locate the chromedriver on the current
+ * the builder will attempt to use the chromedriver path from the
+ * SE_CHROMEDRIVER environment variable, then locate the chromedriver on the current
* PATH. If the chromedriver is not available in path, selenium-manager will
* download the chromedriver
* @throws {Error} If provided executable does not exist, or the chromedriver
* cannot be found on the PATH.
*/
constructor(opt_exe) {
- super(opt_exe)
+ let exePath = opt_exe || process.env[CHROME_DRIVER_EXE_ENV_VAR]
+ super(exePath)
}
}
diff --git a/javascript/selenium-webdriver/edge.js b/javascript/selenium-webdriver/edge.js
index 7b633804f6831..d6f297e289d78 100644
--- a/javascript/selenium-webdriver/edge.js
+++ b/javascript/selenium-webdriver/edge.js
@@ -83,6 +83,12 @@ const { Browser } = require('./lib/capabilities')
const chromium = require('./chromium')
const EDGE_CAPABILITY_KEY = 'ms:edgeOptions'
+/**
+ * Environment variable that defines the location of the MSEdgeDriver executable.
+ * @const {string}
+ */
+const EDGE_DRIVER_EXE_ENV_VAR = 'SE_EDGEDRIVER'
+
/** @type {remote.DriverService} */
/**
@@ -93,13 +99,14 @@ const EDGE_CAPABILITY_KEY = 'ms:edgeOptions'
class ServiceBuilder extends chromium.ServiceBuilder {
/**
* @param {string=} opt_exe Path to the server executable to use. If omitted,
- * the builder will attempt to locate the msedgedriver on the current
+ * the builder will attempt to use the msedgedriver path from the
+ * SE_EDGEDRIVER environment variable, then locate the msedgedriver on the current
* PATH.
* @throws {Error} If provided executable does not exist, or the msedgedriver
* cannot be found on the PATH.
*/
constructor(opt_exe) {
- super(opt_exe)
+ super(opt_exe || process.env[EDGE_DRIVER_EXE_ENV_VAR])
this.setLoopback(true)
}
}
diff --git a/javascript/selenium-webdriver/firefox.js b/javascript/selenium-webdriver/firefox.js
index d97500398fb99..e715d8a59379a 100644
--- a/javascript/selenium-webdriver/firefox.js
+++ b/javascript/selenium-webdriver/firefox.js
@@ -124,6 +124,12 @@ const { getBinaryPaths } = require('./common/driverFinder')
const { findFreePort } = require('./net/portprober')
const FIREFOX_CAPABILITY_KEY = 'moz:firefoxOptions'
+/**
+ * Environment variable that defines the location of the GeckoDriver executable.
+ * @const {string}
+ */
+const GECKO_DRIVER_EXE_ENV_VAR = 'SE_GECKODRIVER'
+
/**
* Thrown when there an add-on is malformed.
* @final
@@ -489,10 +495,12 @@ function configureExecutor(executor) {
class ServiceBuilder extends remote.DriverService.Builder {
/**
* @param {string=} opt_exe Path to the server executable to use. If omitted,
- * the builder will attempt to locate the geckodriver on the system PATH.
+ * the builder will attempt to use the geckodriver path from the
+ * SE_GECKODRIVER environment variable, then locate the geckodriver on the system PATH.
*/
constructor(opt_exe) {
- super(opt_exe)
+ let exePath = opt_exe || process.env[GECKO_DRIVER_EXE_ENV_VAR]
+ super(exePath)
this.setLoopback(true) // Required.
}
diff --git a/javascript/selenium-webdriver/ie.js b/javascript/selenium-webdriver/ie.js
index d4615d49a38bd..9bb28377dfa9b 100644
--- a/javascript/selenium-webdriver/ie.js
+++ b/javascript/selenium-webdriver/ie.js
@@ -38,6 +38,7 @@ const error = require('./lib/error')
const { getBinaryPaths } = require('./common/driverFinder')
const OPTIONS_CAPABILITY_KEY = 'se:ieOptions'
+const IE_DRIVER_EXE_ENV_VAR = 'SE_IEDRIVER'
const SCROLL_BEHAVIOUR = {
BOTTOM: 1,
TOP: 0,
@@ -422,10 +423,11 @@ function createServiceFromCapabilities(capabilities) {
class ServiceBuilder extends remote.DriverService.Builder {
/**
* @param {string=} opt_exe Path to the server executable to use. If omitted,
- * the builder will attempt to locate the IEDriverServer on the system PATH.
+ * the builder will attempt to use the IEDriverServer path from the
+ * SE_IEDRIVER environment variable, then locate the IEDriverServer on the system PATH.
*/
constructor(opt_exe) {
- super(opt_exe)
+ super(opt_exe || process.env[IE_DRIVER_EXE_ENV_VAR])
this.setLoopback(true) // Required.
}
}
diff --git a/javascript/selenium-webdriver/safari.js b/javascript/selenium-webdriver/safari.js
index bc1b9508942e3..f23ac4fc39c90 100644
--- a/javascript/selenium-webdriver/safari.js
+++ b/javascript/selenium-webdriver/safari.js
@@ -29,6 +29,12 @@ const webdriver = require('./lib/webdriver')
const { Browser, Capabilities } = require('./lib/capabilities')
const { getBinaryPaths } = require('./common/driverFinder')
+/**
+ * Environment variable that defines the location of the SafariDriver executable.
+ * @const {string}
+ */
+const SAFARI_DRIVER_EXE_ENV_VAR = 'SE_SAFARIDRIVER'
+
/**
* Creates {@link remote.DriverService} instances that manage
* a [safaridriver] server in a child process.
@@ -38,10 +44,11 @@ const { getBinaryPaths } = require('./common/driverFinder')
class ServiceBuilder extends remote.DriverService.Builder {
/**
* @param {string=} opt_exe Path to the server executable to use. If omitted,
- * the builder will attempt to locate the safaridriver on the system PATH.
+ * the builder will attempt to use the safaridriver path from the
+ * SE_SAFARIDRIVER environment variable, then locate the safaridriver on the system PATH.
*/
constructor(opt_exe) {
- super(opt_exe)
+ super(opt_exe || process.env[SAFARI_DRIVER_EXE_ENV_VAR])
this.setLoopback(true) // Required.
}
}
diff --git a/javascript/selenium-webdriver/test/chrome/service_test.js b/javascript/selenium-webdriver/test/chrome/service_test.js
index 7dc1b953a739a..0714d02c0c207 100644
--- a/javascript/selenium-webdriver/test/chrome/service_test.js
+++ b/javascript/selenium-webdriver/test/chrome/service_test.js
@@ -41,6 +41,64 @@ test.suite(
assert.ok(url.endsWith('/foo/bar/baz'), 'unexpected url: ' + url)
})
})
+
+ describe('environment variable support', function () {
+ let originalEnvValue
+
+ beforeEach(function () {
+ originalEnvValue = process.env.SE_CHROMEDRIVER
+ })
+
+ afterEach(function () {
+ if (originalEnvValue) {
+ process.env.SE_CHROMEDRIVER = originalEnvValue
+ } else {
+ delete process.env.SE_CHROMEDRIVER
+ }
+ })
+
+ it('uses SE_CHROMEDRIVER environment variable when set', function () {
+ const testPath = '/custom/path/to/chromedriver'
+ process.env.SE_CHROMEDRIVER = testPath
+
+ const serviceBuilder = new chrome.ServiceBuilder()
+ const service = serviceBuilder.build()
+ assert.strictEqual(service.getExecutable(), testPath)
+ })
+
+ it('explicit path overrides environment variable', function () {
+ const envPath = '/env/path/to/chromedriver'
+ const explicitPath = '/explicit/path/to/chromedriver'
+
+ process.env.SE_CHROMEDRIVER = envPath
+ const serviceBuilder = new chrome.ServiceBuilder(explicitPath)
+ const service = serviceBuilder.build()
+
+ assert.strictEqual(service.getExecutable(), explicitPath)
+ })
+
+ it('falls back to default behavior when environment variable is not set', function () {
+ delete process.env.SE_CHROMEDRIVER
+
+ const serviceBuilder = new chrome.ServiceBuilder()
+ const service = serviceBuilder.build()
+ // Should be null/undefined when no explicit path and no env var
+ assert.ok(!service.getExecutable())
+ })
+
+ it('environment variable ignores selenium manager', function () {
+ // This test mimics Java's environmentVariableIgnoresSeleniumManager test
+ const testDriverPath = '/custom/path/to/chromedriver'
+ process.env.SE_CHROMEDRIVER = testDriverPath
+
+ // Create ServiceBuilder without explicit path (null equivalent)
+ const serviceBuilder = new chrome.ServiceBuilder()
+ const service = serviceBuilder.build()
+
+ // Verify that the environment variable path is used
+ assert.strictEqual(service.getExecutable(), testDriverPath)
+ })
+ })
})
},
{ browsers: ['chrome'] },
diff --git a/javascript/selenium-webdriver/test/edge/service_test.js b/javascript/selenium-webdriver/test/edge/service_test.js
index 1b6c302ac2058..0e2bc7bbaab9b 100644
--- a/javascript/selenium-webdriver/test/edge/service_test.js
+++ b/javascript/selenium-webdriver/test/edge/service_test.js
@@ -39,6 +39,51 @@ test.suite(
let url = await service.start()
assert(/127\.0\.0\.1/.test(url), `unexpected url: ${url}`)
})
+
+ describe('environment variable support', function () {
+ let originalEnvValue
+
+ beforeEach(function () {
+ originalEnvValue = process.env.SE_EDGEDRIVER
+ })
+
+ afterEach(function () {
+ if (originalEnvValue) {
+ process.env.SE_EDGEDRIVER = originalEnvValue
+ } else {
+ delete process.env.SE_EDGEDRIVER
+ }
+ })
+
+ it('uses SE_EDGEDRIVER environment variable when set', function () {
+ const testPath = '/custom/path/to/edgedriver'
+ process.env.SE_EDGEDRIVER = testPath
+
+ const serviceBuilder = new edge.ServiceBuilder()
+ const service = serviceBuilder.build()
+ assert.strictEqual(service.getExecutable(), testPath)
+ })
+
+ it('explicit path overrides environment variable', function () {
+ const envPath = '/env/path/to/edgedriver'
+ const explicitPath = '/explicit/path/to/edgedriver'
+
+ process.env.SE_EDGEDRIVER = envPath
+ const serviceBuilder = new edge.ServiceBuilder(explicitPath)
+ const service = serviceBuilder.build()
+
+ assert.strictEqual(service.getExecutable(), explicitPath)
+ })
+
+ it('falls back to default behavior when environment variable is not set', function () {
+ delete process.env.SE_EDGEDRIVER
+
+ const serviceBuilder = new edge.ServiceBuilder()
+ const service = serviceBuilder.build()
+ // Should be null/undefined when no explicit path and no env var
+ assert.ok(!service.getExecutable())
+ })
+ })
})
},
{ browsers: ['MicrosoftEdge'] },
diff --git a/javascript/selenium-webdriver/test/firefox/service_test.js b/javascript/selenium-webdriver/test/firefox/service_test.js
new file mode 100644
index 0000000000000..337559f7e70df
--- /dev/null
+++ b/javascript/selenium-webdriver/test/firefox/service_test.js
@@ -0,0 +1,103 @@
+// Licensed to the Software Freedom Conservancy (SFC) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The SFC licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+'use strict'
+
+const assert = require('node:assert')
+const firefox = require('selenium-webdriver/firefox')
+const test = require('../../lib/test')
+const { getBinaryPaths } = require('selenium-webdriver/common/driverFinder')
+
+test.suite(
+ function (_env) {
+ describe('geckodriver', function () {
+ let service
+
+ afterEach(function () {
+ if (service) {
+ return service.kill()
+ }
+ })
+
+ it('can start geckodriver', async function () {
+ service = new firefox.ServiceBuilder().build()
+ service.setExecutable(getBinaryPaths(new firefox.Options()).driverPath)
+ let url = await service.start()
+ assert(/127\.0\.0\.1/.test(url), `unexpected url: ${url}`)
+ })
+
+ describe('environment variable support', function () {
+ let originalEnvValue
+
+ beforeEach(function () {
+ originalEnvValue = process.env.SE_GECKODRIVER
+ })
+
+ afterEach(function () {
+ if (originalEnvValue) {
+ process.env.SE_GECKODRIVER = originalEnvValue
+ } else {
+ delete process.env.SE_GECKODRIVER
+ }
+ })
+
+ it('uses SE_GECKODRIVER environment variable when set', function () {
+ const testPath = '/custom/path/to/geckodriver'
+ process.env.SE_GECKODRIVER = testPath
+
+ const serviceBuilder = new firefox.ServiceBuilder()
+ const service = serviceBuilder.build()
+ assert.strictEqual(service.getExecutable(), testPath)
+ })
+
+ it('explicit path overrides environment variable', function () {
+ const envPath = '/env/path/to/geckodriver'
+ const explicitPath = '/explicit/path/to/geckodriver'
+
+ process.env.SE_GECKODRIVER = envPath
+ const serviceBuilder = new firefox.ServiceBuilder(explicitPath)
+ const service = serviceBuilder.build()
+
+ assert.strictEqual(service.getExecutable(), explicitPath)
+ })
+
+ it('falls back to default behavior when environment variable is not set', function () {
+ delete process.env.SE_GECKODRIVER
+
+ const serviceBuilder = new firefox.ServiceBuilder()
+ const service = serviceBuilder.build()
+ // Should be null/undefined when no explicit path and no env var
+ assert.ok(!service.getExecutable())
+ })
+
+ it('environment variable ignores selenium manager', function () {
+ // This test mimics Java's environmentVariableIgnoresSeleniumManager test
+ const testDriverPath = '/custom/path/to/geckodriver'
+ process.env.SE_GECKODRIVER = testDriverPath
+
+ // Create ServiceBuilder without explicit path (null equivalent)
+ const serviceBuilder = new firefox.ServiceBuilder()
+ const service = serviceBuilder.build()
+
+ // Verify that the environment variable path is used
+ assert.strictEqual(service.getExecutable(), testDriverPath)
+ })
+ })
+ })
+ },
+ { browsers: ['firefox'] },
+)
diff --git a/javascript/selenium-webdriver/test/ie/service_test.js b/javascript/selenium-webdriver/test/ie/service_test.js
new file mode 100644
index 0000000000000..b7b9123c32a76
--- /dev/null
+++ b/javascript/selenium-webdriver/test/ie/service_test.js
@@ -0,0 +1,93 @@
+// Licensed to the Software Freedom Conservancy (SFC) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The SFC licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+'use strict'
+
+const assert = require('node:assert')
+const ie = require('selenium-webdriver/ie')
+const test = require('../../lib/test')
+const { getBinaryPaths } = require('selenium-webdriver/common/driverFinder')
+
+test.suite(
+ function (_env) {
+ describe('iedriver', function () {
+ let service
+
+ afterEach(function () {
+ if (service) {
+ return service.kill()
+ }
+ })
+
+ it('can start iedriver', async function () {
+ // Skip on non-Windows platforms
+ if (process.platform !== 'win32') {
+ this.skip()
+ return
+ }
+
+ service = new ie.ServiceBuilder().build()
+ service.setExecutable(getBinaryPaths(new ie.Options()).driverPath)
+ let url = await service.start()
+ assert(/127\.0\.0\.1/.test(url), `unexpected url: ${url}`)
+ })
+
+ describe('environment variable support', function () {
+ let originalEnvValue
+
+ beforeEach(function () {
+ originalEnvValue = process.env.SE_IEDRIVER
+ })
+
+ afterEach(function () {
+ if (originalEnvValue) {
+ process.env.SE_IEDRIVER = originalEnvValue
+ } else {
+ delete process.env.SE_IEDRIVER
+ }
+ })
+
+ it('uses SE_IEDRIVER environment variable when set', function () {
+ const testPath = '/custom/path/to/iedriver'
+ process.env.SE_IEDRIVER = testPath
+
+ const serviceBuilder = new ie.ServiceBuilder()
+ assert.strictEqual(serviceBuilder.getExecutable(), testPath)
+ })
+
+ it('explicit path overrides environment variable', function () {
+ const envPath = '/env/path/to/iedriver'
+ const explicitPath = '/explicit/path/to/iedriver'
+
+ process.env.SE_IEDRIVER = envPath
+ const serviceBuilder = new ie.ServiceBuilder(explicitPath)
+
+ assert.strictEqual(serviceBuilder.getExecutable(), explicitPath)
+ })
+
+ it('falls back to default behavior when environment variable is not set', function () {
+ delete process.env.SE_IEDRIVER
+
+ const serviceBuilder = new ie.ServiceBuilder()
+ // Should be null/undefined when no explicit path and no env var
+ assert.ok(!serviceBuilder.getExecutable())
+ })
+ })
+ })
+ },
+ { browsers: ['ie'] },
+)
diff --git a/javascript/selenium-webdriver/test/safari_test.js b/javascript/selenium-webdriver/test/safari_test.js
index 98f164ce959df..93df671035331 100644
--- a/javascript/selenium-webdriver/test/safari_test.js
+++ b/javascript/selenium-webdriver/test/safari_test.js
@@ -38,6 +38,51 @@ test.suite(
let url = await service.start()
assert(/127\.0\.0\.1/.test(url), `unexpected url: ${url}`)
})
+
+ describe('environment variable support', function () {
+ let originalEnvValue
+
+ beforeEach(function () {
+ originalEnvValue = process.env.SE_SAFARIDRIVER
+ })
+
+ afterEach(function () {
+ if (originalEnvValue) {
+ process.env.SE_SAFARIDRIVER = originalEnvValue
+ } else {
+ delete process.env.SE_SAFARIDRIVER
+ }
+ })
+
+ it('uses SE_SAFARIDRIVER environment variable when set', function () {
+ const testPath = '/custom/path/to/safaridriver'
+ process.env.SE_SAFARIDRIVER = testPath
+
+ const serviceBuilder = new safari.ServiceBuilder()
+ const service = serviceBuilder.build()
+ assert.strictEqual(service.getExecutable(), testPath)
+ })
+
+ it('explicit path overrides environment variable', function () {
+ const envPath = '/env/path/to/safaridriver'
+ const explicitPath = '/explicit/path/to/safaridriver'
+
+ process.env.SE_SAFARIDRIVER = envPath
+ const serviceBuilder = new safari.ServiceBuilder(explicitPath)
+ const service = serviceBuilder.build()
+
+ assert.strictEqual(service.getExecutable(), explicitPath)
+ })
+
+ it('falls back to default behavior when environment variable is not set', function () {
+ delete process.env.SE_SAFARIDRIVER
+
+ const serviceBuilder = new safari.ServiceBuilder()
+ const service = serviceBuilder.build()
+ // Should be null/undefined when no explicit path and no env var
+ assert.ok(!service.getExecutable())
+ })
+ })
})
},
{ browsers: ['safari'] },