Skip to content

[#571] Added ConfigOverrideTrait to disable Drupal config overrides via tags.#626

Merged
AlexSkrypnyk merged 3 commits intomainfrom
feature/571-config-override
Apr 10, 2026
Merged

[#571] Added ConfigOverrideTrait to disable Drupal config overrides via tags.#626
AlexSkrypnyk merged 3 commits intomainfrom
feature/571-config-override

Conversation

@AlexSkrypnyk
Copy link
Copy Markdown
Member

@AlexSkrypnyk AlexSkrypnyk commented Apr 10, 2026

Closes #571

Summary

Adds a new ConfigOverrideTrait under src/Drupal/ConfigOverrideTrait.php that lets a Behat scenario tell the Drupal system under test (SUT) to ignore config overrides defined in settings.php for specific config objects. Because Behat runs in a separate process from the SUT, the trait signals intent via a request header, a $_SERVER entry, and an environment variable; the SUT is responsible for reading the signal and calling ImmutableConfig::getOriginal() instead of ImmutableConfig::get().

Activation is driven by tags on a feature or scenario:

  • @disable-config-override:CONFIG_NAME - add one per config object; multiple tags are combined into a comma-separated list.
  • @behat-steps-skip:configOverrideBeforeScenario - opt out of the trait entirely for a scenario.
  • @behat-steps-skip:configOverrideBeforeStep - keep tag parsing but skip header propagation.

The BeforeStep hook re-applies the header on every step because some steps (for example, Drupal Extension login) reset headers set earlier in the scenario. Selenium-based drivers are skipped silently because they cannot set request headers. When the consuming context also uses RestTrait, the $restHeaders array is populated via a soft property_exists() check so standalone REST requests receive the same signal.

Changes

  • src/Drupal/ConfigOverrideTrait.php - new trait with configOverrideBeforeScenario and configOverrideBeforeStep hooks, tag parsing, BrowserKit header propagation, $_SERVER + putenv() fallbacks, and a soft RestTrait bridge.
  • tests/behat/features/drupal_config_override.feature - 6 scenarios covering: no tag, single tag, multiple tags (comma-joined), header surviving a login step, behat-steps-skip:configOverrideBeforeScenario, and behat-steps-skip:configOverrideBeforeStep. Reaches 100% line coverage for the new trait.
  • tests/behat/bootstrap/FeatureContext.php - registers the new trait on the default context.
  • tests/behat/fixtures_drupal/d10/.../mysite_core.routing.yml and src/Controller/TestContent.php - add /mysite_core/test-config-no-override-header route and controller that echoes the received X-Config-No-Override header so scenarios can assert it reached the SUT.
  • tests/behat/fixtures_drupal/d11/... - mirror of the D10 route + controller.
  • STEPS.md and README.md - regenerated via ahoy update-docs.

Before / After

Before:
  Behat scenario ──► SUT (Drupal)
                      │
                      └── settings.php overrides always applied
                          → ImmutableConfig::get() returns overridden value
                          → no way to assert original config from Behat


After:
  Behat scenario
    │ @disable-config-override:system.site
    │ @disable-config-override:myconfig.settings
    │
    ├─[BeforeScenario]─► parse tags → ['system.site', 'myconfig.settings']
    │
    └─[BeforeStep, every step]─► set on Mink driver (BrowserKit):
                                   X-Config-No-Override: system.site,myconfig.settings
                                 set $_SERVER['HTTP_X_CONFIG_NO_OVERRIDE']
                                 set putenv('HTTP_X_CONFIG_NO_OVERRIDE=...')
                                 set $this->restHeaders[...] if RestTrait in use
                                   │
                                   ▼
                                 SUT (Drupal)
                                   │
                                   └── reads header / $_SERVER / env
                                       → ImmutableConfig::getOriginal()
                                       → returns unoverridden value

Test plan

  • ahoy lint (phpcs, phpstan, rector --dry-run, gherkinlint) passes locally.
  • ahoy test-unit (189 tests, 312 assertions) passes locally.
  • ahoy test-bdd tests/behat/features/drupal_config_override.feature passes locally (6 scenarios, 100% line coverage for ConfigOverrideTrait).
  • CI green on this PR.

Overview

This PR adds a Drupal-specific Behat trait that lets scenarios signal the system-under-test (SUT) to ignore config overrides from settings.php for specified config objects. Activation is tag-driven and requires no new step definitions.

Key Changes

Core Implementation

  • Added trait: src/Drupal/ConfigOverrideTrait.php
    • BeforeScenario hook: parses @disable-config-override:NAME tags (feature + scenario), deduplicates, stores names; honors @behat-steps-skip:configOverrideBeforeScenario and resolves @behat-steps-skip:configOverrideBeforeStep.
    • BeforeStep hook: runs on every step and, when enabled, emits a comma-separated X-Config-No-Override value via:
      • Mink request header for BrowserKit-based drivers (silently skipped for Selenium/JS drivers)
      • $_SERVER['HTTP_X_CONFIG_NO_OVERRIDE']
      • HTTP_X_CONFIG_NO_OVERRIDE environment variable (putenv)
      • Soft integration with RestTrait::$restHeaders when that property exists
    • Clears driver-level header when no names or when BeforeStep propagation is skipped.

Tests & Fixtures

  • tests/behat/features/drupal_config_override.feature: Added eight @api scenarios exercising tag parsing, single/multiple config names, header persistence across a login step, and both skip-tag behaviors.
  • tests/behat/bootstrap/FeatureContext.php: Composes the new trait into the test context.
  • Fixtures for Drupal 10/11: Added routes and controller actions that echo X-Config-No-Override and return overridden vs original system.site:name depending on the header.
  • scripts/provision.sh: Appends system.site overrides to sites/default/settings.php during provisioning to support the tests.

Documentation

  • STEPS.md: Documented the trait, tag usage, skip tags, signaling channels, header-survival behavior, Selenium limitation, and the RestTrait soft-dependency.
  • README.md: Added index entry for Drupal\ConfigOverrideTrait.

Step Definition Compliance (CONTRIBUTING.md)

  • No new step definitions (@Given/@When/@then) were introduced—only hook methods (@BeforeScenario/@BeforeStep). Repository scan found no step-definition annotations in src/Drupal that violate the project's steps-format guidelines. No critical violations detected.

Testing & CI

  • Author reports local linting, unit tests, and BDD feature tests passed; CI pending.
  • The feature file included in the PR contains eight concrete scenarios (contrary to an earlier note that it lacked Scenario lines), so BDD tests are present to exercise the trait end-to-end.

Notes for Reviewers

  • The SUT must detect X-Config-No-Override (header / $_SERVER / env) and call ImmutableConfig::getOriginal() for the named config objects.
  • Selenium/JS driver limitation: headers cannot be set for JS-enabled sessions; this is documented and the trait silently omits header setting for such drivers.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 978fbf64-a3da-44c4-a77c-8305cd101532

📥 Commits

Reviewing files that changed from the base of the PR and between 60e6cc4 and 5ce23f4.

📒 Files selected for processing (2)
  • src/Drupal/ConfigOverrideTrait.php
  • tests/behat/features/drupal_config_override.feature

Walkthrough

Added a new Drupal Behat trait ConfigOverrideTrait that reads @disable-config-override:NAME tags and emits an X-Config-No-Override signal (request header, $_SERVER, env var, and optional restHeaders) per step; added docs, tests, Drupal test routes/controllers, fixture provisioning, and composed the trait into FeatureContext.

Changes

Cohort / File(s) Summary
Documentation
README.md, STEPS.md
Added README index entry and expanded STEPS.md describing the @disable-config-override:NAME tag format, cross-process signaling (request header, $_SERVER, env var, restHeaders), Selenium limitations, skip tags, and examples.
Trait Implementation
src/Drupal/ConfigOverrideTrait.php
New DrevOps\BehatSteps\Drupal\ConfigOverrideTrait with #[BeforeScenario] to collect/de-duplicate tags and #[BeforeStep] to emit a comma-separated X-Config-No-Override signal via Mink request header (when driver supports it), optional restHeaders, $_SERVER, and environment variable; supports skip tags and handles Selenium driver omission.
Context Integration
tests/behat/bootstrap/FeatureContext.php
Composed ConfigOverrideTrait into FeatureContext to enable trait hooks during tests.
Behat Feature Tests
tests/behat/features/drupal_config_override.feature
Added feature exercising tag parsing, single/multiple names, header presence/absence, header persistence across login flows, and skip-tag behaviors.
Fixtures — Drupal 10
tests/behat/fixtures_drupal/d10/.../mysite_core.routing.yml, .../Controller/TestContent.php
Added two routes and controller actions: /mysite_core/test-config-no-override-header (echoes header) and /mysite_core/test-config-system-site-name (returns original vs overridden system.site.name).
Fixtures — Drupal 11
tests/behat/fixtures_drupal/d11/.../mysite_core.routing.yml, .../Controller/TestContent.php
Same routes and controller actions as the D10 fixture for compatibility testing.
Provisioning
scripts/provision.sh
Appended system.site overrides into /app/build/web/sites/default/settings.php during provisioning (with chmod adjustments) to ensure tests exercise overridden values.

Sequence Diagram(s)

sequenceDiagram
    participant Behat as Behat Test
    participant Context as Test Context<br/>(ConfigOverrideTrait)
    participant Mink as Mink Driver
    participant SUT as System Under Test<br/>(Drupal)

    Behat->>Context: BeforeScenario — collect `@disable-config-override:*` tags
    Note over Context: store unique config names

    Behat->>Context: BeforeStep — emit signals
    alt skip tags present
        Note over Context: skip emission for this scenario/step
    else
        Context->>Mink: setRequestHeader("X-Config-No-Override", names) [if driver supports]
        Context->>Context: $_SERVER['HTTP_X_CONFIG_NO_OVERRIDE']=names
        Context->>Context: putenv('HTTP_X_CONFIG_NO_OVERRIDE=names')
        Context->>Context: set $restHeaders['X-Config-No-Override']=names (if present)
    end

    Behat->>Mink: perform HTTP step (visit/login)
    Mink->>SUT: HTTP request (may include X-Config-No-Override)
    SUT->>SUT: read header/$_SERVER -> choose getOriginal() vs get()
    SUT->>Mink: response
    Mink->>Behat: result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

PR: Requires more work

Poem

🐰 I nibbled tags and found the key,

Headers hop — they set me free,
$_SERVER whispers what to do,
Scenarios dance with names anew,
Hooray — the rabbit tests with glee!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title '[#571] Added ConfigOverrideTrait to disable Drupal config overrides via tags' clearly and specifically summarizes the main change: adding a new trait that disables config overrides using tags.
Linked Issues check ✅ Passed The PR implements all acceptance criteria from issue #571: ConfigOverrideTrait with BeforeStep/BeforeScenario hooks, tag parsing, X-Config-No-Override header, BrowserKitDriver/code/Drush support, TagTrait usage, soft RestTrait dependency, Selenium limitation documentation, and comprehensive tests.
Out of Scope Changes check ✅ Passed All changes are in scope: ConfigOverrideTrait implementation, documentation updates (README, STEPS), test scenarios covering tag parsing and header propagation, test fixtures (controllers, routes, FeatureContext integration), and provision script modifications for test setup.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/571-config-override

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 PHPStan (2.1.46)

Composer install failed: this project depends on private packages that require authentication (e.g. GitLab/GitHub, Laravel Nova, etc.).
CodeRabbit tooling environment cannot access private registries.
If your project requires private packages, disable the PHPStan tool in your coderabbit settings.

Instead, run PHPStan in a CI/CD pipeline where you can use custom packages — our pipeline remediation tool can use the PHPStan output from your CI/CD pipeline.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Drupal/ConfigOverrideTrait.php`:
- Around line 115-117: The early return in ConfigOverrideTrait when
$this->configOverrideSkipBeforeStep or $this->configOverrideDisabledNames === []
exits without clearing the propagated "no-override" signal, allowing
X-Config-No-Override to persist via $_SERVER, env, $restHeaders or request
headers; before returning, explicitly reset/clear the override signal state
(e.g. unset any $_SERVER['HTTP_X_CONFIG_NO_OVERRIDE'], clear related env vars
and remove the header from optional $restHeaders or the request header
container) so previous values do not bleed into later scenarios.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 078aa6e5-f710-4366-8008-90cc18a592ad

📥 Commits

Reviewing files that changed from the base of the PR and between b545be4 and c81c884.

📒 Files selected for processing (9)
  • README.md
  • STEPS.md
  • src/Drupal/ConfigOverrideTrait.php
  • tests/behat/bootstrap/FeatureContext.php
  • tests/behat/features/drupal_config_override.feature
  • tests/behat/fixtures_drupal/d10/web/modules/custom/mysite_core/mysite_core.routing.yml
  • tests/behat/fixtures_drupal/d10/web/modules/custom/mysite_core/src/Controller/TestContent.php
  • tests/behat/fixtures_drupal/d11/web/modules/custom/mysite_core/mysite_core.routing.yml
  • tests/behat/fixtures_drupal/d11/web/modules/custom/mysite_core/src/Controller/TestContent.php

Comment thread src/Drupal/ConfigOverrideTrait.php
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.50%. Comparing base (b545be4) to head (5ce23f4).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #626      +/-   ##
==========================================
+ Coverage   97.47%   97.50%   +0.02%     
==========================================
  Files          42       43       +1     
  Lines        2928     2960      +32     
==========================================
+ Hits         2854     2886      +32     
  Misses         74       74              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/behat/features/drupal_config_override.feature`:
- Line 1: Add a descriptive feature-level tag (e.g., `@config-override`) to the
"Check that ConfigOverrideTrait works" feature so it can be selected
independently; update the feature header in the
tests/behat/features/drupal_config_override.feature by inserting the tag line
(for example "@config-override") immediately above or on the same line as the
"Feature: Check that ConfigOverrideTrait works" declaration so all scenarios in
that feature inherit the tag.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: abd712ca-b21c-4b76-a3b6-099bbfbfd5ac

📥 Commits

Reviewing files that changed from the base of the PR and between c81c884 and 60e6cc4.

📒 Files selected for processing (6)
  • scripts/provision.sh
  • tests/behat/features/drupal_config_override.feature
  • tests/behat/fixtures_drupal/d10/web/modules/custom/mysite_core/mysite_core.routing.yml
  • tests/behat/fixtures_drupal/d10/web/modules/custom/mysite_core/src/Controller/TestContent.php
  • tests/behat/fixtures_drupal/d11/web/modules/custom/mysite_core/mysite_core.routing.yml
  • tests/behat/fixtures_drupal/d11/web/modules/custom/mysite_core/src/Controller/TestContent.php

Comment thread tests/behat/features/drupal_config_override.feature
@AlexSkrypnyk AlexSkrypnyk merged commit 47b66a5 into main Apr 10, 2026
14 checks passed
@AlexSkrypnyk AlexSkrypnyk deleted the feature/571-config-override branch April 10, 2026 10:17
@AlexSkrypnyk AlexSkrypnyk added this to the v3.7 milestone Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add ConfigOverrideTrait to disable Drupal config overrides via tags

1 participant