Skip to content

Migrated to 'drupal/drupal-extension' 5.4 and 'drupal/drupal-driver' 3.x.#631

Open
AlexSkrypnyk wants to merge 7 commits intomainfrom
feature/drupal-driver-3x
Open

Migrated to 'drupal/drupal-extension' 5.4 and 'drupal/drupal-driver' 3.x.#631
AlexSkrypnyk wants to merge 7 commits intomainfrom
feature/drupal-driver-3x

Conversation

@AlexSkrypnyk
Copy link
Copy Markdown
Member

@AlexSkrypnyk AlexSkrypnyk commented Apr 23, 2026

Summary

Migrated drevops/behat-steps from drupal/drupal-extension 5.3 / drupal/drupal-driver 2.x to the
5.4 / 3.x line. The 3.x driver ships a DrupalDriverInterface, a ContentCapabilityInterface capability
contract, and a revised entityCreate() / getEntityFieldTypes() API. This PR updates EckTrait and
MediaTrait to use those new interfaces and methods, replaces the vendored Selenium 2 driver with the
Lullabot fork required by drupal-extension 5.4, and raises the BehatCliContext subprocess timeout to give
the in-process Drupal bootstrap enough headroom on @api scenarios.

Changes

composer.json

  • Replaced behat/mink-selenium2-driver with lullabot/mink-selenium2-driver ^1.7.4 - drupal-extension 5.4 depends on the Lullabot fork rather than the upstream Behat package.
  • Pinned drupal/drupal-driver to dev-feature/ext-smoke as 3.0 and drupal/drupal-extension to dev-feature/drupal-driver-3x as 5.4 while the upstream packages reach a stable release.

src/Drupal/EckTrait.php

  • Added use Drupal\Driver\Capability\ContentCapabilityInterface import.
  • Replaced the old $this->getDriver()->createEntity() call (2.x API) with an explicit ContentCapabilityInterface runtime check followed by $driver->entityCreate() (3.x API).
  • The guard clause raises a descriptive RuntimeException naming the active driver class when the driver does not implement ContentCapabilityInterface, making misconfiguration failures immediately actionable.

src/Drupal/MediaTrait.php

  • Widened the driver type check from the concrete DrupalDriver class to the DrupalDriverInterface interface, keeping the check working across driver implementations.
  • Updated getEntityFieldTypes('media', array_keys($fields)) to getEntityFieldTypes('media') - the 3.x driver removed the $base_fields parameter from this method.
  • Extended the field-type match in image resolution to also accept file field type, covering media bundles that store images via a plain file field rather than an image field.

tests/behat/bootstrap/BehatCliContext.php

  • Raised the subprocess Process::setTimeout() from 20 s to 60 s. The 3.x driver bootstraps Drupal in-process before any step runs; on @api subprocess scenarios that install or uninstall modules this easily exceeds 20 s, causing spurious test timeouts.

Before / After

EckTrait - driver call migration

Before (2.x)                       After (3.x)
┌─────────────────────────┐        ┌──────────────────────────────────────────┐
│ $driver->createEntity() │        │ check $driver instanceof                 │
│  returns false on error │  ───►  │   ContentCapabilityInterface             │
│  no capability guard    │        │ then $driver->entityCreate()             │
└─────────────────────────┘        │   throws RuntimeException on bad driver  │
                                   └──────────────────────────────────────────┘

MediaTrait - driver type check widening

Before (2.x)                       After (3.x)
┌───────────────────────────────┐  ┌────────────────────────────────────────────┐
│ $driver instanceof DrupalDriver│  │ $driver instanceof DrupalDriverInterface   │
│ (concrete class, breaks if a  │  │ (interface - works with any conforming     │
│  decorator is used)           │  │  driver implementation or decorator)       │
└───────────────────────────────┘  └────────────────────────────────────────────┘

getEntityFieldTypes() signature change:

  2.x: getEntityFieldTypes('media', ['field_image', ...])
  3.x: getEntityFieldTypes('media')

