Skip to content

4.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 02 Nov 07:27
· 3 commits to main since this release
a2bdd33

What's new since 3.14.4

4.0 is a new major version. Behat Steps used to be a set of traits on top of the Drupal Extension and the Drupal Driver. 4.0 absorbs both, so the Behat extension, the backends that reach Drupal and every step now live in this one package. Almost everything a suite touches changes: Composer packages, Behat configuration, contexts, step text and tags. 4.0 also runs on Behat 4 and Drupal 12.

MIGRATION.md maps every renamed step, method, class, setting and tag from 3.14 to 4.0, and the migrate-behat-steps skill lets an AI coding agent apply it to your project. The new documentation site, behat-steps.drevops.com, covers the rest, with a page for every trait and an example for every step.

The Drupal Extension and the Drupal Driver are part of this package

  3.14: 3 packages                          4.0: drevops/behat-steps alone

  +----------------------------+            +----------------------------------+
  | drevops/behat-steps        |----------->| Steps                            |
  | step traits, HelperTrait   |            | 28 web and 29 Drupal step traits |
  +----------------------------+      +---->| and the helpers they compose     |
                |                     |     +----------------------------------+
                | builds on           |     | Contexts                         |
                v                     | +-->| WebRawContext, WebContext,       |
  +----------------------------+      | |   | DrupalContext                    |
  | drupal/drupal-extension    |      | |   +----------------------------------+
  | steps                      |------+ |   | Extension                        |
  | contexts                   |--------+   | BehatStepsExtension, registries, |
  | extension, managers        |----------->| authenticators, trait options,   |
  +----------------------------+            | prerequisites, browser           |
                |                           | capabilities, HTTP clients       |
                | requires                  +----------------------------------+
                v                     +---->| Backend                          |
  +----------------------------+      |     | Drupal, Drush and Blackbox       |
  | drupal/drupal-driver       |      |     | backends, capability interfaces, |
  | Drupal, Drush, Blackbox    |------+     | field handlers, creation aliases |
  | drivers, field handlers    |            +----------------------------------+
  +----------------------------+

This package conflicts with drupal/drupal-extension and drupal/drupal-driver, so remove both before you require 4.x. In the Behat configuration, BehatStepsExtension replaces Drupal\DrupalExtension, and Mink's own Behat\MinkExtension replaces Drupal\MinkExtension:

# 3.14
default:
  extensions:
    Drupal\MinkExtension:
      base_url: http://example.local
    Drupal\DrupalExtension:
      api_driver: drupal
      drupal:
        drupal_root: web

# 4.0
default:
  extensions:
    Behat\MinkExtension:
      base_url: http://example.local
    DrevOps\BehatSteps\Extension\ServiceContainer\BehatStepsExtension:
      backends: [drupal, blackbox]
      drupal:
        drupal_root: web

Behat 4 reads only PHP configuration, so a suite on Behat 4 moves these settings to behat.php, as the Quick start shows. lullabot/mink-selenium2-driver used to come with the Drupal Extension, so a suite that runs @javascript scenarios through Selenium now requires it itself, and JavaScript browser drivers covers both drivers 4.0 supports.

Backends replace @api

In 3.14, a scenario needed @api to reach Drupal. In 4.0, each step finds its own backend: the first backend in your backends list that can do what the step needs runs it, in-process or over Drush.

  3.14: the scenario's tag picks 1 driver for all of its steps

  +-------------+         +------------------------------+
  | @api        | ------> | api_driver, usually drupal   |
  +-------------+         +------------------------------+
  | @drush      | ------> | drush_driver                 |
  +-------------+         +------------------------------+
  | no tag      | ------> | default_driver, usually      |
  |             |         | blackbox, so Drupal steps    |
  |             |         | fail                         |
  +-------------+         +------------------------------+

  4.0: each step picks its own backend

  +-------------------------------------------+
  | Given the cache has been cleared          |
  | needs a backend that can clear caches     |
  +-------------------------------------------+
        |
        | asks the backends in your order
        v
  +------------+  no   +------------+  no   +------------+  no   +------------+
  | drupal     | ----> | drush      | ----> | blackbox   | ----> | the step   |
  +------------+       +------------+       +------------+       | fails      |
        | yes                | yes                               +------------+
        v                    v
  +------------+       +------------+
  | runs it    |       | runs it    |
  | in-process |       | over Drush |
  +------------+       +------------+

