Skip to content

[rb] Allow to set environment variables when staring a browser#17395

Open
y-yagi wants to merge 6 commits into
SeleniumHQ:trunkfrom
y-yagi:allow_to_set_env
Open

[rb] Allow to set environment variables when staring a browser#17395
y-yagi wants to merge 6 commits into
SeleniumHQ:trunkfrom
y-yagi:allow_to_set_env

Conversation

@y-yagi
Copy link
Copy Markdown
Contributor

@y-yagi y-yagi commented Apr 26, 2026

🔗 Related Issues

None

💥 What does this PR do?

Currently, the environment variables used when launching a browser are the same as those of the Ruby process that performs the launch.

However, there are times when want to change the environment variables passed to a browser. In our case, LD_PRELOAD. We want to set LD_PRELOAD to use jemalloc in Ruby, but we want to avoid setting it for Chrome because using jemalloc can cause crashes or unstable behavior.

To address this issue, this PR fixes allow environment variables to be explicitly specified via the service.

🔧 Implementation Notes

🤖 AI assistance

  • No substantial AI assistance used
  • AI assisted (complete below)
    • Tool(s): Copilot agent
    • What was generated: all codes are generated by AI
    • I reviewed all AI output and can explain the change

💡 Additional Considerations

🔄 Types of changes

  • New feature (non-breaking change which adds functionality and tests!)

Copilot AI review requested due to automatic review settings April 26, 2026 03:44
@selenium-ci selenium-ci added the C-rb Ruby Bindings label Apr 26, 2026
@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Allow setting environment variables when starting a browser

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add ability to set environment variables when starting browser
• Allow explicit env variable configuration via Service class
• Pass env variables through ChildProcess to Process.spawn
• Add comprehensive unit tests for env variable handling

Grey Divider

File Changes

1. rb/lib/selenium/webdriver/common/child_process.rb ✨ Enhancement +3/-2

Add environment variable support to ChildProcess

• Add env attribute accessor to ChildProcess class
• Initialize @env instance variable as empty hash
• Pass @env hash as first argument to Process.spawn

rb/lib/selenium/webdriver/common/child_process.rb


2. rb/lib/selenium/webdriver/common/service.rb ✨ Enhancement +3/-2

Add environment variable parameter to Service

• Add env attribute accessor to Service class
• Add env parameter to initialize method with default nil
• Initialize @env instance variable with provided env or empty hash

rb/lib/selenium/webdriver/common/service.rb


3. rb/lib/selenium/webdriver/common/service_manager.rb ✨ Enhancement +2/-0

Pass environment variables to ChildProcess

• Extract env from config and store in instance variable
• Pass @env to ChildProcess instance in build_process method

rb/lib/selenium/webdriver/common/service_manager.rb


View more (2)
4. rb/spec/unit/selenium/webdriver/chrome/service_spec.rb 🧪 Tests +6/-0

Add Chrome service environment variable test

• Add test case verifying Service accepts and stores env parameter
• Test validates environment variables are properly set on service instance

rb/spec/unit/selenium/webdriver/chrome/service_spec.rb


5. rb/spec/unit/selenium/webdriver/common/child_process_spec.rb 🧪 Tests +25/-0

Add ChildProcess environment variable tests

• Add test verifying Process.spawn receives env variables correctly
• Add test verifying empty hash passed to Process.spawn by default
• Tests use mocking to verify spawn method receives correct arguments

rb/spec/unit/selenium/webdriver/common/child_process_spec.rb


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented Apr 26, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2)

Grey Divider


Action required

1. Tempfile redirection flake ✓ Resolved 🐞 Bug ☼ Reliability
Description
The new ChildProcess env-var spec redirects output to temp_file.path while the Tempfile is still
open; on Windows this commonly prevents the spawned process from opening the same path for writing,
causing intermittent EACCES/empty output failures. This can break CI on Windows even though the
production code is fine.
Code

rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[R57-61]

+        temp_file = Tempfile.new('selenium_test')
+        process.io = temp_file.path
+
+        process.start
+        process.wait
Evidence
The spec keeps the Tempfile open while asking ChildProcess to redirect stdout/stderr to the
Tempfile *path*; ChildProcess#start passes that path to Process.spawn redirection, which
requires opening the file for writing in the child process.

rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[53-68]
rb/lib/selenium/webdriver/common/child_process.rb[54-63]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
A unit test redirects child process output to `Tempfile#path` while the Tempfile is still open. On Windows, the open handle can prevent the spawned process from opening the same file path for redirection, making the spec flaky/failing.