Test plan

  • ahoy lint clean
  • ahoy test-bdd 787/787 pass

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 23, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Dependency management is updated to switch from fixed Drupal extension constraints to dev-feature aliases and replace the Selenium2 Mink driver. Driver capability checks are introduced in entity and field handling traits to enforce interface compliance. Behat CLI timeout is increased to accommodate longer bootstrap scenarios.

Changes

Cohort / File(s) Summary
Dependency Management
composer.json
Replaces behat/mink-selenium2-driver with lullabot/mink-selenium2-driver, swaps Drupal extension dependencies from fixed ^5.3.1 to dev-feature aliases (dev-feature/ext-smoke and dev-feature/drupal-driver-3x).
Entity & Field Handling
src/Drupal/EckTrait.php, src/Drupal/MediaTrait.php
Adds driver capability interface guards to entity creation and field expansion operations; updates driver interface usage from direct calls to capability-interface routing; adjusts field-type lookup to treat file fields like image fields for fixture expansion.
Documentation
STEPS.md
Clarifies that custom field handlers must be registered with the active DrupalDriver core to support upstream-unsupported field types and stub-resolution patterns.
Testing Infrastructure
tests/behat/bootstrap/BehatCliContext.php
Increases Symfony Process timeout from 20 seconds to 60 seconds to prevent premature termination during in-process Drupal bootstrap scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Suggested labels

AUTOMERGE

Suggested reviewers

  • skipper-vp

Poem