Drop @api and @drush from your features. @backend:NAME puts 1 backend first for a scenario or a feature, and Backend resolution has the full rules.

Your FeatureContext extends 1 context that carries every step

  3.14                                      4.0

  +------------------------------+          +------------------------------+
  | RawMinkContext               |          | RawMinkContext               |
  | from Mink                    |          | from Mink                    |
  +------------------------------+          +------------------------------+
                 ^                                         ^
                 | extends                                 | extends
  +------------------------------+          +------------------------------+
  | RawDrupalContext             |          | WebRawContext                |
  | from the Drupal Extension    |          | plumbing, registers no steps |
  +------------------------------+          +------------------------------+
                 ^                                         ^
                 | extends                                 | extends
  +------------------------------+          +------------------------------+
  | DrupalContext                |          | WebContext                   |
  | from the Drupal Extension    |          | + 28 web step traits         |
  +------------------------------+          +------------------------------+
                 ^                                         ^
                 | extends                                 | extends
  +------------------------------+          +------------------------------+
  | FeatureContext, yours        |          | DrupalContext                |
  |   use ContentTrait;          |          | + 29 Drupal step traits      |
  |   use LinkTrait;             |          +------------------------------+
  |   use ... 1 line per trait   |                         ^
  +------------------------------+                         | extends
                                            +------------------------------+
                                            | FeatureContext, yours        |
                                            | your own steps, no use lines |
                                            +------------------------------+

  registered in the suite                   registered in the suite
  +------------------------------+          +------------------------------+
  | FeatureContext               |          | FeatureContext               |
  | the Drupal Extension's       |          | Mink's own MinkContext       |
  | MinkContext, MarkupContext,  |          +------------------------------+
  | MessageContext ...           |
  +------------------------------+

Your FeatureContext extends DrevOps\BehatSteps\DrupalContext, or WebContext on a site that isn't Drupal, and has every step without a single use line. Register it beside Mink's own MinkContext and drop the Drupal Extension's contexts, because their steps are in DrupalContext now. Don't register DrupalContext or WebContext themselves: the steps would register twice, and the run stops with an error that names the context to keep. The traits moved from DrevOps\BehatSteps\ and DrevOps\BehatSteps\Drupal\ to DrevOps\BehatSteps\Steps\Web\ and DrevOps\BehatSteps\Steps\Drupal\, keeping their names. Contexts explains which one to extend.

Every step reads the same way

4.0 writes the Drupal Extension's steps and this package's own to 1 set of wording rules. A name follows its noun, a Given names the state it sets up, and a step the site runs on its own starts with the site rather than with I:

3.14 4.0
Given I am logged in as a user with the "editor" role Given I am logged in as a user with the role "editor"
Given the following "article" content: Given the following "article" content exists:
Then I should see "Welcome" in the "header" region Then I should see the text "Welcome" in the region "header"
Then the "default" queue should be empty Then the queue "default" should be empty
Given I run cron When cron runs

Many steps keep their text, among them Mink's own, such as I fill in and I press, and many of the Drupal Extension's, such as Given the cache has been cleared and Then I should see the success message "Saved". Step text maps every step that changed, from this package and from the Drupal Extension, and the migration skill rewrites your feature files from it. Web steps and Drupal steps list every 4.0 step with an example.