### Issue Context
`ChildProcess#start` uses `Process.spawn(..., {%i[out err] => io})`. When `io` is a String path, Ruby will open that file path for redirection.

### Fix Focus Areas
- rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[53-68]
- rb/lib/selenium/webdriver/common/child_process.rb[54-63]

### Suggested change
Update the spec to avoid redirecting to an *open* Tempfile path:
- Option A: `temp_file.close` **before** `process.start`, and then read the file after `process.wait`.
- Option B (preferable): use `IO.pipe` and set `process.io = writer_io`, then read from the reader IO to assert the output (no filesystem + cross-platform).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Mocks used in child_process_spec 📘 Rule violation ⚙ Maintainability
Description
The newly added unit tests stub Process.spawn and Process.detach, which violates the requirement
to avoid mocks in tests and can reduce fidelity to real behavior.
Code

rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[R30-36]

+          allow(Process).to receive(:spawn).and_return(12_345)
+          allow(Process).to receive(:detach)
+
+          process.start
+
+          expect(Process).to have_received(:spawn).with({'FOO' => 'bar'}, 'echo', 'test', anything)
+        end
Evidence
PR Compliance ID 6 requires avoiding mocks in tests. The added test uses `allow(Process).to
receive(...) and then asserts have_received`, which is mock-based testing.

AGENTS.md
rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[30-36]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new unit tests for `ChildProcess#start` use mocks/stubs (`allow(Process).to receive(...)`) and mock assertions (`have_received`), which violates the project's guidance to avoid mocks in tests.

## Issue Context
This PR adds support for passing environment variables to `Process.spawn`. The tests currently validate this by stubbing Ruby's `Process` module.

## Fix Focus Areas
- rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[25-47]

## Suggested direction
- Prefer an integration-like unit test that executes a very small real command and inspects its output/environment (e.g., spawn a Ruby one-liner that prints `ENV['FOO']`) rather than mocking `Process.spawn`.
- If platform differences are a concern, gate the test appropriately (e.g., skip on Windows if needed) while still avoiding mocks.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Env value nil not typable 🐞 Bug ≡ Correctness
Description
The new RBS types for Service#env/ServiceManager/browser service constructors and
ChildProcess#env require Hash[String, String] (or Hash[String, String]?), which prevents typed
callers from passing per-key nil values to unset inherited environment variables. This is
incorrect/incomplete because the implementation forwards the env hash to Process.spawn without
coercion/validation, and Process.spawn supports nil values to remove variables.
Code

rb/sig/lib/selenium/webdriver/common/service.rbs[R54-60]

+      attr_accessor env: Hash[String, String]
+
      def env_path: -> String?

      alias extra_args args

-      def initialize: (?path: untyped?, ?port: untyped?, ?log: untyped?, ?args: untyped?) -> void
+      def initialize: (?path: untyped?, ?port: untyped?, ?log: untyped?, ?args: untyped?, ?env: Hash[String, String]?) -> void
Evidence
The provided evidence shows that Service stores the env hash as given (with no value
coercion/validation) and ServiceManager passes it into ChildProcess, where ChildProcess#start
passes @env directly as the env hash argument to Process.spawn. Because Process.spawn supports
env hashes with nil values on specific keys to unset variables, the current RBS signatures that
constrain values to String (or only allow the whole hash to be nil) do not match runtime
behavior and prevent typed callers from expressing the supported “unset” use case.

rb/sig/lib/selenium/webdriver/common/service.rbs[54-60]
rb/sig/lib/selenium/webdriver/common/service_manager.rbs[14-15]
rb/sig/lib/selenium/webdriver/firefox/service.rbs[12-12]
rb/sig/lib/selenium/webdriver/safari/service.rbs[12-12]
rb/lib/selenium/webdriver/common/service.rb[69-87]
rb/lib/selenium/webdriver/common/service_manager.rb[39-85]
rb/lib/selenium/webdriver/common/child_process.rb[54-60]
rb/sig/lib/selenium/webdriver/common/child_process.rbs[26-27]
Best Practice: Ruby Process.spawn env hash semantics

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The current RBS types for environment hashes across `Service`/`ServiceManager`/browser service constructors and `ChildProcess#env` constrain env values to `String` (`Hash[String, String]` or `Hash[String, String]?`), which disallows using `nil` for specific keys to unset inherited environment variables. The runtime path forwards these hashes to `Process.spawn` without validation, and `Process.spawn` supports per-key `nil` values for unsetting, so the RBS should be updated to accurately model that behavior.

