You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix regression to custom RSpec matchers from change in #16901
Fix regression to test suite when switching from mocks to custom matchers in #17848
Simplify rspec around logic from #17412
💥 What does this PR do?
Fixes IO handling so RSpec matchers work under SE_DEBUG again
Fixes bug that prevented Ruby unit test suite from passing with SE_DEBUG enabled
🔧 Implementation Notes
SE_DEBUG locks the logger output to prevent runtime overrides; the test suite has no such need, so the custom matchers drop the lock to capture the output
Updated test assertions to be dynamic based on whether SE_DEBUG is set rather than modifying the variables unnecessarily
Fix RSpec log matcher capture under SE_DEBUG and make service specs env-agnostic
🐞 Bug fix🧪 Tests🕐 20-40 Minutes
AI Description
• Restore custom RSpec log matchers when SE_DEBUG forces logger output to stderr.
• Make service spec expectations include SE_DEBUG debug flags when applicable.
• Preserve and restore SE_DEBUG in specs instead of unconditionally deleting it.
The following are alternative approaches to this PR:
1. Add a public Logger capture/override helper
➕ Avoids reaching into @output_forced via instance_variable_get/set
➕ Centralizes the “temporarily override output” behavior for future tests/tools
➖ Requires production-code change for a test-only regression
➖ Needs careful API design to avoid weakening SE_DEBUG guarantees
2. Clear SE_DEBUG only for matcher capture blocks
➕ No dependence on logger internals
➕ Keeps capture logic simple
➖ Makes specs less representative of real SE_DEBUG behavior
➖ Harder to reason about when different parts of an example run with different env
3. Capture stderr at the process/spec level instead of logger output
➕ Doesn’t mutate Selenium logger state
➕ Works even if output forcing mechanism changes
➖ More brittle/noisy: captures unrelated output
➖ Harder to filter to only Selenium logger lines
Recommendation: Given the stated constraint of keeping changes test-only, the current approach (temporarily disabling the logger’s output lock and restoring it) is a pragmatic fix. If SE_DEBUG-related issues recur, consider promoting this into a small, explicit Logger API for temporary output overrides to avoid tests depending on internal instance variables.
Files changed (6) +37 / -28
Bug fix (1) +6 / -1
rspec_matchers.rbTemporarily unforce Selenium logger output to capture matcher logs under SE_DEBUG+6/-1
Temporarily unforce Selenium logger output to capture matcher logs under SE_DEBUG
• Updates log-capturing matchers to bypass the logger’s SE_DEBUG output lock by toggling the internal @output_forced flag during capture. Ensures the original logger output and forced state are restored in an ensure block.
service_spec.rbMake Chrome service spec expectations conditional on SE_DEBUG+6/-4
Make Chrome service spec expectations conditional on SE_DEBUG
• Introduces a debug_args helper and updates expectations so default args and log-path args include SE_DEBUG’s --verbose when set. Adjusts the SE_DEBUG around hook to restore any preexisting SE_DEBUG value instead of always deleting it.
service_spec.rbAlign service shortcut specs with SE_DEBUG-added debug flags+8/-4
Align service shortcut specs with SE_DEBUG-added debug flags
• Adds a small helper to append the appropriate debug flag only when SE_DEBUG is set. Updates expectations for Chrome, Edge, Firefox, and IE shortcut constructors to include debug args while keeping Safari unchanged.
service_spec.rbMake Edge service spec expectations conditional on SE_DEBUG+8/-5
Make Edge service spec expectations conditional on SE_DEBUG
• Adds debug_args and updates expectations for default args, log-path args, and user-provided args to account for --verbose under SE_DEBUG. Updates the SE_DEBUG around hook to restore the prior environment value and adjusts duplicated log-path assertions accordingly.
service_spec.rbStop forcibly clearing SE_DEBUG and assert Firefox debug args dynamically+4/-11
Stop forcibly clearing SE_DEBUG and assert Firefox debug args dynamically
• Removes the previous around hook that unconditionally deleted SE_DEBUG for the spec. Adds debug_args and updates count/equality expectations so -v is included only when SE_DEBUG is present.
service_spec.rbMake IE service spec expectations conditional on SE_DEBUG and restore env+5/-3
Make IE service spec expectations conditional on SE_DEBUG and restore env
• Adds debug_args and updates expectations so default and user-provided args include the SE_DEBUG --log-level=DEBUG flag when set. Updates the SE_DEBUG around hook to restore any original value rather than unconditionally deleting it.
1. SE_DEBUG lock disabled too long 🐞 Bug≡ Correctness
Description
In capture_log_lines, @output_forced is set to false for the entire yielded block, so code under
test can successfully call Logger#output= even though SE_DEBUG is intended to make output overrides
a no-op. This can make SE_DEBUG spec runs diverge from real runtime behavior and can redirect logs
away from the matcher capture.
SE_DEBUG forces logger output and blocks output overrides via the @output_forced guard, but the
matcher clears that guard across the entire block it is asserting on, enabling output overrides
during the test subject execution.
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
### Issue description
`capture_log_lines` clears `Selenium::WebDriver.logger`'s `@output_forced` flag for the entire duration of the yielded block. Under `SE_DEBUG`, this changes the semantics of `Logger#output=` inside the code under test (it becomes effective when it should be ignored), which can lead to behavior differences and lost/redirected captured output.
### Issue Context
- `SE_DEBUG` causes the logger to call `stderr!`, which sets `@output_forced = true` and makes `Logger#output=` a guarded no-op.
- The matcher only needs the lock cleared briefly to swap output to a `StringIO` and later restore it.
### Fix Focus Areas
- rb/spec/rspec_matchers.rb[74-90]
### Suggested fix
1. Save the original `@output_forced` value.
2. Temporarily clear it only to set `logger.output = io`, then immediately restore it to the original value *before* `yield`.
3. In `ensure`, temporarily clear it again only long enough to restore `logger.output = default_output`, then restore the original `@output_forced` value.
4. (Optional) Add/extend a unit spec to cover `SE_DEBUG` behavior where code inside the block attempts `WebDriver.logger.output = ...` and verify it still behaves as forced (ignored) while capture still works.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
2. Brittle logger ivar access 🐞 Bug⚙ Maintainability
Description
capture_log_lines disables SE_DEBUG’s forced-output behavior by directly mutating
Selenium::WebDriver.logger’s private @output_forced instance variable, tightly coupling this matcher
to Logger internals. If the logger enforcement mechanism changes, log capture behavior may regress
or become flaky in future refactors/upgrades.
The matcher now directly sets @output_forced, which is an internal guard used by
Selenium::WebDriver::Logger#output= to ignore output overrides when forced (e.g., via #stderr!).
This makes the spec helper dependent on a private internal variable name and enforcement mechanism.
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
## Issue description
`capture_log_lines` reaches into `Selenium::WebDriver::Logger` internals via `instance_variable_set(:@output_forced, false)`, which is brittle and couples specs to a private implementation detail.
## Issue Context
`Selenium::WebDriver::Logger#output=` gates changes on `@output_forced`, which is set by `#stderr!` under `SE_DEBUG`. The matcher currently toggles that ivar directly.
## Fix Focus Areas
- rb/spec/rspec_matchers.rb[71-87]
- rb/lib/selenium/webdriver/common/logger.rb[70-103]
## Suggested fix
Prefer a supported API over raw ivar mutation, e.g. add a small (possibly @api private) helper on `Selenium::WebDriver::Logger` such as `with_unforced_output { ... }` or `unforce_output!` and use it from `capture_log_lines` to temporarily allow output redirection during matcher capture.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
1. SE_DEBUG lock disabled too long 🐞 Bug≡ Correctness
Description
In capture_log_lines, @output_forced is set to false for the entire yielded block, so code under
test can successfully call Logger#output= even though SE_DEBUG is intended to make output overrides
a no-op. This can make SE_DEBUG spec runs diverge from real runtime behavior and can redirect logs
away from the matcher capture.
SE_DEBUG forces logger output and blocks output overrides via the @output_forced guard, but the
matcher clears that guard across the entire block it is asserting on, enabling output overrides
during the test subject execution.
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
### Issue description
`capture_log_lines` clears `Selenium::WebDriver.logger`'s `@output_forced` flag for the entire duration of the yielded block. Under `SE_DEBUG`, this changes the semantics of `Logger#output=` inside the code under test (it becomes effective when it should be ignored), which can lead to behavior differences and lost/redirected captured output.
### Issue Context
- `SE_DEBUG` causes the logger to call `stderr!`, which sets `@output_forced = true` and makes `Logger#output=` a guarded no-op.
- The matcher only needs the lock cleared briefly to swap output to a `StringIO` and later restore it.
### Fix Focus Areas
- rb/spec/rspec_matchers.rb[74-90]
### Suggested fix
1. Save the original `@output_forced` value.
2. Temporarily clear it only to set `logger.output = io`, then immediately restore it to the original value *before* `yield`.
3. In `ensure`, temporarily clear it again only long enough to restore `logger.output = default_output`, then restore the original `@output_forced` value.
4. (Optional) Add/extend a unit spec to cover `SE_DEBUG` behavior where code inside the block attempts `WebDriver.logger.output = ...` and verify it still behaves as forced (ignored) while capture still works.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
1. Brittle logger ivar access 🐞 Bug⚙ Maintainability
Description
capture_log_lines disables SE_DEBUG’s forced-output behavior by directly mutating
Selenium::WebDriver.logger’s private @output_forced instance variable, tightly coupling this matcher
to Logger internals. If the logger enforcement mechanism changes, log capture behavior may regress
or become flaky in future refactors/upgrades.
The matcher now directly sets @output_forced, which is an internal guard used by
Selenium::WebDriver::Logger#output= to ignore output overrides when forced (e.g., via #stderr!).
This makes the spec helper dependent on a private internal variable name and enforcement mechanism.
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
## Issue description
`capture_log_lines` reaches into `Selenium::WebDriver::Logger` internals via `instance_variable_set(:@output_forced, false)`, which is brittle and couples specs to a private implementation detail.
## Issue Context
`Selenium::WebDriver::Logger#output=` gates changes on `@output_forced`, which is set by `#stderr!` under `SE_DEBUG`. The matcher currently toggles that ivar directly.
## Fix Focus Areas
- rb/spec/rspec_matchers.rb[71-87]
- rb/lib/selenium/webdriver/common/logger.rb[70-103]
## Suggested fix
Prefer a supported API over raw ivar mutation, e.g. add a small (possibly @api private) helper on `Selenium::WebDriver::Logger` such as `with_unforced_output { ... }` or `unforce_output!` and use it from `capture_log_lines` to temporarily allow output redirection during matcher capture.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
titusfortner
changed the title
[rb] capture log matcher output under SE_DEBUG and keep service specs env-agnostic
[rb] fix tests and custom matchers to work with SE_DEBUG
Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔗 Related Issues
Fix regression to custom RSpec matchers from change in #16901
Fix regression to test suite when switching from mocks to custom matchers in #17848
Simplify rspec around logic from #17412
💥 What does this PR do?
SE_DEBUGagainSE_DEBUGenabled🔧 Implementation Notes
SE_DEBUGlocks the logger output to prevent runtime overrides; the test suite has no such need, so the custom matchers drop the lock to capture the outputSE_DEBUGis set rather than modifying the variables unnecessarilySE_DEBUGvariable was unilaterally deleted in specs to restore original value (from [rb] output driver logs by default when debug is enabled #16901)🤖 AI assistance
🔄 Types of changes