REST, JSON and XML steps have a session of their own

  3.14: every step shares the browser's session

  +--------------------+          +------------------------------+
  | page steps         | -------> | browser session              |
  +--------------------+    +---> | 1 page and 1 cookie jar,     |
  | REST steps         | ---+     | so a REST response replaces  |
  +--------------------+    |     | the page                     |
  | JSON and XML steps | ---+     +------------------------------+
  +--------------------+

  4.0: REST, JSON and XML steps read the "rest" session

  +--------------------+          +------------------------------+
  | page steps         | -------> | browser session              |
  +--------------------+          | page, cookies and login kept |
  | REST steps         | ---+     +------------------------------+
  +--------------------+    +---> | "rest" session               |
  | JSON and XML steps | ---+     | no browser cookies, works    |
  +--------------------+          | in @javascript scenarios     |
                                  +------------------------------+

The REST steps send through a Mink session named rest, and the JSON and XML steps read its last response, so a REST request no longer carries the browser's cookies or replaces its page. 2 things change in a suite:

  • The JSON and XML steps fail on a page the browser loaded. Load the response with a REST request instead:

    # 3.14
    When I go to "/api/articles.json"
    
    # 4.0
    When I send a REST "GET" request to "/api/articles.json"
    Then the JSON path "$.data[0].title" should have the value "Hello"
  • A REST request that relied on the browser's login now runs anonymously. Send the credentials the API expects with Given the REST header "Authorization" has the value "...".

A REST header can also take its value from the last response, so a token flow needs no step of your own: Given the REST header "Authorization" has the value from the JSON path "$.access_token" with the prefix "Bearer ". HTTP clients covers what the session carries and how to declare your own.

Tags

  • @api, @drush and @queue are gone.
  • A skip tag names a trait, so @behat-steps-skip:EmailTrait replaces @behat-steps-skip:emailBeforeScenario and @behat-steps-skip:emailAfterScenario. A skip tag that names a hook method fails the run.
  • A tag on the Feature: line applies to every scenario below it, so @email or @testmode there now acts on the whole feature.

Tags explains how the tags combine, and the Configuration reference lists every tag 4.0 reads.

Trait settings moved under steps

Each trait reads its settings from the steps section of BehatStepsExtension, and the config argument on your FeatureContext registration or a tag can override them for 1 context or scenario. The Drupal Extension's ajax_timeout, selectors.messages and mappings moved to steps.wait.ajax_timeout, steps.message.selectors and steps.mapping.groups. The message selectors have no default, so a suite that asserts on messages sets them:

DrevOps\BehatSteps\Extension\ServiceContainer\BehatStepsExtension:
  steps:
    message:
      selectors:
        default: '.messages'
        error: '.messages--error'
        success: '.messages--status'

Trait options explains the order the settings resolve in, and each trait's page, such as Messages, lists its options.

PHP errors fail scenarios

DrupalContext includes WatchdogTrait, so a scenario that logs a PHP error fails. The check reads the log of the core dblog module, and on a site without it every scenario fails at its start. Enable dblog, or switch the check off:

DrevOps\BehatSteps\Extension\ServiceContainer\BehatStepsExtension:
  steps:
    watchdog:
      enabled: false

Watchdog lists what the check needs and the tags that relax it for 1 scenario.

References and a skill for AI coding agents

The package ships 3 files for an agent to read from vendor/drevops/behat-steps/, at the version you installed:

  • STEPS.md lists every step with its options and an example.
  • HELPERS.md is new, and lists the helpers your own steps can call.
  • skills/create-behat-step/SKILL.md is new too. It's a skill that turns a plain-English description into a step of your own, built on those helpers, then writes a scenario for it and runs it.

Writing tests with AI assistants has the snippet for your CLAUDE.md or AGENTS.md, and shows how to install the skill.