## Issue Context
The env flow is `Service#env` -> `ServiceManager` -> `ChildProcess#env` -> `ChildProcess#start` -> `Process.spawn(env_hash, ...)`, and the env hash is passed through as-is (no coercion/validation). Since `Process.spawn` allows `nil` values in the env hash to remove variables, typed Ruby callers need the signatures to permit `nil` values per key; model this as `Hash[String, String?]` (and `Hash[String, String?]?` where the entire hash itself is optional), including updating any related ivar/accessor types.

## Fix Focus Areas
- rb/sig/lib/selenium/webdriver/common/service.rbs[22-23]
- rb/sig/lib/selenium/webdriver/common/service.rbs[54-55]
- rb/sig/lib/selenium/webdriver/common/service.rbs[60-60]
- rb/sig/lib/selenium/webdriver/common/service_manager.rbs[14-15]
- rb/sig/lib/selenium/webdriver/firefox/service.rbs[12-12]
- rb/sig/lib/selenium/webdriver/safari/service.rbs[12-12]
- rb/sig/lib/selenium/webdriver/common/child_process.rbs[14-15]
- rb/sig/lib/selenium/webdriver/common/child_process.rbs[26-27]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. env input not validated 📘 Rule violation ☼ Reliability
Description
Service#initialize accepts env: and passes it down to Process.spawn without validating
type/shape, which can lead to unclear runtime errors if callers pass a non-Hash or invalid values.
Code

rb/lib/selenium/webdriver/common/service.rb[R69-72]

+      def initialize(path: nil, port: nil, log: nil, args: nil, env: nil)
        port ||= self.class::DEFAULT_PORT
        args ||= []
        path ||= env_path
Evidence
PR Compliance ID 11 requires early validation of configuration inputs with clear exceptions. The new
env: parameter is accepted and stored as @env = env || {} without checking that env is a
Hash suitable for Process.spawn.

rb/lib/selenium/webdriver/common/service.rb[69-86]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`env:` is a new public-ish configuration input on `Service#initialize`, but it is not validated. If a caller passes an unexpected type (e.g., String, Array, nil-ish objects) or invalid env keys/values, failures will occur later (in `Process.spawn`) with non-actionable errors.

## Issue Context
The new feature is intended to let users pass environment variables to the driver/browser process. This is a configuration surface and should fail fast with a clear exception message when misused.

## Fix Focus Areas
- rb/lib/selenium/webdriver/common/service.rb[69-86]

## Suggested direction
- Add a type/shape check such as:
 - raise `ArgumentError, "env must be a Hash"` unless `env.nil? || env.is_a?(Hash)`