🐰 Drivers now dance through capability gates,
Field fixtures expand as their magic awaits,
Timeouts grow gentle for bootstrap's long waltz,
Dependencies shift to avoid old defaults,
A rabbit hops forward, no breaking faults! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main change: migration to newer versions of drupal/drupal-extension (5.4) and drupal/drupal-driver (3.x), which aligns with the primary dependency updates shown in composer.json and the accompanying code changes throughout the PR.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/drupal-driver-3x

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 `@composer.json`:
- Around line 23-25: composer.json currently depends on unpinned dev branches
drupal/drupal-driver (dev-feature/ext-smoke) and drupal/drupal-extension
(dev-feature/drupal-driver-3x) which can break downstream installs; either
replace those entries with stable constraint strings (e.g., change
"drupal/drupal-driver": "dev-feature/ext-smoke as 3.0" to a released semver like
"drupal/drupal-driver": "^3.0" and similarly for "drupal/drupal-extension"), or
if you must keep fork branches, document the fork-based strategy and rationale
in README/CONTRIBUTING and convert the branch specs to explicit commit
references (dev-feature/ext-smoke#<commit-sha>) so installs are reproducible;
update the composer.json entries for drupal/drupal-driver and
drupal/drupal-extension accordingly and add a short note in the repository docs
explaining the chosen approach.
🪄 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 Plus

Run ID: b3150f4e-8ef8-401d-a91a-f85995dd0401

📥 Commits

Reviewing files that changed from the base of the PR and between 5905387 and fb7fc09.

📒 Files selected for processing (2)
  • composer.json
  • src/Drupal/EckTrait.php

Comment thread composer.json
Comment on lines +23 to +25
"drupal/drupal-driver": "dev-feature/ext-smoke as 3.0",
"drupal/drupal-extension": "dev-feature/drupal-driver-3x as 5.4",
"lullabot/mink-selenium2-driver": "^1.7.4"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Checking for unpinned dev branch requirements in composer.json..."
jq -r '
  .require
  | to_entries[]
  | select(.value | startswith("dev-") and (contains("#") | not))
  | "\(.key): \(.value)"
' composer.json

echo
echo "Checking branch/version presence on Packagist (read-only)..."
for pkg in drupal/drupal-driver drupal/drupal-extension; do
  echo "== $pkg =="
  curl -fsSL "https://repo.packagist.org/p2/${pkg}.json" \
    | jq -r --arg pkg "$pkg" '.packages[$pkg][].version' \
    | rg '^dev-feature/|^v[0-9]' \
    | head -n 25
  echo
done

Repository: drevops/behat-steps

Length of output: 803


🏁 Script executed:

cat composer.json

Repository: drevops/behat-steps

Length of output: 2533


🏁 Script executed:

rg -i "repository|repositories|vcs|github" composer.json -A 3 -B 1

Repository: drevops/behat-steps

Length of output: 525


🏁 Script executed:

# Check if branches exist on the upstream Drupal packages
curl -fsSL "https://api.github.com/repos/drupal/drupal-driver/branches" \
  | jq -r '.[] | .name' | grep -E "feature/ext-smoke|feature/drupal-driver"

echo "---"

curl -fsSL "https://api.github.com/repos/drupal/drupal-extension/branches" \
  | jq -r '.[] | .name' | grep -E "feature/ext-smoke|feature/drupal-driver"

Repository: drevops/behat-steps

Length of output: 181


🏁 Script executed:

# Check if composer.lock exists and what it resolved
if [ -f "composer.lock" ]; then
  jq '.packages[] | select(.name == "drupal/drupal-driver" or .name == "drupal/drupal-extension")' composer.lock | head -40
else
  echo "No composer.lock file found"
fi

Repository: drevops/behat-steps

Length of output: 1403


🏁 Script executed:

# Get the full drupal/drupal-extension entry from composer.lock
jq '.packages[] | select(.name == "drupal/drupal-extension")' composer.lock | head -50

Repository: drevops/behat-steps

Length of output: 1850


🏁 Script executed:

# Check if composer.lock is tracked in git
git ls-files | grep -E "composer.lock"

Repository: drevops/behat-steps

Length of output: 45


🏁 Script executed:

# More explicit check for composer.lock in git
git status composer.lock 2>&1 || echo "File not tracked or not found"

Repository: drevops/behat-steps

Length of output: 128


🏁 Script executed:

# Check git history for composer.lock
git log --oneline -- composer.lock 2>&1 | head -5 || echo "No history found"

Repository: drevops/behat-steps

Length of output: 45


Pin dev-branch dependencies to stable versions or document fork-based strategy.

Lines 23–24 reference unpinned dev-feature/* branches from forks (jhedstrom/DrupalDriver and jhedstrom/drupalextension). While your composer.lock pins these to concrete commits (ensuring reproducibility for this project), downstream consumers of this library will inherit the unpinned branch constraints. This exposes consumers to non-reproducible installs and potential breakage from force-pushes on development branches.

Consider:

  • Pinning to stable versions (e.g., drupal/drupal-driver: "^3.0") if available
  • Or documenting the fork-based development strategy and the rationale for dev-branch dependencies in a README or CONTRIBUTING guide
  • Or using inline commit SHAs in composer.json itself (e.g., dev-feature/ext-smoke#bc835adf...) for clarity
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@composer.json` around lines 23 - 25, composer.json currently depends on
unpinned dev branches drupal/drupal-driver (dev-feature/ext-smoke) and
drupal/drupal-extension (dev-feature/drupal-driver-3x) which can break
downstream installs; either replace those entries with stable constraint strings
(e.g., change "drupal/drupal-driver": "dev-feature/ext-smoke as 3.0" to a
released semver like "drupal/drupal-driver": "^3.0" and similarly for
"drupal/drupal-extension"), or if you must keep fork branches, document the
fork-based strategy and rationale in README/CONTRIBUTING and convert the branch
specs to explicit commit references (dev-feature/ext-smoke#<commit-sha>) so
installs are reproducible; update the composer.json entries for
drupal/drupal-driver and drupal/drupal-extension accordingly and add a short
note in the repository docs explaining the chosen approach.

@AlexSkrypnyk AlexSkrypnyk force-pushed the feature/drupal-driver-3x branch from fb7fc09 to c88bcca Compare April 23, 2026 08:20
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/MediaTrait.php`:
- Around line 380-386: The guard and type expectations are inconsistent:
mediaExpandEntityFieldsFixtures() checks for DrupalDriverInterface but
mediaExpandEntityFields() expects the concrete DrupalDriver class, causing
interface-implementing drivers to fail; update mediaExpandEntityFields() to use
the DrupalDriverInterface check instead of DrupalDriver (replace any "$driver
instanceof DrupalDriver" checks and related type hints or docblocks to
DrupalDriverInterface) so both mediaExpandEntityFieldsFixtures() and
mediaExpandEntityFields() consistently accept any implementation of
DrupalDriverInterface.
🪄 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 Plus

Run ID: 939956d6-bb89-4e28-86b2-27d52bce1655

📥 Commits

Reviewing files that changed from the base of the PR and between fb7fc09 and c88bcca.

📒 Files selected for processing (3)
  • composer.json
  • src/Drupal/EckTrait.php
  • src/Drupal/MediaTrait.php

Comment thread src/Drupal/MediaTrait.php
Comment on lines +380 to +386
if (!$driver instanceof DrupalDriverInterface) {
// @codeCoverageIgnoreStart
throw new \RuntimeException(sprintf('The active Drupal driver "%s" does not support content operations required for media field expansion.', $driver::class));
// @codeCoverageIgnoreEnd
}

$field_types = $driver->getCore()->getEntityFieldTypes('media', array_keys($fields));
$field_types = $driver->getCore()->getEntityFieldTypes('media');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n 'instanceof\s+DrupalDriver\b|instanceof\s+DrupalDriverInterface\b' src/Drupal/MediaTrait.php

Repository: drevops/behat-steps

Length of output: 167


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check imports
echo "=== Imports (lines 1-20) ==="
head -20 src/Drupal/MediaTrait.php

# Check context around line 349
echo -e "\n=== Context around line 349 ==="
sed -n '340,360p' src/Drupal/MediaTrait.php | cat -n

# Check context around line 380
echo -e "\n=== Context around line 380 ==="
sed -n '370,395p' src/Drupal/MediaTrait.php | cat -n

# Get method names for these lines
echo -e "\n=== Method containing line 349 ==="
sed -n '1,349p' src/Drupal/MediaTrait.php | grep -n 'function\|public\|private' | tail -1

echo -e "\n=== Method containing line 380 ==="
sed -n '1,380p' src/Drupal/MediaTrait.php | grep -n 'function\|public\|private' | tail -1

Repository: drevops/behat-steps

Length of output: 2892


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check all uses of DrupalDriver in the file (not just instanceof)
echo "=== All uses of DrupalDriver in the file ==="
rg -n 'DrupalDriver' src/Drupal/MediaTrait.php

# Check if these methods call each other
echo -e "\n=== Check method relationships ==="
grep -n 'mediaExpandEntityFields' src/Drupal/MediaTrait.php

# Check the full method definition around line 346 to see method signature
echo -e "\n=== Full mediaExpandEntityFields method ==="
sed -n '346,366p' src/Drupal/MediaTrait.php | cat -n

# Check the full method definition around line 367 to see method signature
echo -e "\n=== Full mediaExpandEntityFieldsFixtures method start ==="
sed -n '367,400p' src/Drupal/MediaTrait.php | head -30 | cat -n

Repository: drevops/behat-steps

Length of output: 3083


Align driver type checks across sequential method calls.

mediaExpandEntityFieldsFixtures() (line 380) uses DrupalDriverInterface, but the next method in the sequence, mediaExpandEntityFields() (line 349), requires the concrete DrupalDriver class. A driver implementing the interface will pass the first guard and fail the second, breaking the workflow.

Update both methods to use DrupalDriverInterface for consistent interface-based compatibility.

🧰 Tools
🪛 PHPMD (2.15.0)

[error] 382-382: Missing class import via use statement (line '382', column '17'). (undefined)

(MissingImport)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Drupal/MediaTrait.php` around lines 380 - 386, The guard and type
expectations are inconsistent: mediaExpandEntityFieldsFixtures() checks for
DrupalDriverInterface but mediaExpandEntityFields() expects the concrete
DrupalDriver class, causing interface-implementing drivers to fail; update
mediaExpandEntityFields() to use the DrupalDriverInterface check instead of
DrupalDriver (replace any "$driver instanceof DrupalDriver" checks and related
type hints or docblocks to DrupalDriverInterface) so both
mediaExpandEntityFieldsFixtures() and mediaExpandEntityFields() consistently
accept any implementation of DrupalDriverInterface.

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: 3

🤖 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_paragraphs.feature`:
- Line 15: The Paragraphs happy-path scenario has been excluded from CI by the
"@api `@skipped`" tag; either remove the "@skipped" tag from that tag line to
re-enable the scenario in CI or replace it with a skip that references a
tracking issue (e.g., change "@skipped" to a named skip like
"@skipped:PAR-1234") so the skip is explicitly tracked; update the tag line
"@api `@skipped`" (or the scenario-level tags) and ensure the Paragraphs
happy-path scenario label remains unchanged.

In `@tests/behat/features/drupal_taxonomy.feature`:
- Line 262: Two vertical-format taxonomy creation scenarios are fully skipped by
the added "@skipped" tags, removing test coverage for single-term and multi-term
vertical-field workflows; remove the "@skipped" tag from those scenario examples
(the ones currently annotated "@api `@skipped`") or replace it with a
remediation-tracking tag (e.g., "@known_issue:<ticket-id>" or
"@todo:<ticket-id>") and add a short comment referencing the ticket so the tests
remain discoverable and the exclusion is traceable; ensure both scenarios
(single-term and multi-term vertical-field) are no longer silently excluded by
updating their tags in the feature file.

In `@tests/behat/features/file_download.feature`:
- Line 28: The new `@skipped` tags on download scenarios (e.g., occurrences of the
tag sequence "@api `@download` `@skipped`") create a gap in FileDownloadTrait
coverage by disabling link-download and ZIP validation paths; remove the broad
"@skipped" tag (or replace it with a narrow, scenario-specific skip marker) from
those download scenarios so the link-download paths and ZIP validation tests
(including negative assertions) are executed again, and verify the scenarios
that validate archive contents and negative download behaviors are restored and
un-skipped.
🪄 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 Plus

Run ID: 65d268eb-7a02-49e2-b74c-1de96dd19629

📥 Commits

Reviewing files that changed from the base of the PR and between c88bcca and 36d9bc4.

📒 Files selected for processing (3)
  • tests/behat/features/drupal_paragraphs.feature
  • tests/behat/features/drupal_taxonomy.feature
  • tests/behat/features/file_download.feature

Comment thread tests/behat/features/drupal_paragraphs.feature Outdated
"""

@api
@api @skipped
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid disabling both vertical-format taxonomy creation scenarios without remediation tracking.

These @skipped tags exclude both positive creation paths from execution, leaving a coverage gap for single-term and multi-term vertical-field workflows.

Suggested change
-  `@api` `@skipped`
+  `@api`
...
-  `@api` `@skipped`
+  `@api`

Also applies to: 271-271

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/behat/features/drupal_taxonomy.feature` at line 262, Two
vertical-format taxonomy creation scenarios are fully skipped by the added
"@skipped" tags, removing test coverage for single-term and multi-term
vertical-field workflows; remove the "@skipped" tag from those scenario examples
(the ones currently annotated "@api `@skipped`") or replace it with a
remediation-tracking tag (e.g., "@known_issue:<ticket-id>" or
"@todo:<ticket-id>") and add a short comment referencing the ticket so the tests
remain discoverable and the exclusion is traceable; ensure both scenarios
(single-term and multi-term vertical-field) are no longer silently excluded by
updating their tags in the feature file.

Comment thread tests/behat/features/file_download.feature Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.48%. Comparing base (5905387) to head (0c00d37).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #631      +/-   ##
==========================================
+ Coverage   97.45%   97.48%   +0.03%     
==========================================
  Files          44       44              
  Lines        3024     3024              
==========================================
+ Hits         2947     2948       +1     
+ Misses         77       76       -1     

☔ 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.

@AlexSkrypnyk AlexSkrypnyk changed the title Updated to the latest DrupalDriver and DrupalExtension. Migrated to 'drupal/drupal-extension' 5.4 and 'drupal/drupal-driver' 3.x. Apr 24, 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.

1 participant