All 162 changes since 3.14.4
  • Update toshimaru/auto-author-assign action to v3.1.1 @renovate[bot] (#1134)
  • [#1129] Settled when a 'Get' throws, added language creation hooks, documented the factory's REST reach and merged the Drush lookup. @AlexSkrypnyk (#1132)
  • Update chromedp/headless-shell Docker tag to v159 @renovate[bot] (#1133)
  • Polished the docs and comments against the code, moved docs CI to Node 26 and fixed the 'ahoy test-bdd' path. @AlexSkrypnyk (#1130)
  • Update dependency drupal/token to ^1.18.0 @renovate[bot] (#1131)
  • [#1122] Added 'the static caches have been cleared' step and cleared the static caches after every Drush step. @AlexSkrypnyk (#1128)
  • [#1125] Added REST steps that set a header from a JSON path in the last response and send a body read from a fixture file. @AlexSkrypnyk (#1127)
  • Update Node.js to v26 @renovate[bot] (#1118)
  • [#1124] Sent REST requests through a dedicated 'rest' Mink session that the JSON and XML steps read. @AlexSkrypnyk (#1126)
  • Corrected the real-browser driver claim in the installation guide and dropped a fixture version from 'CONTRIBUTING.md'. @AlexSkrypnyk (#1121)
  • Rewrote the documentation pages for readability and corrected the claims the source contradicted. @AlexSkrypnyk (#1119)
  • Update all dependencies @renovate[bot] (#1120)
  • Update all dependencies @renovate[bot] (#1117)
  • Update dependency phpstan/phpstan to ^2.3.3 @renovate[bot] (#1116)
  • Update dependency phpunit/phpunit to ^12.5.42 @renovate[bot] (#1115)
  • Update dependency rector/rector to ^2.8.1 @renovate[bot] (#1114)
  • Update all dependencies @renovate[bot] (#1113)
  • [#1108] Resolved relative backend roots and a bare 'drush' at container build for the lazy backends. @AlexSkrypnyk (#1112)
  • [#1108] Made the 'drupal' and 'drush' backend services lazy, so classes in Behat's 'autoload' paths are found. @AlexSkrypnyk (#1110)
  • [#1109] Stored 'date_recur' values as written and rejected a record with no 'timezone' or a non-storage date. @AlexSkrypnyk (#1111)
  • [#1098] Expanded relative date tokens in ':title', ':name' and ':label' step arguments. @AlexSkrypnyk (#1106)
  • [#1089] Fixed 'When the test email system queue is cleared' failing in scenarios tagged only with '@email:TYPE'. @AlexSkrypnyk (#1092)
  • [#1090] Treated the 'anonymous' role as a logout in 'I am logged in as a user with the role(s) :roles'. @AlexSkrypnyk (#1094)
  • [#1091] Kept stderr after stdout in the Drush step output. @AlexSkrypnyk (#1093)
  • Update all dependencies @renovate[bot] (#1088)
  • [#1081] Named the submit input fallback in 'field.add_more_button_selectors' and reworded 'time.enabled'. @AlexSkrypnyk (#1087)
  • Update dependency drupal/profile to ^1.16.0 @renovate[bot] (#1086)
  • [#1081] Split Configuration into a guide and a reference, and rewrote the option and tag prose against the code. @AlexSkrypnyk (#1085)
  • Added a 'create-behat-step' skill that ships in the package and writes a project's own step on the public helpers. @AlexSkrypnyk (#1084)
  • [#1080] Steered projects to a 'FeatureContext' that extends 'DrupalContext' or 'WebContext', and named it in the duplicate-context error. @AlexSkrypnyk (#1082)
  • Added a zooming lightbox for images and diagrams to the docs site and linked the development docs in the README. @AlexSkrypnyk (#1083)
  • Reworked the docs for newcomers to Behat, gave Architecture a page per layer and made 'HELPERS.md' the only helper reference. @AlexSkrypnyk (#1077)
  • [#1075] Replaced the PlantUML architecture diagrams with logical architecture, class inheritance and data flow diagrams in draw.io. @AlexSkrypnyk (#1076)
  • [#1073] Corrected the docs that said the Watchdog check needs an in-process backend. @AlexSkrypnyk (#1074)
  • Updated the docs site to Jest 30, jest-dom 7 and cspell 10 on Node 24, keeping Babel on 7 for Docusaurus 3. @renovate[bot] (#1071)
  • Added a home page to the documentation site and moved the introduction to '/introduction'. @AlexSkrypnyk (#1072)
  • Update all dependencies @renovate[bot] (#1070)
  • [#1063] Added a Docusaurus documentation site in 'docs' for behat-steps.drevops.com. @AlexSkrypnyk (#1069)
  • [#1055] Raised every file to at least 95% line coverage and fixed the Drush steps passing a multi-word string as 1 argument. @AlexSkrypnyk (#1068)
  • Update chromedp/headless-shell Docker tag to v158 @renovate[bot] (#1066)
  • [#1059] Built the version core for the detected Drupal major in the 'drupal' backend and added the 'drupal.core' option. @AlexSkrypnyk (#1067)
  • Update chromedp/headless-shell Docker tag to v157.0.8103.6 @renovate[bot] (#1065)
  • Update all dependencies @renovate[bot] (#1064)
  • [#1060] Added the 'creation_aliases' options and 'registerCreationAlias()', and ran aliases on every entity created from field values. @AlexSkrypnyk (#1062)
  • [#1056] Added the 'drupal.field_handlers' option, read 'date_recur' values in their timezone and aligned the cookie messages. @AlexSkrypnyk (#1058)
  • Polished the README and docs, converged source comments and corrected stale claims. @AlexSkrypnyk (#1057)
  • Update all dependencies to v12.0.0-beta2 @renovate[bot] (#1054)
  • [#1049] Closed the remaining capability gaps in the step traits, the neutral contracts, the backends and the harness. @AlexSkrypnyk (#1053)
  • Update all dependencies @renovate[bot] (#1052)
  • Update dependency symfony/browser-kit to ^8.1.9 @renovate[bot] (#1051)
  • [#1048] Retired 'CoreCapabilityInterface' from the step traits and moved their remaining Drupal storage knowledge and side channels into backend capabilities. @AlexSkrypnyk (#1050)
  • [#1041] Routed entity updates, reads and config entity writes through the backend and returned stubs from the step trait helpers. @AlexSkrypnyk (#1046)
  • Update selenium/standalone-chromium Docker tag to v155 @renovate[bot] (#1047)
  • [#1042] Added per-subsystem Drupal capabilities for queues, the log, cache bins, files, search indexing, node access and one-time logins. @AlexSkrypnyk (#1045)
  • [#1040] Added an entity lookup capability and routed the step traits through the block, mail, state and role capabilities. @AlexSkrypnyk (#1044)
  • Removed the 11 contrib modules that already allow Drupal 12 from the 'd12' lenient allowed-list. @AlexSkrypnyk (#1043)
  • Update dependency drupal/testmode to ^2.8.0 @renovate[bot] (#1039)
  • [#1037] Moved the node and term methods to Drupal-only capabilities and replaced the Drupal 'Random' with a package random generator. @AlexSkrypnyk (#1038)
  • Restructured the namespace tree around the 3 layers and moved the contexts to the package root. @AlexSkrypnyk (#1036)
  • Update dependency phpunit/phpunit to ^12.5.39 @renovate[bot] (#1035)
  • Reworded every step to follow 19 numbered rules with no exceptions, declared each step's actor and checked the rules in 'docs.php'. @AlexSkrypnyk (#1034)
  • Update dependency ahoy-cli/ahoy to v3 @renovate[bot] (#1033)
  • Update all dependencies @renovate[bot] (#1032)
  • Added a 'migrate-behat-steps' skill and a README prompt that fetches it to migrate a project from 3.x to 4.x. @AlexSkrypnyk (#1031)
  • Ported the dependency, image and action digest updates merged into main after 3.14.4 to 4.x. @AlexSkrypnyk (#1030)
  • Restructured 'MIGRATION.md' into deduplicated 3.14-to-4.0 mapping tables and filled the gaps against 3.14.4. @AlexSkrypnyk (#1029)
  • Removed the 'draggableviews_demo' sample nodes from the fixture site and gave the testmode articles explicit 'changed' times. @AlexSkrypnyk (#1028)
  • Update all dependencies @renovate[bot] (#1027)
  • Made 'composer.json' conflict with every version of 'drupal/drupal-extension' and 'drupal/drupal-driver'. @AlexSkrypnyk (#1026)
  • [#1007] Stopped promising Behat 4 to a project that admits alpha releases in the README and 'CONTRIBUTING.md'. @AlexSkrypnyk (#1025)
  • [#1011] Corrected 34 source comments whose claims the code contradicts. @AlexSkrypnyk (#1024)
  • [#1017] Converged option reads, class names, harness hooks, test placement and control structure spacing onto the project's conventions. @AlexSkrypnyk (#1022)
  • [#1007] Settled the 4.0 install line, support policy, Behat 4 constraints, Behat 4 Chrome leg and 'MIGRATION.md' names. @AlexSkrypnyk (#1023)
  • [#1003] Fixed how trait hooks and tags behave at scenario start. @AlexSkrypnyk (#1021)
  • [#1006] Made 6 steps and 3 capability contracts do what their step text and docblocks say. @AlexSkrypnyk (#1020)
  • Update dependency phpstan/phpstan to ^2.3.1 @renovate[bot] (#1019)
  • Fixed documentation drift, tightened source comments and flattened 3 nested assertions. @AlexSkrypnyk (#1018)
  • [#990] Settled which entity a lookup by title acts on, how the viewport steps fail without JavaScript and which way the top offset scrolls. @AlexSkrypnyk (#1002)
  • [#988] Settled the public surface and placement of helpers, override points and types. @AlexSkrypnyk (#1001)
  • [#992] Fixed 'Authenticator::login()' failing a JavaScript login before the post-login page loads. @AlexSkrypnyk (#1000)
  • [#987] Extracted duplicated and inline step logic into shared and named helpers. @AlexSkrypnyk (#998)
  • [#989] Tidied the Drush backend and declared the modules and package the traits depend on. @AlexSkrypnyk (#996)
  • [#991] Replaced reachable coverage markers with tests, removed dead branches, folded duplicate kernel tests and aligned the Behat harness. @AlexSkrypnyk (#995)
  • [#985] [#986] Settled the remaining naming, step text, hook, failure message and exception conventions. @AlexSkrypnyk (#997)
  • Update release-drafter/release-drafter digest to 978bb0b @renovate[bot] (#999)
  • Update actions/upload-artifact digest to cf430e0 @renovate[bot] (#994)
  • Converged step method names, step text, failure messages and comments onto the project's own rules. @AlexSkrypnyk (#993)
  • [#923] Registered 'DrupalContext' alone in 'behat.dist.php' and ran the reference suite through the one-context guard. @AlexSkrypnyk (#947)
  • Update dependency rector/rector to ^2.7.0 @renovate[bot] (#948)
  • [#921] Dropped the @queue filter so the 'QueueTrait' teardown runs after every scenario. @AlexSkrypnyk (#944)
  • Update dependency phpstan/phpstan to ^2.3.0 @renovate[bot] (#946)
  • [#919] Made 'tableTransposeVertical()' throw the documented 'RuntimeException' for an empty table. @AlexSkrypnyk (#943)
  • [#913] Sealed every class a project is not meant to extend and typed every constant under 'src/'. @AlexSkrypnyk (#945)
  • [#911] Declared step placeholders as required strings, parsed numbers with 'StringTrait' and defaulted optional strings to 'NULL'. @AlexSkrypnyk (#933)
  • [#922] Made 'SupportedImageHandler' reuse an existing managed file the way the file and image handlers do. @AlexSkrypnyk (#942)
  • [#924] Removed the Drupal Finder variables that the nested Behat run never reads. @AlexSkrypnyk (#941)
  • [#918] Settled the split test suite conventions and enforced them with 'TestConventionTest'. @AlexSkrypnyk (#940)
  • [#917] Settled the remaining code-style ties in the library code. @AlexSkrypnyk (#939)
  • [#920] Narrowed the page cache steps to delete only the entries for the paths they name. @AlexSkrypnyk (#938)
  • [#909] Renamed entity create and delete methods verb-first and batch methods to end in 'Multiple'. @AlexSkrypnyk (#931)
  • [#916] Prefixed the @trait: and @skipped harness tags with 'test-'. @AlexSkrypnyk (#937)
  • [#915] Split the 'Behat\Manager' namespace into 'Behat\Registry' and 'Behat\Auth'. @AlexSkrypnyk (#936)
  • [#914] Made the email subject steps match the whole subject or a case-sensitive part through 'emailFindMessageBySubject()'. @AlexSkrypnyk (#935)
  • Update dependency phpunit/phpunit to ^11.5.57 @renovate[bot] (#934)
  • [#908] Merged the 2 same-event hook pairs into 'authAfterScenario()' and 'accessibilityBeforeSuite()'. @AlexSkrypnyk (#929)
  • [#912] Made every capability create return the stub and every delete return 'void' and tolerate a missing target. @AlexSkrypnyk (#932)
  • [#910] Settled the navigation, click, select, viewport and email address step wording. @AlexSkrypnyk (#930)
  • [#907] Spelled logging in and out as 'login' and 'logout' across the method, interface and configuration names. @AlexSkrypnyk (#928)
  • Converged naming, failure messages, test structure and comments onto the existing project conventions. @AlexSkrypnyk (#925)
  • Update dependency phpstan/phpstan to ^2.2.17 @renovate[bot] (#927)
  • Update chromedp/headless-shell Docker tag to v157 @renovate[bot] (#926)
  • Update drevops/ci-runner Docker tag to v26.10.0 @renovate[bot] (#906)
  • Backported dependency updates and the per-clone local dev URL from main to 4.x, and typed the hook callable for both Behat majors. @AlexSkrypnyk (#905)
  • Update dependency dmore/behat-chrome-extension to ^1.5.0 @renovate[bot] (#904)
  • [#899] Enforced sorted imports with 'AlphabeticallySortedUses' and finished the backend rename in test names and 'MIGRATION.md'. @AlexSkrypnyk (#903)
  • [#893] Renamed the backend drivers to backends so their names stop colliding with Mink's. @AlexSkrypnyk (#896)
  • [#857] Aligned assertion and helper names with the documented naming rules. @AlexSkrypnyk (#895)
  • [#830] Made repeated @driver: tags rank by the configured driver list instead of the order they are written in. @AlexSkrypnyk (#894)
  • [#859] Made the trait hooks read tags on the 'Feature:' line through shared 'Tag' readers and named tag constants. @AlexSkrypnyk (#884)
  • [#886] Added trait prerequisites checked through driver capabilities, and made 'WatchdogTrait' fail at scenario start without 'dblog'. @AlexSkrypnyk (#887)
  • [#890] Built the page client as Mink does, retired the Drupal 12 deprecated calls, and settled the driver vocabulary. @AlexSkrypnyk (#892)
  • Removed the 'drevops/ci-runner' job container from CI and ran both jobs directly on the GitHub-hosted runner. @AlexSkrypnyk (#891)
  • [#811] Replaced the Mink wrapper and 'DrupalTestBrowser' with Mink's own extension and page, detached and bare Symfony HTTP clients. @AlexSkrypnyk (#889)
  • [#854] Settled the 'behat-steps-skip' tag on the trait name. @AlexSkrypnyk (#883)
  • [#845] Added a unit test that fails when a registered step has no scenario, and scenarios for the 25 steps that had none. @AlexSkrypnyk (#881)
  • [#858] Aligned the step text with the documented Gherkin grammar rules. @AlexSkrypnyk (#882)
  • [#855] Aligned the 'LoadMultiple()' helpers on returning loaded entities keyed by ID. @AlexSkrypnyk (#880)
  • [#856] Renamed the lookup helpers so 'Find' returns NULL, 'Get' throws and 'Load' loads a set. @AlexSkrypnyk (#879)
  • [#861] Recorded the test naming shape and data provider form as unsettled, and enforced the settled provider rules. @AlexSkrypnyk (#878)
  • [#864] Extracted trait option resolution out of the context base class into a 'Behat\Config' namespace. @AlexSkrypnyk (#876)
  • [#852] Extended the trait convention checks to 'src/Helper' and partitioned the 'entityLifecycle' prefix. @AlexSkrypnyk (#877)
  • [#862] Corrected the source comments that misstated what the code does. @AlexSkrypnyk (#875)
  • [#866] Renamed the manager classes for the role each one plays. @AlexSkrypnyk (#874)
  • [#867] Routed steps through capabilities, added a browser capability layer, and removed the duplicated entity and handler logic. @AlexSkrypnyk (#872)
  • Converted 'scripts/provision.sh' to 'scripts/provision.php'. @AlexSkrypnyk (#873)
  • Declared the package patches from 'provision.sh' rather than 'composer.json'. @AlexSkrypnyk (#869)
  • Converged the codebase on consistent naming, typing, exceptions and comment register, and fixed 4 defects found along the way. @AlexSkrypnyk (#863)
  • [#836] Replaced the split contexts with one chain and per-concern helpers. @AlexSkrypnyk (#838)
  • Ported dependency updates, the queue step rename and the Renovate root-constraint rule from main to 4.x. @AlexSkrypnyk (#851)
  • [#847] Capped 'twig/twig' below 3.30 in the Drupal 12 fixture. @AlexSkrypnyk (#849)
  • [#834] Added per-trait configuration schemas resolved through 'steps', context 'config' and scenario tags. @AlexSkrypnyk (#837)
  • [#832] Replaced '@api' driver selection with capability-based driver resolution. @AlexSkrypnyk (#833)
  • Backported dependency updates and the bounded accessibility engine fetch from main to 4.x. @AlexSkrypnyk (#828)
  • Converged the codebase conventions and the source comment register. @AlexSkrypnyk (#827)
  • [#820] Added Drupal 12 support. @AlexSkrypnyk (#826)
  • [#784] Unified the reference documentation toolchain and published the helper API. @AlexSkrypnyk (#823)
  • [#775] Consolidated lint, the CI matrix and Renovate, and ran the test suites on both Behat 3 and Behat 4. @AlexSkrypnyk (#815)
  • [#807] Added the 'update-architecture-docs' skill and the PlantUML architecture walkthrough. @AlexSkrypnyk (#813)
  • [#781] Unified the scenario lifecycle and replaced DrupalExtension with first-party wiring. @AlexSkrypnyk (#808)
  • [#778] Imported the Behat integration layer as 'BehatStepsExtension'. @AlexSkrypnyk (#805)
  • [#780] Re-rooted the step traits and their tests under 'Steps\Generic' and 'Steps\Drupal'. @AlexSkrypnyk (#804)
  • [#776] Imported the driver layer under 'DrevOps\BehatSteps\Driver'. @AlexSkrypnyk (#802)
  • [#785] Added the scenario styles documentation page. @AlexSkrypnyk (#801)
  • [#724] Ordered every trait's members into one documented layout. @AlexSkrypnyk (#743)
  • [#714] Settled the negation shape, 'Normalize' spelling and getter naming across 44 trait methods. @AlexSkrypnyk (#800)
  • [#715] Tidied public-surface visibility, constants, property types, and hook signatures across traits. @AlexSkrypnyk (#795)
  • [#711] Aligned registered step text with the project step conventions. @AlexSkrypnyk (#793)
  • [#716] Unified the exception type thrown by assertion steps. @AlexSkrypnyk (#798)
  • [#733] Distinguished an absent query parameter from an empty or zero one. @AlexSkrypnyk (#797)
  • [#713] Prefixed every trait method with its trait name. @AlexSkrypnyk (#792)
  • [#712] Unified Gherkin placeholder names, articles and Given verbs across steps. @AlexSkrypnyk (#791)
  • [#790] Removed PHP 8.2 and Drupal 10 support, moved the fixture to Drupal 11.4 and upgraded dev tooling. @AlexSkrypnyk (#794)

Full Changelog: 3.14.4...4.0.0