- Optionally validate that env keys/values are Strings (or respond to `to_str`) to match Ruby `Process.spawn` expectations, and raise with an actionable message if not.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Safari env unsupported 🐞 Bug ≡ Correctness
Description
The base Service now supports an env: keyword, but Safari::Service overrides initialize
without env:/**, so passing env: when constructing Safari’s service raises ArgumentError and
the feature can’t be used for Safari.
Code

rb/lib/selenium/webdriver/common/service.rb[69]

+      def initialize(path: nil, port: nil, log: nil, args: nil, env: nil)
Evidence
The PR adds env: support to the base Service initializer and exposes env via an accessor.
However, Safari::Service defines its own initialize signature without env: (and without **
to accept/forward unknown keywords), so callers cannot use the new option for Safari services.

rb/lib/selenium/webdriver/common/service.rb[60-89]
rb/lib/selenium/webdriver/safari/service.rb[23-32]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`Safari::Service` overrides `initialize` but does not accept/forward the new `env:` keyword supported by the base `WebDriver::Service`, preventing env customization for Safari and causing `ArgumentError` if `env:` is provided.

### Issue Context
Base `WebDriver::Service#initialize` now takes `env:` and stores it, and `ServiceManager` will use it to set the child process environment.

### Fix Focus Areas
- rb/lib/selenium/webdriver/safari/service.rb[23-32]
- rb/lib/selenium/webdriver/common/service.rb[60-89]

### Suggested fix
- Update `Safari::Service#initialize` to accept `env: nil` (or `**`), and call `super` with the forwarded keywords while preserving the existing `log`-unsupported behavior.
- (Optional) Add/extend a unit spec for `Safari::Service.new(env: {...})` verifying `service.env` is set.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Previous review results

Review updated until commit adcba78

Results up to commit 3725918


🐞 Bugs (1) 📘 Rule violations (2) 📎 Requirement gaps (0)


Action required
1. Mocks used in child_process_spec 📘 Rule violation ⚙ Maintainability
Description
The newly added unit tests stub Process.spawn and Process.detach, which violates the requirement
to avoid mocks in tests and can reduce fidelity to real behavior.
Code

rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[R30-36]

+          allow(Process).to receive(:spawn).and_return(12_345)
+          allow(Process).to receive(:detach)
+
+          process.start
+
+          expect(Process).to have_received(:spawn).with({'FOO' => 'bar'}, 'echo', 'test', anything)
+        end
Evidence
PR Compliance ID 6 requires avoiding mocks in tests. The added test uses `allow(Process).to
receive(...) and then asserts have_received`, which is mock-based testing.

AGENTS.md
rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[30-36]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new unit tests for `ChildProcess#start` use mocks/stubs (`allow(Process).to receive(...)`) and mock assertions (`have_received`), which violates the project's guidance to avoid mocks in tests.

## Issue Context
This PR adds support for passing environment variables to `Process.spawn`. The tests currently validate this by stubbing Ruby's `Process` module.

## Fix Focus Areas
- rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[25-47]

## Suggested direction
- Prefer an integration-like unit test that executes a very small real command and inspects its output/environment (e.g., spawn a Ruby one-liner that prints `ENV['FOO']`) rather than mocking `Process.spawn`.
- If platform differences are a concern, gate the test appropriately (e.g., skip on Windows if needed) while still avoiding mocks.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
2. env input not validated 📘 Rule violation ☼ Reliability
Description
Service#initialize accepts env: and passes it down to Process.spawn without validating
type/shape, which can lead to unclear runtime errors if callers pass a non-Hash or invalid values.
Code

rb/lib/selenium/webdriver/common/service.rb[R69-72]

+      def initialize(path: nil, port: nil, log: nil, args: nil, env: nil)
        port ||= self.class::DEFAULT_PORT
        args ||= []
        path ||= env_path
Evidence
PR Compliance ID 11 requires early validation of configuration inputs with clear exceptions. The new
env: parameter is accepted and stored as @env = env || {} without checking that env is a
Hash suitable for Process.spawn.

rb/lib/selenium/webdriver/common/service.rb[69-86]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`env:` is a new public-ish configuration input on `Service#initialize`, but it is not validated. If a caller passes an unexpected type (e.g., String, Array, nil-ish objects) or invalid env keys/values, failures will occur later (in `Process.spawn`) with non-actionable errors.

## Issue Context
The new feature is intended to let users pass environment variables to the driver/browser process. This is a configuration surface and should fail fast with a clear exception message when misused.

## Fix Focus Areas
- rb/lib/selenium/webdriver/common/service.rb[69-86]

## Suggested direction
- Add a type/shape check such as:
 - raise `ArgumentError, "env must be a Hash"` unless `env.nil? || env.is_a?(Hash)`
- Optionally validate that env keys/values are Strings (or respond to `to_str`) to match Ruby `Process.spawn` expectations, and raise with an actionable message if not.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Safari env unsupported 🐞 Bug ≡ Correctness
Description
The base Service now supports an env: keyword, but Safari::Service overrides initialize
without env:/**, so passing env: when constructing Safari’s service raises ArgumentError and
the feature can’t be used for Safari.
Code

rb/lib/selenium/webdriver/common/service.rb[69]

+      def initialize(path: nil, port: nil, log: nil, args: nil, env: nil)
Evidence
The PR adds env: support to the base Service initializer and exposes env via an accessor.
However, Safari::Service defines its own initialize signature without env: (and without **
to accept/forward unknown keywords), so callers cannot use the new option for Safari services.

rb/lib/selenium/webdriver/common/service.rb[60-89]
rb/lib/selenium/webdriver/safari/service.rb[23-32]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`Safari::Service` overrides `initialize` but does not accept/forward the new `env:` keyword supported by the base `WebDriver::Service`, preventing env customization for Safari and causing `ArgumentError` if `env:` is provided.

### Issue Context
Base `WebDriver::Service#initialize` now takes `env:` and stores it, and `ServiceManager` will use it to set the child process environment.

### Fix Focus Areas
- rb/lib/selenium/webdriver/safari/service.rb[23-32]
- rb/lib/selenium/webdriver/common/service.rb[60-89]

### Suggested fix
- Update `Safari::Service#initialize` to accept `env: nil` (or `**`), and call `super` with the forwarded keywords while preserving the existing `log`-unsupported behavior.
- (Optional) Add/extend a unit spec for `Safari::Service.new(env: {...})` verifying `service.env` is set.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 2fbb347


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)


Action required
1. Tempfile redirection flake ✓ Resolved 🐞 Bug ☼ Reliability
Description
The new ChildProcess env-var spec redirects output to temp_file.path while the Tempfile is still
open; on Windows this commonly prevents the spawned process from opening the same path for writing,
causing intermittent EACCES/empty output failures. This can break CI on Windows even though the
production code is fine.
Code

rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[R57-61]

+        temp_file = Tempfile.new('selenium_test')
+        process.io = temp_file.path
+
+        process.start
+        process.wait
Evidence
The spec keeps the Tempfile open while asking ChildProcess to redirect stdout/stderr to the
Tempfile *path*; ChildProcess#start passes that path to Process.spawn redirection, which
requires opening the file for writing in the child process.

rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[53-68]
rb/lib/selenium/webdriver/common/child_process.rb[54-63]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
A unit test redirects child process output to `Tempfile#path` while the Tempfile is still open. On Windows, the open handle can prevent the spawned process from opening the same file path for redirection, making the spec flaky/failing.

### Issue Context
`ChildProcess#start` uses `Process.spawn(..., {%i[out err] => io})`. When `io` is a String path, Ruby will open that file path for redirection.

### Fix Focus Areas
- rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[53-68]
- rb/lib/selenium/webdriver/common/child_process.rb[54-63]

### Suggested change
Update the spec to avoid redirecting to an *open* Tempfile path:
- Option A: `temp_file.close` **before** `process.start`, and then read the file after `process.wait`.
- Option B (preferable): use `IO.pipe` and set `process.io = writer_io`, then read from the reader IO to assert the output (no filesystem + cross-platform).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 5ccc267


🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)


Remediation recommended
1. Env value nil not typable 🐞 Bug ≡ Correctness
Description
The new RBS types for Service#env/ServiceManager/browser service constructors and
ChildProcess#env require Hash[String, String] (or Hash[String, String]?), which prevents typed
callers from passing per-key nil values to unset inherited environment variables. This is
incorrect/incomplete because the implementation forwards the env hash to Process.spawn without
coercion/validation, and Process.spawn supports nil values to remove variables.
Code

rb/sig/lib/selenium/webdriver/common/service.rbs[R54-60]

+      attr_accessor env: Hash[String, String]
+
      def env_path: -> String?

      alias extra_args args

-      def initialize: (?path: untyped?, ?port: untyped?, ?log: untyped?, ?args: untyped?) -> void
+      def initialize: (?path: untyped?, ?port: untyped?, ?log: untyped?, ?args: untyped?, ?env: Hash[String, String]?) -> void
Evidence
The provided evidence shows that Service stores the env hash as given (with no value
coercion/validation) and ServiceManager passes it into ChildProcess, where ChildProcess#start
passes @env directly as the env hash argument to Process.spawn. Because Process.spawn supports
env hashes with nil values on specific keys to unset variables, the current RBS signatures that
constrain values to String (or only allow the whole hash to be nil) do not match runtime
behavior and prevent typed callers from expressing the supported “unset” use case.

rb/sig/lib/selenium/webdriver/common/service.rbs[54-60]
rb/sig/lib/selenium/webdriver/common/service_manager.rbs[14-15]
rb/sig/lib/selenium/webdriver/firefox/service.rbs[12-12]
rb/sig/lib/selenium/webdriver/safari/service.rbs[12-12]
rb/lib/selenium/webdriver/common/service.rb[69-87]
rb/lib/selenium/webdriver/common/service_manager.rb[39-85]
rb/lib/selenium/webdriver/common/child_process.rb[54-60]
rb/sig/lib/selenium/webdriver/common/child_process.rbs[26-27]
Best Practice: Ruby Process.spawn env hash semantics

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The current RBS types for environment hashes across `Service`/`ServiceManager`/browser service constructors and `ChildProcess#env` constrain env values to `String` (`Hash[String, String]` or `Hash[String, String]?`), which disallows using `nil` for specific keys to unset inherited environment variables. The runtime path forwards these hashes to `Process.spawn` without validation, and `Process.spawn` supports per-key `nil` values for unsetting, so the RBS should be updated to accurately model that behavior.

## Issue Context
The env flow is `Service#env` -> `ServiceManager` -> `ChildProcess#env` -> `ChildProcess#start` -> `Process.spawn(env_hash, ...)`, and the env hash is passed through as-is (no coercion/validation). Since `Process.spawn` allows `nil` values in the env hash to remove variables, typed Ruby callers need the signatures to permit `nil` values per key; model this as `Hash[String, String?]` (and `Hash[String, String?]?` where the entire hash itself is optional), including updating any related ivar/accessor types.

## Fix Focus Areas
- rb/sig/lib/selenium/webdriver/common/service.rbs[22-23]
- rb/sig/lib/selenium/webdriver/common/service.rbs[54-55]
- rb/sig/lib/selenium/webdriver/common/service.rbs[60-60]
- rb/sig/lib/selenium/webdriver/common/service_manager.rbs[14-15]
- rb/sig/lib/selenium/webdriver/firefox/service.rbs[12-12]
- rb/sig/lib/selenium/webdriver/safari/service.rbs[12-12]
- rb/sig/lib/selenium/webdriver/common/child_process.rbs[14-15]
- rb/sig/lib/selenium/webdriver/common/child_process.rbs[26-27]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

Comment on lines +30 to +36
allow(Process).to receive(:spawn).and_return(12_345)
allow(Process).to receive(:detach)

process.start

expect(Process).to have_received(:spawn).with({'FOO' => 'bar'}, 'echo', 'test', anything)
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Mocks used in child_process_spec 📘 Rule violation ⚙ Maintainability

The newly added unit tests stub Process.spawn and Process.detach, which violates the requirement
to avoid mocks in tests and can reduce fidelity to real behavior.
Agent Prompt
## Issue description
The new unit tests for `ChildProcess#start` use mocks/stubs (`allow(Process).to receive(...)`) and mock assertions (`have_received`), which violates the project's guidance to avoid mocks in tests.

## Issue Context
This PR adds support for passing environment variables to `Process.spawn`. The tests currently validate this by stubbing Ruby's `Process` module.

## Fix Focus Areas
- rb/spec/unit/selenium/webdriver/common/child_process_spec.rb[25-47]

## Suggested direction
- Prefer an integration-like unit test that executes a very small real command and inspects its output/environment (e.g., spawn a Ruby one-liner that prints `ENV['FOO']`) rather than mocking `Process.spawn`.
- If platform differences are a concern, gate the test appropriately (e.g., skip on Windows if needed) while still avoiding mocks.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support in the Ruby bindings to pass an explicit environment hash into the driver service process launch, enabling callers to avoid inheriting (or to override) the Ruby process environment when starting a browser via its driver.

Changes:

  • Add env configuration to WebDriver::Service and propagate it through ServiceManager into ChildProcess.
  • Update ChildProcess to pass the env hash as the first argument to Process.spawn.
  • Add unit tests covering env passing in ChildProcess#start and Chrome::Service initialization.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
rb/lib/selenium/webdriver/common/service.rb Introduces env attribute/keyword on the base Service configuration.
rb/lib/selenium/webdriver/common/service_manager.rb Passes the configured env through to the spawned child process.
rb/lib/selenium/webdriver/common/child_process.rb Uses Process.spawn(env, *command, options) to apply env overrides.
rb/spec/unit/selenium/webdriver/common/child_process_spec.rb Adds specs asserting Process.spawn receives the env hash (and {} by default).
rb/spec/unit/selenium/webdriver/chrome/service_spec.rb Adds a spec asserting Chrome::Service retains the provided env.

Comment on lines +69 to 70
def initialize(path: nil, port: nil, log: nil, args: nil, env: nil)
port ||= self.class::DEFAULT_PORT
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Service now accepts an env: keyword, but at least one concrete subclass (Safari::Service) overrides initialize without env:/** and will raise ArgumentError: unknown keyword: :env when users try to use this new option. Update the Safari service initializer to accept/pass through env: (or switch to **) so the feature is consistently available across drivers.

Copilot uses AI. Check for mistakes.

WebDriver.logger.debug("Starting process: #{@command} with #{options}", id: :process)
@pid = Process.spawn(*@command, options)
@pid = Process.spawn(@env, *@command, options)
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env is an attr_accessor, so it can be set to nil (or another non-Hash) after initialization; Process.spawn expects the optional first argument to be a Hash and will raise a TypeError if it isn't. Consider coercing to {} at the call site (or validating in env= and raising a more actionable WebDriver error) to make service startup resilient to nil/invalid env values.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Comment on lines +52 to +54
it 'spawns process with environment variables' do
process = described_class.new('ruby', '-e', 'puts ENV["SELENIUM_TEST_VAR"]')
process.env = {'SELENIUM_TEST_VAR' => 'test_value'}
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec spawns 'ruby' from PATH, which can be a different interpreter than the one running the test suite (and can fail in some CI setups). Use the current Ruby executable (e.g., RbConfig.ruby) for the child process command to make the test deterministic.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is very simple and it would provide same behavior on all versions.

Comment thread rb/spec/unit/selenium/webdriver/common/child_process_spec.rb Outdated
Comment on lines +28 to 29
def initialize(path: nil, port: nil, log: nil, args: nil, env: nil)
raise Error::WebDriverError, 'Safari Service does not support setting log output' if log
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Safari::Service currently lists all keyword parameters explicitly. Other service subclasses (e.g., Chrome/Edge/Firefox) use def initialize(args: nil, **) and then super, which avoids needing to update this signature whenever the base WebDriver::Service adds a new config keyword (as happened here for env). Consider switching Safari::Service to accept ** (while still enforcing the log restriction) to make this more future-proof.

Suggested change
def initialize(path: nil, port: nil, log: nil, args: nil, env: nil)
raise Error::WebDriverError, 'Safari Service does not support setting log output' if log
def initialize(args: nil, **opts)
raise Error::WebDriverError, 'Safari Service does not support setting log output' if opts[:log]

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

@y-yagi y-yagi Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thinks the current implementation is better.

Currently, the environment variables used when launching a browser
are the same as those of the Ruby process that performs the launch.

However, there are times when want to change the environment variables
passed to a browser. In our case, `LD_PRELOAD`. We want to set `LD_PRELOAD`
to use jemalloc in Ruby, but we want to avoid setting it for Chrome
because using jemalloc can cause crashes or unstable behavior.

To address this issue, this PR fixes allow environment variables to be
explicitly specified via the service.
@y-yagi y-yagi force-pushed the allow_to_set_env branch from 2e5da27 to 4572e98 Compare April 26, 2026 05:39
@aguspe
Copy link
Copy Markdown
Contributor

aguspe commented May 10, 2026

Nice @y-yagi! Before we merge, the new env: keyword and attr_accessor are public API, so per rb/AGENTS.md we should update the RBS signatures in rb/sig/. Right now they're still on the old shape:

common/service.rbs — needs attr_accessor env: untyped, @env: untyped, and ?env: untyped? on initialize

safari/service.rbs — needs ?env: untyped? on initialize

common/child_process.rbs — needs attr_accessor env: untyped and @env: untyped

Otherwise looks good to me! :)

Copilot AI review requested due to automatic review settings May 10, 2026 08:13
@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented May 10, 2026

Persistent review updated to latest commit 2fbb347

Comment thread rb/spec/unit/selenium/webdriver/common/child_process_spec.rb
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

y-yagi added 2 commits May 10, 2026 18:18
Close Tempfile before spawning process to avoid EACCES on Windows.
On Windows, an open file handle can prevent spawned processes from
opening the same file for redirection, causing test failures.
@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented May 10, 2026

Persistent review updated to latest commit 5ccc267

@y-yagi
Copy link
Copy Markdown
Contributor Author

y-yagi commented May 10, 2026

@aguspe
Thanks for your review!
I updated RBS signatures and fixed the comment by qodo-code-review. Thanks!

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented May 10, 2026

Persistent review updated to latest commit c850774

Copy link
Copy Markdown
Contributor

@aguspe aguspe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, thank you for the great job @y-yagi

JRuby environments may not have 'ruby' in PATH. Use RbConfig.ruby
to get the path to the current Ruby interpreter instead.
@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented May 10, 2026

Persistent review updated to latest commit adcba78

@y-yagi
Copy link
Copy Markdown
Contributor Author

y-yagi commented May 10, 2026

https://github.com/SeleniumHQ/selenium/actions/runs/25625296761/job/75219325680 has failed. I added the commit for fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-rb Ruby Bindings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants