PackageTrack
Sign in Get early access

drupal/drupal-extension

Drupal extension for Behat

v6.1.0 16M downloads/mo #1661 most downloaded on Packagist jhedstrom/drupalextension

What this package is like to depend on

Last release 2 months ago

22 Jun 2026

Release timing varies

gaps range from 2 weeks to 1.4 years

Rarely documented

notes for 8 of 69 stable releases

Nothing withdrawn

no release was ever pulled

14 years old

72 releases · first in 2012

12 releases in the last 12 months

see the full history below

Release timeline

72 releases · Jul 2012 to Jun 2026
2013 2015 2017 2019 2021 2023 2025
Release Pre-release

Releases

latest 60 of 72
  1. v6.1.0 22 Jun 2026
    Release notes

    What's new since v6.0.0

    Breaking changes

    • [#874] Removed the 'field_parser: legacy' parser. @AlexSkrypnyk (#880)
      The field_parser configuration node and its legacy value (which opted back into the pre-6.0 inline field syntax) are gone, so EntityFieldParser is now always active and accepts no configuration. Any field_parser key left in behat.yml now triggers a hard configuration error on load. To migrate, delete the field_parser entry from your Drupal\DrupalExtension config and convert any feature files still written in the legacy field syntax to the current syntax (see the field-syntax mapping table in UPGRADING.md).
    • [#876] Removed the 'region_map' configuration key. @AlexSkrypnyk (#879)
      The region_map key, superseded by the identically structured regions key in 6.0.0, has been removed, and a behat.yml that still uses it now fails to load with an "Unrecognized option" error. To migrate, rename region_map: to regions: in your Drupal\DrupalExtension configuration; the nested structure is unchanged, so only the key name needs updating.
    • [#875] Removed flat message selector keys. @AlexSkrypnyk (#878)
      The four flat keys under selectors: - message_selector, error_message_selector, success_message_selector, and warning_message_selector - are no longer accepted, and the nested selectors.messages: map (keyed default, error, success, warning) is now the only supported form. A missing selector now raises a RuntimeException naming the exact path to configure, e.g. Drupal\DrupalExtension.selectors.messages.error. To migrate, move each flat key into the nested map under its corresponding type.
    • [#873] Removed the legacy '<?name>' random token syntax. @AlexSkrypnyk (#877)
      The <?name> random-token form has been removed, leaving the typed [?name:type,args] syntax as the only one RandomContext understands. As a side effect RandomContext no longer implements ParametersAwareInterface or DeprecationInterface, so subclasses that relied on those members are affected. To migrate, replace every <?name> token in your feature files with the [?name] / [?name:type,args] form documented in docs/writing-tests.md.

    Highlights

    • [#597] Added HTTP Basic authentication support for sites behind webserver-level basic auth. @AlexSkrypnyk (#870)
      You can now test Drupal sites sitting behind Apache/Nginx HTTP Basic auth, which previously failed because fastLogout() reset the session and discarded the Authorization header, returning a 401 before the login form ever loaded. Credentials are read from a new basic_auth: {username, password} config node (or the base_url userinfo) and re-applied automatically after every session reset, so the whole login flow stays authenticated.
    • [#536] Added best-practice docs and a tested example for module-shipped Behat contexts. @AlexSkrypnyk (#869)
      A new "Shipping contexts in a module" guide documents where to place context classes, how to namespace them (Drupal\Tests\{module}\Behat\Context\), and how to wire PSR-4 autoloading for standalone Behat runs - filling the gap left when sub-context auto-discovery was removed. It is backed by a working ExampleContext in the behat_test fixture module that CI exercises under --strict, so the recommended pattern is proven rather than theoretical.
    • [#813] Added '@AfterScenario' cleanup of files attached through the UI. @AlexSkrypnyk (#868)
      Files uploaded via the I attach the file step are now tracked and their managed-file entities deleted after each scenario, so re-uploading the same filename is no longer silently renamed by Drupal (e.g. image.png becomes image_0.png) and breaking path-based assertions. Tag a scenario or feature with @no-file-cleanup to opt out; the hook is a no-op on blackbox and other non-in-process drivers.
    • [#672] Added email attachment assertion steps to 'MailContext'. @AlexSkrypnyk (#867)
      Four new Then steps let you assert that a sent email carries specific attachment(s), optionally filtered by recipient and/or subject, and the When I send the following (e)mail: step gains an attachments table column so tests can send mails with attachments in the first place. This makes it possible to verify attachment delivery end to end without writing custom step code.
    • [#734] Added steps to run a failing drush command and assert its output. @AlexSkrypnyk (#866)
      New I run the failing drush command steps run a Drush command expected to exit non-zero and capture its output so the existing the drush output should contain/match steps can assert on it, failing the step if the command unexpectedly succeeds. This closes the gap where a non-zero exit previously aborted the scenario before you could inspect the error output.
    • [#115] Added 'MappingContext' resolving '{{ Key }}' tokens from 'mappings' config. @AlexSkrypnyk (#865)
      A new MappingContext replaces {{ Key }} tokens in any step argument or table cell with values defined under a new mappings key in behat.yml, letting you centralise shared test data (URLs, labels, IDs) in one place instead of repeating literals across feature files. Keys must be globally unique - duplicates are rejected at config load - and an unknown key fails the step immediately rather than passing through unresolved.

    All changes

    • [#874] Removed the 'field_parser: legacy' parser. @AlexSkrypnyk (#880)
      Deletes the field_parser config node, the legacy value, and the backing LegacyEntityFieldParser class, leaving EntityFieldParser as the sole parser with no configuration. Any field_parser key in behat.yml now produces a hard configuration error on load.
    • [#876] Removed the 'region_map' configuration key. @AlexSkrypnyk (#879)
      Drops the region_map key from the config schema in favour of the identically structured regions key, so a stale region_map now fails to load with an "Unrecognized option" error. Rename the key to regions to upgrade.
    • [#875] Removed flat message selector keys. @AlexSkrypnyk (#878)
      Removes the flat message_selector, error_message_selector, success_message_selector, and warning_message_selector keys, so selectors must now live under the nested selectors.messages: map. An unconfigured selector throws a RuntimeException that names the exact nested path to add.
    • [#873] Removed the legacy '<?name>' random token syntax. @AlexSkrypnyk (#877)
      Removes the <?name> token form and the legacy parsing path from RandomContext, leaving the typed [?name:type,args] syntax as the only supported form. As a result RandomContext no longer implements ParametersAwareInterface or DeprecationInterface, and the per-run [Deprecation] notices it printed are gone.
    • Switched back to stable DrupalDriver. @AlexSkrypnyk (#872)
      Restores the drupal/drupal-driver requirement to a stable version range, replacing the temporary dev-master pin used while driver-side APIs needed by recent features were still unreleased. Consumers get a stable, tagged driver constraint again.
    • Updated information about maintainers. @AlexSkrypnyk (#871)
      Refreshes the project's maintainer information. A documentation-only change with no effect on the extension's behaviour.
    • [#597] Added HTTP Basic authentication support for sites behind webserver-level basic auth. @AlexSkrypnyk (#870)
      Adds first-class HTTP Basic auth: credentials from a new basic_auth config node (or the base_url userinfo) are applied to the Mink session and re-applied automatically after each reset, so logging into a site behind Apache/Nginx basic auth no longer fails with a 401. JavaScript/Selenium drivers, which cannot set request headers, fall back to the base_url userinfo and degrade to a silent no-op where unsupported.
    • [#536] Added best-practice docs and a tested example for module-shipped Behat contexts. @AlexSkrypnyk (#869)
      Adds a "Shipping contexts in a module" guide covering directory layout, namespacing, and PSR-4 autoloading for standalone Behat runs, plus a working ExampleContext and helper trait in the behat_test fixture module that CI exercises under --strict. This documents the recommended replacement for the removed sub-context auto-discovery.
    • [#813] Added '@AfterScenario' cleanup of files attached through the UI. @AlexSkrypnyk (#868)
      Tracks files uploaded via the I attach the file step and deletes their managed-file entities after each scenario, preventing Drupal from renaming a re-uploaded file (e.g. image.png to image_0.png) and breaking path-based assertions. Opt out per scenario or feature with @no-file-cleanup; the hook is a no-op on blackbox and other non-in-process drivers.
    • [#672] Added email attachment assertion steps to 'MailContext'. @AlexSkrypnyk (#867)
      Adds four Then steps that assert a sent email carries specific attachment(s), with optional recipient and subject filters, and extends When I send the following (e)mail: with an attachments table column so such mails can be sent in tests. Lets you verify attachment delivery without writing custom step definitions.
    • [#734] Added steps to run a failing drush command and assert its output. @AlexSkrypnyk (#866)
      Adds I run the failing drush command steps that execute a Drush command expected to exit non-zero, capture its output for the existing the drush output should contain/match assertions, and fail if the command unexpectedly exits 0. Previously a non-zero exit aborted the scenario before its error output could be checked.
    • [#115] Added 'MappingContext' resolving '{{ Key }}' tokens from 'mappings' config. @AlexSkrypnyk (#865)
      Adds a driver-free MappingContext that substitutes {{ Key }} tokens in step arguments and table cells with values defined under a new mappings key in behat.yml. Keys must be globally unique (duplicates are rejected at config load) and an unknown key fails the step rather than passing through unresolved.
    • [#860] Added a test for 'color_field' field support. @AlexSkrypnyk (#863)
      Adds end-to-end coverage for the contrib color_field module's color_field_type, driving a Gherkin table cell through the entity-field parser, the driver's ColorFieldTypeHandler (from drupal/drupal-driver v3.1.0), Drupal storage, and rendered output. It exercises both the bare-hex shorthand and the color/opacity form, covering the extension-level path a user actually drives.
    • [#861] Documented bracketed test markers as a compound-mode trigger in 'UPGRADING.md'. @AlexSkrypnyk (#862)
      Documents a non-obvious upgrade footgun: in the modern parser a compound column value beginning with [ (such as a [TEST] or [DEV] marker) is read as the start of a [name:value] token and causes a parse error. The new guidance shows that wrapping the value in double quotes makes the bracket literal, and explains why an unrelated column can tip a whole cell into compound mode.
    • Fixed PHPStan always-true comparison errors in docs generator and field parser. @AlexSkrypnyk (#864)
      Resolves three PHPStan always-true comparison errors that were failing ahoy lint, by dropping a provably-redundant condition in scripts/docs.php and reading the stop character in EntityFieldParser::parseScalarList() via substr() instead of offset indexing. Both changes are behavior-preserving, with no PHPStan config, baseline, or ignore annotations added.

    Full Changelog: v6.0.0...v6.1.0

    Open source →
    Release notes

    v6.1.0 Latest

    Latest

    Compare

    Choose a tag to compare

    Open source →
  2. v6.0.0 29 May 2026
    Release notes

    What's new since v6.0.0-rc2

    • Prepared v6 stable release: pinned 'drupal/drupal-driver' to stable v3 and tidied release docs. @AlexSkrypnyk (#859)

    Full Changelog: v6.0.0-rc2...v6.0.0

    @AlexSkrypnyk

    Migration

    For migration instructions, see UPGRADING.md.

    Implemented across pre-stable v6

    This combines the release notes from every pre-stable v6 release - v6.0.0-alpha1, v6.0.0-rc1, and v6.0.0-rc2. The complete set is what ships in v6.0.0 stable. Each section lists the items first introduced in that specific pre-release.

    v6.0.0-alpha1

    Version 6.0 enforces a consistent set of step-definition conventions across all bundled contexts. The conventions are documented in CONTRIBUTING.md and validated by scripts/docs.php; CI fails on any violation.

    See UPGRADING.md for detailed migration instructions covering all breaking changes, and the table below for a summary of highlights and breaking changes.

    Highlights

    • Updated 'drupal/drupal-driver' to 3.x and migrated to capability-based API. @AlexSkrypnyk (#803)
      The monolithic DriverInterface is replaced with capability interfaces (AuthenticationCapabilityInterface, MailCapabilityInterface, ConfigCapabilityInterface, ContentCapabilityInterface, CacheCapabilityInterface, CronCapabilityInterface, LanguageCapabilityInterface, RoleCapabilityInterface, UserCapabilityInterface) and every CRUD method is renamed to a verb-noun form. Migration: bump drupal/drupal-driver to ^3.0, rename driver calls (createNodenodeCreate, runCroncronRun, clearCachecacheClear, startCollectingMailmailStartCollecting, getMailmailGet, sendMailmailSend, etc.), and add capability-interface guards before invoking driver methods in subclasses.
    • [#469] Added typed random tokens with '[?name:type,args]' syntax and deprecated '<?name>' form. @AlexSkrypnyk (#844)
      RandomContext ships six built-in generators (string, name, machine_name, int, email, uuid) selectable via [?name:type,args], with subclasses able to register custom types by overriding a single method. Equivalent literals share a scenario-scoped cache key, so [?title], [?title:string], and [?title:string,10] all produce the same value within one scenario.
    • [#258] Added BigPipe NOJS cookie bypass to 'DrupalContext'. @AlexSkrypnyk (#821)
      Tagging a scenario with @bigpipe sets the big_pipe_nojs cookie on non-JS Mink drivers (BrowserKit, Goutte) so Drupal renders pages fully server-side instead of leaving placeholders that only the BigPipe JS would replace. This makes authenticated-user assertions like "I should see Log out" reliable on BigPipe-enabled sites without switching to a real browser.
    • [#732] Added 'login_field' configuration to submit a custom user property as the login value. @AlexSkrypnyk (#820)
      Sites that authenticate by email rather than username (via mail_login, email_registration, or similar contrib) can now set login_field: mail (or any other user property) under Drupal\DrupalExtension, and the auth manager submits that property value to the username field instead of the hardcoded name. The default remains name, so existing setups are unaffected.
    • [#766] Added modern entity-field parser with 'field_parser' configuration flag. @AlexSkrypnyk (#818)
      The new EntityFieldParser introduces double-quote escaping, named-column compound syntax (country:"BE", locality:"Brussel"), structured ParseException errors with file/line context, and aggregated multi-error reporting. Bare - is now treated as literal text in scalar mode, so entity reference titles like "My article - Part 2" no longer require escaping.
    • Added 'suppress_deprecations' configuration and 'BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS' environment variable. @AlexSkrypnyk (#836)
      Both the suppress_deprecations config key and the BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS env var silence the extension's [Deprecation] notices to STDERR, with the env var winning over config. This lets teams roll forward through migrations without their CI failing on deprecation noise from extension-detected legacy patterns.
    • [#647] Added 'BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP' env var to skip scenario teardown. @AlexSkrypnyk (#845)
      Setting BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP=1 (or true/yes/on) skips the AfterScenario teardown of entities, users, and roles, and intentionally leaves the last logged-in session open so a failing scenario's database state and browser session can be inspected directly. Intended for ad-hoc local debugging - leave it off in CI.
    • [#479] Added verbose diagnostic output to AJAX timeout exception. @AlexSkrypnyk (#838)
      iWaitForAjaxToFinish() now captures the current URL, jQuery.active count, animated-element count, and each active Drupal.ajax.instances entry (selector, event, URL) at the moment of timeout and embeds them in a structured multi-line error message. Replaces the previous single-line "Unable to complete AJAX request." message that gave no clue why the browser was busy.

    Breaking changes

    • Updated 'drupal/drupal-driver' to 3.x and migrated to capability-based API. @AlexSkrypnyk (#803)
      The monolithic DriverInterface is replaced with capability interfaces (AuthenticationCapabilityInterface, MailCapabilityInterface, ConfigCapabilityInterface, ContentCapabilityInterface, CacheCapabilityInterface, CronCapabilityInterface, LanguageCapabilityInterface, RoleCapabilityInterface, UserCapabilityInterface) and every CRUD method is renamed to a verb-noun form. Migration: bump drupal/drupal-driver to ^3.0, rename driver calls (createNodenodeCreate, runCroncronRun, clearCachecacheClear, startCollectingMailmailStartCollecting, getMailmailGet, sendMailmailSend, etc.), and add capability-interface guards before invoking driver methods in subclasses.
    • [#469] Added typed random tokens with '[?name:type,args]' syntax and deprecated '<?name>' form. @AlexSkrypnyk (#844)
      The legacy <?name> random-token form still works in 6.0 but emits a [Deprecation] notice once per literal. Migration: replace <?name> with [?name] (equivalent default) or one of the typed forms ([?slug:machine_name], [?age:int,18,99], [?email:email], [?id:uuid]); the legacy form is scheduled for removal in 6.1.
    • Renamed 'assert' action steps and tightened validator. @AlexSkrypnyk (#837)
      Action methods that previously used assertXxx names are renamed to action-style names (e.g. assertCroniRunCron, assertAuthenticatedByRoleiAmLoggedInAsUserWithRole, assertDrushCommandiRunDrush), and three negative-message steps move from @Given to @Then with matching method renames. Migration: see the rename table in MIGRATION.md and search-and-replace overridden method names in your subclasses; step text is unchanged for most steps but the three re-classified steps now require @Then semantics.
    • [#824] Converted 'BatchContext' into 'BatchTrait' on 'DrupalContext'. @AlexSkrypnyk (#835)
      BatchContext is deleted; its iWaitForTheBatchJobToFinish and thereIsAnItemInTheSystemQueue steps are now provided by DrupalContext via BatchTrait. Migration: remove Drupal\DrupalExtension\Context\BatchContext from the contexts: list in your behat.yml - the steps are loaded automatically with DrupalContext.
    • Moved driver and mail manager classes under 'Drupal\DrupalExtension\Manager' namespace. @AlexSkrypnyk (#833)
      Drupal\DrupalDriverManagerDrupal\DrupalExtension\Manager\DriverManager (the Drupal prefix drops), Drupal\DrupalDriverManagerInterfaceDrupal\DrupalExtension\Manager\DriverManagerInterface, Drupal\DrupalMailManagerDrupal\DrupalExtension\Manager\DrupalMailManager, Drupal\DrupalMailManagerInterfaceDrupal\DrupalExtension\Manager\DrupalMailManagerInterface. Migration: update use statements and any FQCN references; the user and authentication managers retain their existing namespaces.
    • Moved 'ParametersAwareInterface' to root namespace alongside 'ParametersTrait'. @AlexSkrypnyk (#832)
      The interface moved from Drupal\DrupalExtension\Context\ParametersAwareInterface to Drupal\DrupalExtension\ParametersAwareInterface. Migration: update use statements to import from the root namespace; signatures (setParameters, getParameter) are unchanged.
    • [#825] Extracted Drupal AJAX handling into 'DrupalAjaxTrait'. @AlexSkrypnyk (#830)
      The three Drupal-specific AJAX methods (iWaitForAjaxToFinish, beforeJavascriptStep, afterJavascriptStep) move from MinkContext into DrupalAjaxTrait. MinkContext composes the trait so existing consumers see no behavior change, but downstream subclasses that overrode these methods inline must now override the trait methods or compose DrupalAjaxTrait directly.
    • Moved 'ajax_timeout' to 'Drupal\DrupalExtension' and renamed parameters interface. @AlexSkrypnyk (#829)
      ajax_timeout configuration moves from Drupal\MinkExtension to Drupal\DrupalExtension, and the parameters API drops its Drupal prefix: DrupalParametersAwareInterfaceParametersAwareInterface, DrupalParametersTraitParametersTrait, setDrupalParameterssetParameters, getDrupalParametergetParameter, $drupalParameters$parameters. Migration: relocate ajax_timeout in behat.yml and rename interface/trait/method/property references in subclasses.
    • [#822] Rebased MessageContext on RawMinkContext and moved message selectors to Drupal\MinkExtension. @AlexSkrypnyk (#827)
      MessageContext now extends RawMinkContext instead of RawDrupalContext, so it can be registered in any Mink suite without booting the Drupal driver; subclasses that depended on RawDrupalContext helpers must compose ParametersTrait themselves or change their base. The four message selectors (message_selector, error_message_selector, success_message_selector, warning_message_selector) move from Drupal\DrupalExtension.selectors: to Drupal\MinkExtension.selectors:; the legacy location still works in 6.0 with a one-shot deprecation notice and is removed in 6.1.
    • [#258] Added BigPipe NOJS cookie bypass to 'DrupalContext'. @AlexSkrypnyk (#821)
      This is additive (opt-in via @bigpipe tag) but ships as part of DrupalContext, so subclasses that override the existing BeforeScenario / BeforeStep hook methods without calling parent will silently disable the bypass. Migration: if you override these hooks, call parent:: or use BigPipeTrait explicitly so the cookie management still runs.
    • Replaced Sphinx documentation with Markdown-based docs in 'docs/'. @AlexSkrypnyk (#819)
      The Read the Docs / Sphinx tree under doc/ is removed and replaced with Markdown under docs/. Migration: update bookmarks and any internal links pointing at doc/*.rst to the new docs/*.md paths; the Read the Docs site is no longer maintained.
    • [#766] Added modern entity-field parser with 'field_parser' configuration flag. @AlexSkrypnyk (#818)
      The default field-value parser is now EntityFieldParser, which uses double-quote escaping and detects compound mode by key:"value" form rather than - separator spacing. Migration: set field_parser: legacy under Drupal\DrupalExtension in behat.yml to keep the 5.x behavior (emits a one-shot deprecation notice); the legacy parser is removed in 6.1. Cells containing - no longer require escaping under the modern parser.
    • Renamed 'classifier()' calls to 'getFieldClassifier()' to match drupal-driver API. @AlexSkrypnyk (#817)
      The drupal-driver CoreInterface::classifier() accessor was renamed to getFieldClassifier(). Migration: replace direct calls of $driver->getCore()->classifier() with $driver->getCore()->getFieldClassifier(); no backwards-compatibility shim is provided.
    • [#337] Replaced 'stdClass' entity stubs with typed 'EntityStub' from driver. @AlexSkrypnyk (#814)
      Hook scopes (BeforeNodeCreateScope, AfterNodeCreateScope, etc.) and step methods now expose EntityStubInterface instead of \stdClass, and EntityScope::getEntity() is renamed to getStub(). Migration: replace ad-hoc property reads with $stub->getValue('title') and writes with $stub->setValue(...); replace (object) [...] constructions with new EntityStub($entity_type, $bundle, $values); replace $saved->nid / $saved->tid with $stub->getId(); rename getEntity() calls to getStub().
    • [#806] Removed 'store' parameter from 'DrupalMailManager' and 'DrupalMailManagerInterface'. @AlexSkrypnyk (#812)
      getMail() and clearMail() no longer accept a $store argument because the v3 driver only exposes a single implicit collector. Migration: drop the $store argument from any direct calls and from any subclass overrides that implement DrupalMailManagerInterface; tracked counts in RawMailContext are now a scalar int rather than an array keyed by store.
    • [#752] Replaced generic exceptions with typed Mink exceptions across bundled contexts. @AlexSkrypnyk (#811)
      Roughly 30 \Exception throws across the bundled contexts are replaced with Behat\Mink\Exception\ElementNotFoundException (lookups), Behat\Mink\Exception\ExpectationException (assertion mismatches), or \RuntimeException (configuration errors). Migration: any tests or hooks that catch \Exception from these steps continue to work, but code that asserts on specific exception classes or messages must update to the typed classes; Mink exceptions append URL and page-snippet context via __toString().
    • Enforced step-definition conventions for v6 across all bundled contexts. @AlexSkrypnyk (#810)
      Roughly 50 @Then methods are renamed to <concern>Assert<action> form, around 29 step texts are updated to satisfy the new conventions (e.g. Given users:Given the following users:, Then drush output should contain XThen the drush output should contain X, Then I log outWhen I log out), and several methods are re-categorised from @Then to @When for side-effect steps. Migration: search-and-replace step text in your feature files using the table in MIGRATION.md; rename overridden method names in your subclasses.
    • Removed deprecated APIs in preparation for 6.0.0. @AlexSkrypnyk (#809)
      Subcontext auto-discovery (subcontexts.paths config, .behat.inc loading, DrupalSubContextInterface, DrupalSubContextBase), the annotation-based hook reader (Annotation\Reader), RawDrupalContext::loggedInWithRole(), and the AnnotatedDefinitionProposal shim are all removed. Migration: rewrite subcontexts as regular Behat contexts using PHP attributes; remove any subcontexts: block from behat.yml; replace loggedInWithRole() calls with the standard authenticated-user flow.
    • [#823] Rebased 'RandomContext' on bare Behat context interface. @AlexSkrypnyk (#834)
      RandomContext no longer extends RawDrupalContext; it implements Behat\Behat\Context\Context directly and instantiates a Random lazily. Migration: subclassers that relied on inherited Drupal/Mink helpers must compose those traits themselves or change their base class; documented in MIGRATION.md under "RandomContext base class".

    All changes

    • [#356] Strengthened 'author' property test to assert author is applied. @AlexSkrypnyk (#847)
      The existing scenario for the author property in Given the following :type content: was rewritten as a direct test that creates an article with author = Joe User, visits /admin/content, and asserts Joe User appears in the article's author column. Previously the scenario only verified the syntax did not error.
    • [#647] Added 'BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP' env var to skip scenario teardown. @AlexSkrypnyk (#845)
      Setting BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP=1 (or true/yes/on) skips the AfterScenario teardown of entities, users, and roles, and intentionally leaves the last logged-in session open so a failing scenario's database state and browser session can be inspected directly. Intended for ad-hoc local debugging - leave it off in CI.
    • [#735] Added test coverage and docs for options in 'I run drush :command :arguments' step. @AlexSkrypnyk (#846)
      The existing I run drush :command :arguments step already supported flags because the arguments string is appended verbatim to the shell command, but this was undocumented. The docblock now shows a combined positional-argument-plus-flag example, and a new scenario exercises config:get "system.site uuid --format=string" end to end.
    • [#469] Added typed random tokens with '[?name:type,args]' syntax and deprecated '<?name>' form. @AlexSkrypnyk (#844)
      RandomContext ships six built-in generators (string, name, machine_name, int, email, uuid) selectable via [?name:type,args], with subclasses able to register custom types by overriding a single method. Equivalent literals share a scenario-scoped cache key, so [?title], [?title:string], and [?title:string,10] all produce the same value within one scenario.
    • [#733] Added test coverage and docs for configurable login and logout URLs. @AlexSkrypnyk (#843)
      Three new PHPUnit tests pin the visit() argument so a regression that hardcoded /user back into DrupalAuthenticationManager would now fail loudly, and the logout_confirm_url entry was added to the documented text: example so all three login/logout URL keys are visible together.
    • [#415] Added test coverage for URI-only link field values. @AlexSkrypnyk (#841)
      Five new Behat scenarios exercise URI-only link field values - bare URIs, comma-separated lists, the named uri: compound column, and a mixed scenario - covering the upstream LinkHandler fix in drupal-driver that wraps a bare string as ['uri' => $value].
    • Fixed chrome port and AJAX assertion after Pygmy and Lagoon stack migration. @AlexSkrypnyk (#840)
      The Selenium VNC port mapping was changed from a fixed 7900:7900 host binding to a Docker-assigned ephemeral port to avoid conflicts, and the AJAX timeout assertion in FeatureContext no longer hardcodes http://blackbox so it works against the new in-process PHP server (http://cli:8888). CONTRIBUTING.md now documents how to read the dynamic VNC URL from ahoy info.
    • [#730] Migrated local stack to Pygmy and Lagoon images. @AlexSkrypnyk (#839)
      The Wodby + Traefik local stack is replaced with Lagoon container images fronted by Pygmy, matching the layout used by drevops/behat-steps. The blackbox nginx container is dropped in favour of an in-process PHP server started by BlackboxServerContext inside the cli container, the drupal_https profile is removed, and provisioning steps move into a single scripts/provision.sh shared by ahoy and CI.
    • [#479] Added verbose diagnostic output to AJAX timeout exception. @AlexSkrypnyk (#838)
      iWaitForAjaxToFinish() now captures the current URL, jQuery.active count, animated-element count, and each active Drupal.ajax.instances entry (selector, event, URL) at the moment of timeout and embeds them in a structured multi-line error message. Replaces the previous single-line "Unable to complete AJAX request." message that gave no clue why the browser was busy.
    • Renamed 'assert' action steps and tightened validator. @AlexSkrypnyk (#837)
      Action methods that previously used assertXxx names are renamed to action-style names (e.g. assertCroniRunCron, assertAuthenticatedByRoleiAmLoggedInAsUserWithRole, assertDrushCommandiRunDrush), and three negative-message steps move from @Given to @Then with matching method renames. The validator now hard-fails when @Given/@When step text contains should or method names contain Assert.
    • Added 'suppress_deprecations' configuration and 'BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS' environment variable. @AlexSkrypnyk (#836)
      Both the suppress_deprecations config key and the BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS env var silence the extension's [Deprecation] notices to STDERR, with the env var winning over config. This lets teams roll forward through migrations without their CI failing on deprecation noise from extension-detected legacy patterns.
    • [#824] Converted 'BatchContext' into 'BatchTrait' on 'DrupalContext'. @AlexSkrypnyk (#835)
      BatchContext is deleted; its iWaitForTheBatchJobToFinish and thereIsAnItemInTheSystemQueue steps are now provided by DrupalContext via BatchTrait. Both steps depend on \Drupal:: calls, so hosting them on the API-driver-only DrupalContext keeps them behind a bootstrapped Drupal kernel and prevents silent failures under Blackbox or Drush drivers.
    • Moved driver and mail manager classes under 'Drupal\DrupalExtension\Manager' namespace. @AlexSkrypnyk (#833)
      Drupal\DrupalDriverManagerDrupal\DrupalExtension\Manager\DriverManager (the Drupal prefix drops because driver routing is generic infrastructure), and the mail manager and its interface move alongside the user/auth managers under the same namespace. The dead psr-0 autoload entry in composer.json is removed.
    • [#823] Rebased 'RandomContext' on bare Behat context interface. @AlexSkrypnyk (#834)
      RandomContext no longer extends RawDrupalContext; it implements Behat\Behat\Context\Context directly and instantiates a Random lazily, so the context can be registered in any Behat suite regardless of whether the Drupal extension is loaded. New PHPUnit tests cover the standalone shape and the token substitution contract.
    • Moved 'ParametersAwareInterface' to root namespace alongside 'ParametersTrait'. @AlexSkrypnyk (#832)
      The interface moved from Drupal\DrupalExtension\Context\ParametersAwareInterface to Drupal\DrupalExtension\ParametersAwareInterface so it sits next to its companion ParametersTrait and RegionTrait. setParameters / getParameter signatures are unchanged - only the FQN moves.
    • [#826] Documented 'ParametersTrait' and 'RegionTrait' as Mink-only consumption points. @AlexSkrypnyk (#831)
      The two traits work on any RawMinkContext consumer without requiring a Drupal driver bootstrap; the trait docblocks and a new "Mink-only contexts" section in docs/contexts.md make the pattern explicit. The bundled MinkContext, MarkupContext, and MessageContext already follow this pattern.
    • [#825] Extracted Drupal AJAX handling into 'DrupalAjaxTrait'. @AlexSkrypnyk (#830)
      The three Drupal-specific AJAX methods (iWaitForAjaxToFinish, beforeJavascriptStep, afterJavascriptStep) move from MinkContext into DrupalAjaxTrait; MinkContext composes the trait so existing consumers see no behavior change. The trait can now be reused in custom Mink-based contexts without inheriting from MinkContext.
    • Moved 'ajax_timeout' to 'Drupal\DrupalExtension' and renamed parameters interface. @AlexSkrypnyk (#829)
      ajax_timeout configuration moves from Drupal\MinkExtension to Drupal\DrupalExtension so all custom config lives under one extension, and the parameters API drops its Drupal prefix throughout: interface, trait, methods, and property name. The Drupal\MinkExtension extension now only registers the BrowserKit driver factory.
    • Moved 'ClassGenerator' out of 'Context/ContextClass/' into a top-level 'Generator/' namespace. @AlexSkrypnyk (#828)
      ClassGenerator (Behat's behat --init scaffolder for Drupal context classes) moves from Drupal\DrupalExtension\Context\ContextClass to Drupal\DrupalExtension\Generator, away from the actual step-defining contexts. The class is only instantiated by Behat's DI from inside the extension, so no downstream user code is affected. New PHPUnit tests cover both namespaced and rootless context-class generation.
    • [#822] Rebased MessageContext on RawMinkContext and moved message selectors to Drupal\MinkExtension. @AlexSkrypnyk (#827)
      MessageContext now extends RawMinkContext instead of RawDrupalContext, so blackbox-only suites no longer pay the cost of booting the Drupal driver stack. The four message selectors move from Drupal\DrupalExtension.selectors: to a new Drupal\MinkExtension.selectors: map; the legacy location keeps working in 6.0 with a one-shot deprecation notice.
    • [#258] Added BigPipe NOJS cookie bypass to 'DrupalContext'. @AlexSkrypnyk (#821)
      Tagging a scenario with @bigpipe sets the big_pipe_nojs cookie on non-JS Mink drivers so Drupal renders pages fully server-side instead of leaving placeholders that only the BigPipe JS would replace. The cookie is re-applied on every step because login redirects drop session cookies, and the trait is a no-op when the active driver supports JavaScript.
    • [#732] Added 'login_field' configuration to submit a custom user property as the login value. @AlexSkrypnyk (#820)
      Sites that authenticate by email rather than username (via mail_login, email_registration, or similar contrib) can now set login_field: mail (or any other user property) under Drupal\DrupalExtension, and the auth manager submits that property value to the username field instead of the hardcoded name. The default remains name, so existing setups are unaffected.
    • Replaced Sphinx documentation with Markdown-based docs in 'docs/'. @AlexSkrypnyk (#819)
      The Read the Docs / Sphinx tree under doc/ is removed and replaced with plain Markdown under docs/ covering installation, configuration, drivers, contexts, hooks, and writing tests. The Read the Docs badge and links in README.md are also dropped.
    • [#766] Added modern entity-field parser with 'field_parser' configuration flag. @AlexSkrypnyk (#818)
      The new EntityFieldParser introduces double-quote escaping, named-column compound syntax (country:"BE", locality:"Brussel"), structured ParseException errors with file/line context, and aggregated multi-error reporting. Bare - is now treated as literal text in scalar mode, so entity reference titles like "My article - Part 2" no longer require escaping.
    • [#766] Extracted field parsing into 'ParserInterface' and 'LegacyEntityFieldsParser'. @AlexSkrypnyk (#816)
      This is a pure refactor that lifts the cell-level field-value parsing out of RawDrupalContext::parseEntityFields() into a new LegacyEntityFieldsParser implementing a new ParserInterface. Behavior is unchanged in this PR; the contract is introduced first so the new modern parser (#818) can land against a stable interface.
    • Renamed 'classifier()' calls to 'getFieldClassifier()' to match drupal-driver API. @AlexSkrypnyk (#817)
      The drupal-driver CoreInterface::classifier() accessor was renamed to getFieldClassifier() upstream, and this PR updates the single call site in parseEntityFields() and the four mock setups in RawDrupalContextTest. No backwards-compatibility shim is provided.
    • Removed PHPSpec-based unit testing from the project. @AlexSkrypnyk (#815)
      The 22 PHPSpec spec files, the test-phpspec ahoy command, and the phpspec/phpspec Composer dev dependency are all removed; PHPUnit and Behat already cover the same ground. CI now runs one fewer parallel step.
    • [#337] Replaced 'stdClass' entity stubs with typed 'EntityStub' from driver. @AlexSkrypnyk (

    Note truncated.

    Open source →
    Release notes

    Breaking changes

    • [ #874 ] Removed the 'field_parser: legacy' parser. @AlexSkrypnyk ( #880 ) The field_parser configuration node and its legacy value (which opted back into the pre-6.0 inline field syntax) are gone, so EntityFieldParser is now always active and accepts no configuration. Any field_parser key left in behat.yml now triggers a hard configuration error on load. To migrate, delete the field_parser entry from your Drupal\DrupalExtension config and convert any feature files still written in the legacy field syntax to the current syntax (see the field-syntax mapping table in UPGRADING.md ).

    • [ #876 ] Removed the 'region_map' configuration key. @AlexSkrypnyk ( #879 ) The region_map key, superseded by the identically structured regions key in 6.0.0, has been removed, and a behat.yml that still uses it now fails to load with an "Unrecognized option" error. To migrate, rename region_map: to regions: in your Drupal\DrupalExtension configuration; the nested structure is unchanged, so only the key name needs updating.

    • [ #875 ] Removed flat message selector keys. @AlexSkrypnyk ( #878 ) The four flat keys under selectors: - message_selector , error_message_selector , success_message_selector , and warning_message_selector - are no longer accepted, and the nested selectors.messages: map (keyed default , error , success , warning ) is now the only supported form. A missing selector now raises a RuntimeException naming the exact path to configure, e.g. Drupal\DrupalExtension.selectors.messages.error . To migrate, move each flat key into the nested map under its corresponding type.

    • [ #873 ] Removed the legacy '<?name>' random token syntax. @AlexSkrypnyk ( #877 ) The <?name> random-token form has been removed, leaving the typed [?name:type,args] syntax as the only one RandomContext understands. As a side effect RandomContext no longer implements ParametersAwareInterface or DeprecationInterface , so subclasses that relied on those members are affected. To migrate, replace every <?name> token in your feature files with the [?name] / [?name:type,args] form documented in docs/writing-tests.md .

    Highlights

    • [ #597 ] Added HTTP Basic authentication support for sites behind webserver-level basic auth. @AlexSkrypnyk ( #870 ) You can now test Drupal sites sitting behind Apache/Nginx HTTP Basic auth, which previously failed because fastLogout() reset the session and discarded the Authorization header, returning a 401 before the login form ever loaded. Credentials are read from a new basic_auth: {username, password} config node (or the base_url userinfo) and re-applied automatically after every session reset, so the whole login flow stays authenticated.

    • [ #536 ] Added best-practice docs and a tested example for module-shipped Behat contexts. @AlexSkrypnyk ( #869 ) A new "Shipping contexts in a module" guide documents where to place context classes, how to namespace them ( Drupal\Tests{module}\Behat\Context\ ), and how to wire PSR-4 autoloading for standalone Behat runs - filling the gap left when sub-context auto-discovery was removed. It is backed by a working ExampleContext in the behat_test fixture module that CI exercises under --strict , so the recommended pattern is proven rather than theoretical.

    • [ #813 ] Added '@AfterScenario' cleanup of files attached through the UI. @AlexSkrypnyk ( #868 ) Files uploaded via the I attach the file step are now tracked and their managed-file entities deleted after each scenario, so re-uploading the same filename is no longer silently renamed by Drupal (e.g. image.png becomes image_0.png ) and breaking path-based assertions. Tag a scenario or feature with @no-file-cleanup to opt out; the hook is a no-op on blackbox and other non-in-process drivers.

    • [ #672 ] Added email attachment assertion steps to 'MailContext'. @AlexSkrypnyk ( #867 ) Four new Then steps let you assert that a sent email carries specific attachment(s), optionally filtered by recipient and/or subject, and the When I send the following (e)mail: step gains an attachments table column so tests can send mails with attachments in the first place. This makes it possible to verify attachment delivery end to end without writing custom step code.

    • [ #734 ] Added steps to run a failing drush command and assert its output. @AlexSkrypnyk ( #866 ) New I run the failing drush command steps run a Drush command expected to exit non-zero and capture its output so the existing the drush output should contain/match steps can assert on it, failing the step if the command unexpectedly succeeds. This closes the gap where a non-zero exit previously aborted the scenario before you could inspect the error output.

    • [ #115 ] Added 'MappingContext' resolving '{{ Key }}' tokens from 'mappings' config. @AlexSkrypnyk ( #865 ) A new MappingContext replaces {{ Key }} tokens in any step argument or table cell with values defined under a new mappings key in behat.yml , letting you centralise shared test data (URLs, labels, IDs) in one place instead of repeating literals across feature files. Keys must be globally unique - duplicates are rejected at config load - and an unknown key fails the step immediately rather than passing through unresolved.

    All changes

    • [ #874 ] Removed the 'field_parser: legacy' parser. @AlexSkrypnyk ( #880 ) Deletes the field_parser config node, the legacy value, and the backing LegacyEntityFieldParser class, leaving EntityFieldParser as the sole parser with no configuration. Any field_parser key in behat.yml now produces a hard configuration error on load.

    • [ #876 ] Removed the 'region_map' configuration key. @AlexSkrypnyk ( #879 ) Drops the region_map key from the config schema in favour of the identically structured regions key, so a stale region_map now fails to load with an "Unrecognized option" error. Rename the key to regions to upgrade.

    • [ #875 ] Removed flat message selector keys. @AlexSkrypnyk ( #878 ) Removes the flat message_selector , error_message_selector , success_message_selector , and warning_message_selector keys, so selectors must now live under the nested selectors.messages: map. An unconfigured selector throws a RuntimeException that names the exact nested path to add.

    • [ #873 ] Removed the legacy '<?name>' random token syntax. @AlexSkrypnyk ( #877 ) Removes the <?name> token form and the legacy parsing path from RandomContext , leaving the typed [?name:type,args] syntax as the only supported form. As a result RandomContext no longer implements ParametersAwareInterface or DeprecationInterface , and the per-run [Deprecation] notices it printed are gone.

    • Switched back to stable DrupalDriver. @AlexSkrypnyk ( #872 ) Restores the drupal/drupal-driver requirement to a stable version range, replacing the temporary dev-master pin used while driver-side APIs needed by recent features were still unreleased. Consumers get a stable, tagged driver constraint again.

    • Updated information about maintainers. @AlexSkrypnyk ( #871 ) Refreshes the project's maintainer information. A documentation-only change with no effect on the extension's behaviour.

    • [ #597 ] Added HTTP Basic authentication support for sites behind webserver-level basic auth. @AlexSkrypnyk ( #870 ) Adds first-class HTTP Basic auth: credentials from a new basic_auth config node (or the base_url userinfo) are applied to the Mink session and re-applied automatically after each reset, so logging into a site behind Apache/Nginx basic auth no longer fails with a 401 . JavaScript/Selenium drivers, which cannot set request headers, fall back to the base_url userinfo and degrade to a silent no-op where unsupported.

    • [ #536 ] Added best-practice docs and a tested example for module-shipped Behat contexts. @AlexSkrypnyk ( #869 ) Adds a "Shipping contexts in a module" guide covering directory layout, namespacing, and PSR-4 autoloading for standalone Behat runs, plus a working ExampleContext and helper trait in the behat_test fixture module that CI exercises under --strict . This documents the recommended replacement for the removed sub-context auto-discovery.

    • [ #813 ] Added '@AfterScenario' cleanup of files attached through the UI. @AlexSkrypnyk ( #868 ) Tracks files uploaded via the I attach the file step and deletes their managed-file entities after each scenario, preventing Drupal from renaming a re-uploaded file (e.g. image.png to image_0.png ) and breaking path-based assertions. Opt out per scenario or feature with @no-file-cleanup ; the hook is a no-op on blackbox and other non-in-process drivers.

    • [ #672 ] Added email attachment assertion steps to 'MailContext'. @AlexSkrypnyk ( #867 ) Adds four Then steps that assert a sent email carries specific attachment(s), with optional recipient and subject filters, and extends When I send the following (e)mail: with an attachments table column so such mails can be sent in tests. Lets you verify attachment delivery without writing custom step definitions.

    • [ #734 ] Added steps to run a failing drush command and assert its output. @AlexSkrypnyk ( #866 ) Adds I run the failing drush command steps that execute a Drush command expected to exit non-zero, capture its output for the existing the drush output should contain/match assertions, and fail if the command unexpectedly exits 0. Previously a non-zero exit aborted the scenario before its error output could be checked.

    • [ #115 ] Added 'MappingContext' resolving '{{ Key }}' tokens from 'mappings' config. @AlexSkrypnyk ( #865 ) Adds a driver-free MappingContext that substitutes {{ Key }} tokens in step arguments and table cells with values defined under a new mappings key in behat.yml . Keys must be globally unique (dupl...

    Read more

    Contributors

    AlexSkrypnyk

    Assets 2 Loading

    Uh oh!

    There was an error while loading. Please reload this page .

    All reactions

    Open source →
  3. v6.0.0-rc2 19 May 2026 pre-release
    Release notes

    What's new since v6.0.0-rc1

    Full Changelog: v6.0.0-rc1...v6.0.0-rc2

    @AlexSkrypnyk

    Open source →
    Release notes
    • Prepared v6 stable release: pinned 'drupal/drupal-driver' to stable v3 and tidied release docs. @AlexSkrypnyk ( #859 )

    Full Changelog : v6.0.0-rc2...v6.0.0

    @AlexSkrypnyk

    Open source →
  4. v6.0.0-rc1 18 May 2026 pre-release
    Release notes

    What's new since v6.0.0-alpha1

    • Bumped 'drupal/drupal-driver' to 3.0.0-rc1 and tightened 'minimum-stability' to RC. @AlexSkrypnyk (#856)
    • [#854] Made 'Before/AfterEntityCreate' hooks fire for every entity create path. @AlexSkrypnyk (#855)
    • [#194] Added 'Given the following :type entities:' step for generic entity creation. @AlexSkrypnyk (#853)
    • Allowed bundle fields defined in hooks to be recognised. @AlexSkrypnyk (#852)

    Full Changelog: v6.0.0-alpha1...v6.0.0-rc1

    @AlexSkrypnyk

    Open source →
    Release notes
    • [ #857 ] Allowed literal '"' inside unquoted scalar values. @AlexSkrypnyk ( #858 )

    Full Changelog : v6.0.0-rc1...v6.0.0-rc2

    @AlexSkrypnyk

    Contributors

    AlexSkrypnyk

    Assets 2 Loading

    Uh oh!

    There was an error while loading. Please reload this page .

    All reactions

    Open source →
  5. v6.0.0-alpha1 04 May 2026 pre-release
    Release notes

    What's new since v5.4.0

    Version 6.0 enforces a consistent set of step-definition conventions across all bundled contexts. The conventions are documented inCONTRIBUTING.md and validated by scripts/docs.php; CI fails on any violation.

    See UPGRADING.md for detailed migration instructions covering all breaking changes, and the table below for a summary of highlights and breaking changes.

    Highlights

    • Updated 'drupal/drupal-driver' to 3.x and migrated to capability-based API. @AlexSkrypnyk (#803)
      The monolithic DriverInterface is replaced with capability interfaces (AuthenticationCapabilityInterface, MailCapabilityInterface, ConfigCapabilityInterface, ContentCapabilityInterface, CacheCapabilityInterface, CronCapabilityInterface, LanguageCapabilityInterface, RoleCapabilityInterface, UserCapabilityInterface) and every CRUD method is renamed to a verb-noun form. Migration: bump drupal/drupal-driver to ^3.0, rename driver calls (createNodenodeCreate, runCroncronRun, clearCachecacheClear, startCollectingMailmailStartCollecting, getMailmailGet, sendMailmailSend, etc.), and add capability-interface guards before invoking driver methods in subclasses.
    • [#469] Added typed random tokens with '[?name:type,args]' syntax and deprecated '<?name>' form. @AlexSkrypnyk (#844)
      RandomContext ships six built-in generators (string, name, machine_name, int, email, uuid) selectable via [?name:type,args], with subclasses able to register custom types by overriding a single method. Equivalent literals share a scenario-scoped cache key, so [?title], [?title:string], and [?title:string,10] all produce the same value within one scenario.
    • [#258] Added BigPipe NOJS cookie bypass to 'DrupalContext'. @AlexSkrypnyk (#821)
      Tagging a scenario with @bigpipe sets the big_pipe_nojs cookie on non-JS Mink drivers (BrowserKit, Goutte) so Drupal renders pages fully server-side instead of leaving placeholders that only the BigPipe JS would replace. This makes authenticated-user assertions like "I should see Log out" reliable on BigPipe-enabled sites without switching to a real browser.
    • [#732] Added 'login_field' configuration to submit a custom user property as the login value. @AlexSkrypnyk (#820)
      Sites that authenticate by email rather than username (via mail_login, email_registration, or similar contrib) can now set login_field: mail (or any other user property) under Drupal\DrupalExtension, and the auth manager submits that property value to the username field instead of the hardcoded name. The default remains name, so existing setups are unaffected.
    • [#766] Added modern entity-field parser with 'field_parser' configuration flag. @AlexSkrypnyk (#818)
      The new EntityFieldParser introduces double-quote escaping, named-column compound syntax (country:"BE", locality:"Brussel"), structured ParseException errors with file/line context, and aggregated multi-error reporting. Bare - is now treated as literal text in scalar mode, so entity reference titles like "My article - Part 2" no longer require escaping.
    • Added 'suppress_deprecations' configuration and 'BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS' environment variable. @AlexSkrypnyk (#836)
      Both the suppress_deprecations config key and the BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS env var silence the extension's [Deprecation] notices to STDERR, with the env var winning over config. This lets teams roll forward through migrations without their CI failing on deprecation noise from extension-detected legacy patterns.
    • [#647] Added 'BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP' env var to skip scenario teardown. @AlexSkrypnyk (#845)
      Setting BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP=1 (or true/yes/on) skips the AfterScenario teardown of entities, users, and roles, and intentionally leaves the last logged-in session open so a failing scenario's database state and browser session can be inspected directly. Intended for ad-hoc local debugging - leave it off in CI.
    • [#479] Added verbose diagnostic output to AJAX timeout exception. @AlexSkrypnyk (#838)
      iWaitForAjaxToFinish() now captures the current URL, jQuery.active count, animated-element count, and each active Drupal.ajax.instances entry (selector, event, URL) at the moment of timeout and embeds them in a structured multi-line error message. Replaces the previous single-line "Unable to complete AJAX request." message that gave no clue why the browser was busy.

    Breaking changes

    • Updated 'drupal/drupal-driver' to 3.x and migrated to capability-based API. @AlexSkrypnyk (#803)
      The monolithic DriverInterface is replaced with capability interfaces (AuthenticationCapabilityInterface, MailCapabilityInterface, ConfigCapabilityInterface, ContentCapabilityInterface, CacheCapabilityInterface, CronCapabilityInterface, LanguageCapabilityInterface, RoleCapabilityInterface, UserCapabilityInterface) and every CRUD method is renamed to a verb-noun form. Migration: bump drupal/drupal-driver to ^3.0, rename driver calls (createNodenodeCreate, runCroncronRun, clearCachecacheClear, startCollectingMailmailStartCollecting, getMailmailGet, sendMailmailSend, etc.), and add capability-interface guards before invoking driver methods in subclasses.
    • [#469] Added typed random tokens with '[?name:type,args]' syntax and deprecated '<?name>' form. @AlexSkrypnyk (#844)
      The legacy <?name> random-token form still works in 6.0 but emits a [Deprecation] notice once per literal. Migration: replace <?name> with [?name] (equivalent default) or one of the typed forms ([?slug:machine_name], [?age:int,18,99], [?email:email], [?id:uuid]); the legacy form is scheduled for removal in 6.1.
    • Renamed 'assert' action steps and tightened validator. @AlexSkrypnyk (#837)
      Action methods that previously used assertXxx names are renamed to action-style names (e.g. assertCroniRunCron, assertAuthenticatedByRoleiAmLoggedInAsUserWithRole, assertDrushCommandiRunDrush), and three negative-message steps move from @Given to @Then with matching method renames. Migration: see the rename table in MIGRATION.md and search-and-replace overridden method names in your subclasses; step text is unchanged for most steps but the three re-classified steps now require @Then semantics.
    • [#824] Converted 'BatchContext' into 'BatchTrait' on 'DrupalContext'. @AlexSkrypnyk (#835)
      BatchContext is deleted; its iWaitForTheBatchJobToFinish and thereIsAnItemInTheSystemQueue steps are now provided by DrupalContext via BatchTrait. Migration: remove Drupal\DrupalExtension\Context\BatchContext from the contexts: list in your behat.yml - the steps are loaded automatically with DrupalContext.
    • Moved driver and mail manager classes under 'Drupal\DrupalExtension\Manager' namespace. @AlexSkrypnyk (#833)
      Drupal\DrupalDriverManagerDrupal\DrupalExtension\Manager\DriverManager (the Drupal prefix drops), Drupal\DrupalDriverManagerInterfaceDrupal\DrupalExtension\Manager\DriverManagerInterface, Drupal\DrupalMailManagerDrupal\DrupalExtension\Manager\DrupalMailManager, Drupal\DrupalMailManagerInterfaceDrupal\DrupalExtension\Manager\DrupalMailManagerInterface. Migration: update use statements and any FQCN references; the user and authentication managers retain their existing namespaces.
    • Moved 'ParametersAwareInterface' to root namespace alongside 'ParametersTrait'. @AlexSkrypnyk (#832)
      The interface moved from Drupal\DrupalExtension\Context\ParametersAwareInterface to Drupal\DrupalExtension\ParametersAwareInterface. Migration: update use statements to import from the root namespace; signatures (setParameters, getParameter) are unchanged.
    • [#825] Extracted Drupal AJAX handling into 'DrupalAjaxTrait'. @AlexSkrypnyk (#830)
      The three Drupal-specific AJAX methods (iWaitForAjaxToFinish, beforeJavascriptStep, afterJavascriptStep) move from MinkContext into DrupalAjaxTrait. MinkContext composes the trait so existing consumers see no behavior change, but downstream subclasses that overrode these methods inline must now override the trait methods or compose DrupalAjaxTrait directly.
    • Moved 'ajax_timeout' to 'Drupal\DrupalExtension' and renamed parameters interface. @AlexSkrypnyk (#829)
      ajax_timeout configuration moves from Drupal\MinkExtension to Drupal\DrupalExtension, and the parameters API drops its Drupal prefix: DrupalParametersAwareInterfaceParametersAwareInterface, DrupalParametersTraitParametersTrait, setDrupalParameterssetParameters, getDrupalParametergetParameter, $drupalParameters$parameters. Migration: relocate ajax_timeout in behat.yml and rename interface/trait/method/property references in subclasses.
    • [#822] Rebased MessageContext on RawMinkContext and moved message selectors to Drupal\MinkExtension. @AlexSkrypnyk (#827)
      MessageContext now extends RawMinkContext instead of RawDrupalContext, so it can be registered in any Mink suite without booting the Drupal driver; subclasses that depended on RawDrupalContext helpers must compose ParametersTrait themselves or change their base. The four message selectors (message_selector, error_message_selector, success_message_selector, warning_message_selector) move from Drupal\DrupalExtension.selectors: to Drupal\MinkExtension.selectors:; the legacy location still works in 6.0 with a one-shot deprecation notice and is removed in 6.1.
    • [#258] Added BigPipe NOJS cookie bypass to 'DrupalContext'. @AlexSkrypnyk (#821)
      This is additive (opt-in via @bigpipe tag) but ships as part of DrupalContext, so subclasses that override the existing BeforeScenario / BeforeStep hook methods without calling parent will silently disable the bypass. Migration: if you override these hooks, call parent:: or use BigPipeTrait explicitly so the cookie management still runs.
    • Replaced Sphinx documentation with Markdown-based docs in 'docs/'. @AlexSkrypnyk (#819)
      The Read the Docs / Sphinx tree under doc/ is removed and replaced with Markdown under docs/. Migration: update bookmarks and any internal links pointing at doc/*.rst to the new docs/*.md paths; the Read the Docs site is no longer maintained.
    • [#766] Added modern entity-field parser with 'field_parser' configuration flag. @AlexSkrypnyk (#818)
      The default field-value parser is now EntityFieldParser, which uses double-quote escaping and detects compound mode by key:"value" form rather than - separator spacing. Migration: set field_parser: legacy under Drupal\DrupalExtension in behat.yml to keep the 5.x behavior (emits a one-shot deprecation notice); the legacy parser is removed in 6.1. Cells containing - no longer require escaping under the modern parser.
    • Renamed 'classifier()' calls to 'getFieldClassifier()' to match drupal-driver API. @AlexSkrypnyk (#817)
      The drupal-driver CoreInterface::classifier() accessor was renamed to getFieldClassifier(). Migration: replace direct calls of $driver->getCore()->classifier() with $driver->getCore()->getFieldClassifier(); no backwards-compatibility shim is provided.
    • [#337] Replaced 'stdClass' entity stubs with typed 'EntityStub' from driver. @AlexSkrypnyk (#814)
      Hook scopes (BeforeNodeCreateScope, AfterNodeCreateScope, etc.) and step methods now expose EntityStubInterface instead of \stdClass, and EntityScope::getEntity() is renamed to getStub(). Migration: replace ad-hoc property reads with $stub->getValue('title') and writes with $stub->setValue(...); replace (object) [...] constructions with new EntityStub($entity_type, $bundle, $values); replace $saved->nid / $saved->tid with $stub->getId(); rename getEntity() calls to getStub().
    • [#806] Removed 'store' parameter from 'DrupalMailManager' and 'DrupalMailManagerInterface'. @AlexSkrypnyk (#812)
      getMail() and clearMail() no longer accept a $store argument because the v3 driver only exposes a single implicit collector. Migration: drop the $store argument from any direct calls and from any subclass overrides that implement DrupalMailManagerInterface; tracked counts in RawMailContext are now a scalar int rather than an array keyed by store.
    • [#752] Replaced generic exceptions with typed Mink exceptions across bundled contexts. @AlexSkrypnyk (#811)
      Roughly 30 \Exception throws across the bundled contexts are replaced with Behat\Mink\Exception\ElementNotFoundException (lookups), Behat\Mink\Exception\ExpectationException (assertion mismatches), or \RuntimeException (configuration errors). Migration: any tests or hooks that catch \Exception from these steps continue to work, but code that asserts on specific exception classes or messages must update to the typed classes; Mink exceptions append URL and page-snippet context via __toString().
    • Enforced step-definition conventions for v6 across all bundled contexts. @AlexSkrypnyk (#810)
      Roughly 50 @Then methods are renamed to <concern>Assert<action> form, around 29 step texts are updated to satisfy the new conventions (e.g. Given users:Given the following users:, Then drush output should contain XThen the drush output should contain X, Then I log outWhen I log out), and several methods are re-categorised from @Then to @When for side-effect steps. Migration: search-and-replace step text in your feature files using the table in MIGRATION.md; rename overridden method names in your subclasses.
    • Removed deprecated APIs in preparation for 6.0.0. @AlexSkrypnyk (#809)
      Subcontext auto-discovery (subcontexts.paths config, .behat.inc loading, DrupalSubContextInterface, DrupalSubContextBase), the annotation-based hook reader (Annotation\Reader), RawDrupalContext::loggedInWithRole(), and the AnnotatedDefinitionProposal shim are all removed. Migration: rewrite subcontexts as regular Behat contexts using PHP attributes; remove any subcontexts: block from behat.yml; replace loggedInWithRole() calls with the standard authenticated-user flow.
    • [#823] Rebased 'RandomContext' on bare Behat context interface. @AlexSkrypnyk (#834)
      RandomContext no longer extends RawDrupalContext; it implements Behat\Behat\Context\Context directly and instantiates a Random lazily. Migration: subclassers that relied on inherited Drupal/Mink helpers must compose those traits themselves or change their base class; documented in MIGRATION.md under "RandomContext base class".

    All changes

    • [#356] Strengthened 'author' property test to assert author is applied. @AlexSkrypnyk (#847)
      The existing scenario for the author property in Given the following :type content: was rewritten as a direct test that creates an article with author = Joe User, visits /admin/content, and asserts Joe User appears in the article's author column. Previously the scenario only verified the syntax did not error.
    • [#647] Added 'BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP' env var to skip scenario teardown. @AlexSkrypnyk (#845)
      Setting BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP=1 (or true/yes/on) skips the AfterScenario teardown of entities, users, and roles, and intentionally leaves the last logged-in session open so a failing scenario's database state and browser session can be inspected directly. Intended for ad-hoc local debugging - leave it off in CI.
    • [#735] Added test coverage and docs for options in 'I run drush :command :arguments' step. @AlexSkrypnyk (#846)
      The existing I run drush :command :arguments step already supported flags because the arguments string is appended verbatim to the shell command, but this was undocumented. The docblock now shows a combined positional-argument-plus-flag example, and a new scenario exercises config:get "system.site uuid --format=string" end to end.
    • [#469] Added typed random tokens with '[?name:type,args]' syntax and deprecated '<?name>' form. @AlexSkrypnyk (#844)
      RandomContext ships six built-in generators (string, name, machine_name, int, email, uuid) selectable via [?name:type,args], with subclasses able to register custom types by overriding a single method. Equivalent literals share a scenario-scoped cache key, so [?title], [?title:string], and [?title:string,10] all produce the same value within one scenario.
    • [#733] Added test coverage and docs for configurable login and logout URLs. @AlexSkrypnyk (#843)
      Three new PHPUnit tests pin the visit() argument so a regression that hardcoded /user back into DrupalAuthenticationManager would now fail loudly, and the logout_confirm_url entry was added to the documented text: example so all three login/logout URL keys are visible together.
    • [#415] Added test coverage for URI-only link field values. @AlexSkrypnyk (#841)
      Five new Behat scenarios exercise URI-only link field values - bare URIs, comma-separated lists, the named uri: compound column, and a mixed scenario - covering the upstream LinkHandler fix in drupal-driver that wraps a bare string as ['uri' => $value].
    • Fixed chrome port and AJAX assertion after Pygmy and Lagoon stack migration. @AlexSkrypnyk (#840)
      The Selenium VNC port mapping was changed from a fixed 7900:7900 host binding to a Docker-assigned ephemeral port to avoid conflicts, and the AJAX timeout assertion in FeatureContext no longer hardcodes http://blackbox so it works against the new in-process PHP server (http://cli:8888). CONTRIBUTING.md now documents how to read the dynamic VNC URL from ahoy info.
    • [#730] Migrated local stack to Pygmy and Lagoon images. @AlexSkrypnyk (#839)
      The Wodby + Traefik local stack is replaced with Lagoon container images fronted by Pygmy, matching the layout used by drevops/behat-steps. The blackbox nginx container is dropped in favour of an in-process PHP server started by BlackboxServerContext inside the cli container, the drupal_https profile is removed, and provisioning steps move into a single scripts/provision.sh shared by ahoy and CI.
    • [#479] Added verbose diagnostic output to AJAX timeout exception. @AlexSkrypnyk (#838)
      iWaitForAjaxToFinish() now captures the current URL, jQuery.active count, animated-element count, and each active Drupal.ajax.instances entry (selector, event, URL) at the moment of timeout and embeds them in a structured multi-line error message. Replaces the previous single-line "Unable to complete AJAX request." message that gave no clue why the browser was busy.
    • Renamed 'assert' action steps and tightened validator. @AlexSkrypnyk (#837)
      Action methods that previously used assertXxx names are renamed to action-style names (e.g. assertCroniRunCron, assertAuthenticatedByRoleiAmLoggedInAsUserWithRole, assertDrushCommandiRunDrush), and three negative-message steps move from @Given to @Then with matching method renames. The validator now hard-fails when @Given/@When step text contains should or method names contain Assert.
    • Added 'suppress_deprecations' configuration and 'BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS' environment variable. @AlexSkrypnyk (#836)
      Both the suppress_deprecations config key and the BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS env var silence the extension's [Deprecation] notices to STDERR, with the env var winning over config. This lets teams roll forward through migrations without their CI failing on deprecation noise from extension-detected legacy patterns.
    • [#824] Converted 'BatchContext' into 'BatchTrait' on 'DrupalContext'. @AlexSkrypnyk (#835)
      BatchContext is deleted; its iWaitForTheBatchJobToFinish and thereIsAnItemInTheSystemQueue steps are now provided by DrupalContext via BatchTrait. Both steps depend on \Drupal:: calls, so hosting them on the API-driver-only DrupalContext keeps them behind a bootstrapped Drupal kernel and prevents silent failures under Blackbox or Drush drivers.
    • Moved driver and mail manager classes under 'Drupal\DrupalExtension\Manager' namespace. @AlexSkrypnyk (#833)
      Drupal\DrupalDriverManagerDrupal\DrupalExtension\Manager\DriverManager (the Drupal prefix drops because driver routing is generic infrastructure), and the mail manager and its interface move alongside the user/auth managers under the same namespace. The dead psr-0 autoload entry in composer.json is removed.
    • [#823] Rebased 'RandomContext' on bare Behat context interface. @AlexSkrypnyk (#834)
      RandomContext no longer extends RawDrupalContext; it implements Behat\Behat\Context\Context directly and instantiates a Random lazily, so the context can be registered in any Behat suite regardless of whether the Drupal extension is loaded. New PHPUnit tests cover the standalone shape and the token substitution contract.
    • Moved 'ParametersAwareInterface' to root namespace alongside 'ParametersTrait'. @AlexSkrypnyk (#832)
      The interface moved from Drupal\DrupalExtension\Context\ParametersAwareInterface to Drupal\DrupalExtension\ParametersAwareInterface so it sits next to its companion ParametersTrait and RegionTrait. setParameters / getParameter signatures are unchanged - only the FQN moves.
    • [#826] Documented 'ParametersTrait' and 'RegionTrait' as Mink-only consumption points. @AlexSkrypnyk (#831)
      The two traits work on any RawMinkContext consumer without requiring a Drupal driver bootstrap; the trait docblocks and a new "Mink-only contexts" section in docs/contexts.md make the pattern explicit. The bundled MinkContext, MarkupContext, and MessageContext already follow this pattern.
    • [#825] Extracted Drupal AJAX handling into 'DrupalAjaxTrait'. @AlexSkrypnyk (#830)
      The three Drupal-specific AJAX methods (iWaitForAjaxToFinish, beforeJavascriptStep, afterJavascriptStep) move from MinkContext into DrupalAjaxTrait; MinkContext composes the trait so existing consumers see no behavior change. The trait can now be reused in custom Mink-based contexts without inheriting from MinkContext.
    • Moved 'ajax_timeout' to 'Drupal\DrupalExtension' and renamed parameters interface. @AlexSkrypnyk (#829)
      ajax_timeout configuration moves from Drupal\MinkExtension to Drupal\DrupalExtension so all custom config lives under one extension, and the parameters API drops its Drupal prefix throughout: interface, trait, methods, and property name. The Drupal\MinkExtension extension now only registers the BrowserKit driver factory.
    • Moved 'ClassGenerator' out of 'Context/ContextClass/' into a top-level 'Generator/' namespace. @AlexSkrypnyk (#828)
      ClassGenerator (Behat's behat --init scaffolder for Drupal context classes) moves from Drupal\DrupalExtension\Context\ContextClass to Drupal\DrupalExtension\Generator, away from the actual step-defining contexts. The class is only instantiated by Behat's DI from inside the extension, so no downstream user code is affected. New PHPUnit tests cover both namespaced and rootless context-class generation.
    • [#822] Rebased MessageContext on RawMinkContext and moved message selectors to Drupal\MinkExtension. @AlexSkrypnyk (#827)
      MessageContext now extends RawMinkContext instead of RawDrupalContext, so blackbox-only suites no longer pay the cost of booting the Drupal driver stack. The four message selectors move from Drupal\DrupalExtension.selectors: to a new Drupal\MinkExtension.selectors: map; the legacy location keeps working in 6.0 with a one-shot deprecation notice.
    • [#258] Added BigPipe NOJS cookie bypass to 'DrupalContext'. @AlexSkrypnyk (#821)
      Tagging a scenario with @bigpipe sets the big_pipe_nojs cookie on non-JS Mink drivers so Drupal renders pages fully server-side instead of leaving placeholders that only the BigPipe JS would replace. The cookie is re-applied on every step because login redirects drop session cookies, and the trait is a no-op when the active driver supports JavaScript.
    • [#732] Added 'login_field' configuration to submit a custom user property as the login value. @AlexSkrypnyk (#820)
      Sites that authenticate by email rather than username (via mail_login, email_registration, or similar contrib) can now set login_field: mail (or any other user property) under Drupal\DrupalExtension, and the auth manager submits that property value to the username field instead of the hardcoded name. The default remains name, so existing setups are unaffected.
    • Replaced Sphinx documentation with Markdown-based docs in 'docs/'. @AlexSkrypnyk (#819)
      The Read the Docs / Sphinx tree under doc/ is removed and replaced with plain Markdown under docs/ covering installation, configuration, drivers, contexts, hooks, and writing tests. The Read the Docs badge and links in README.md are also dropped.
    • [#766] Added modern entity-field parser with 'field_parser' configuration flag. @AlexSkrypnyk (#818)
      The new EntityFieldParser introduces double-quote escaping, named-column compound syntax (country:"BE", locality:"Brussel"), structured ParseException errors with file/line context, and aggregated multi-error reporting. Bare - is now treated as literal text in scalar mode, so entity reference titles like "My article - Part 2" no longer require escaping.
    • [#766] Extracted field parsing into 'ParserInterface' and 'LegacyEntityFieldsParser'. @AlexSkrypnyk (#816)
      This is a pure refactor that lifts the cell-level field-value parsing out of RawDrupalContext::parseEntityFields() into a new LegacyEntityFieldsParser implementing a new ParserInterface. Behavior is unchanged in this PR; the contract is introduced first so the new modern parser (#818) can land against a stable interface.
    • Renamed 'classifier()' calls to 'getFieldClassifier()' to match drupal-driver API. @AlexSkrypnyk (#817)
      The drupal-driver CoreInterface::classifier() accessor was renamed to getFieldClassifier() upstream, and this PR updates the single call site in parseEntityFields() and the four mock setups in RawDrupalContextTest. No backwards-compatibility shim is provided.
    • Removed PHPSpec-based unit testing from the project. @AlexSkrypnyk (#815)
      The 22 PHPSpec spec files, the test-phpspec ahoy command, and the phpspec/phpspec Composer dev dependency are all removed; PHPUnit and Behat already cover the same ground. CI now runs one fewer parallel step.
    • [#337] Replaced 'stdClass' entity stubs with typed 'EntityStub' from driver. @AlexSkrypnyk (#814)
      Hook scopes and step methods now expose EntityStubInterface instead of \stdClass, four parallel creation paths collapse into a single entityCreate() entry point, and the four cleanNodes()/cleanTerms()/cleanUsers()/cleanLanguages() AfterScenario hooks become a single cleanEntities() reverse-walk. (object) [...] constructions become new EntityStub($type, $bundle, $values) and ad-hoc property access becomes getValue()/setValue().
    • [#806] Removed 'store' parameter from 'DrupalMailManager' and 'DrupalMailManagerInterface'. @AlexSkrypnyk (

    Note truncated.

    Open source →
    Release notes

    Version 6.0 enforces a consistent set of step-definition conventions across all bundled contexts. The conventions are documented in CONTRIBUTING.md and validated by scripts/docs.php ; CI fails on any violation.

    See UPGRADING.md for detailed migration instructions covering all breaking changes, and the table below for a summary of highlights and breaking changes.

    Highlights

    • Updated 'drupal/drupal-driver' to 3.x and migrated to capability-based API. @AlexSkrypnyk ( #803 ) The monolithic DriverInterface is replaced with capability interfaces ( AuthenticationCapabilityInterface , MailCapabilityInterface , ConfigCapabilityInterface , ContentCapabilityInterface , CacheCapabilityInterface , CronCapabilityInterface , LanguageCapabilityInterface , RoleCapabilityInterface , UserCapabilityInterface ) and every CRUD method is renamed to a verb-noun form. Migration: bump drupal/drupal-driver to ^3.0 , rename driver calls ( createNode → nodeCreate , runCron → cronRun , clearCache → cacheClear , startCollectingMail → mailStartCollecting , getMail → mailGet , sendMail → mailSend , etc.), and add capability-interface guards before invoking driver methods in subclasses.

    • [ #469 ] Added typed random tokens with '[?name:type,args]' syntax and deprecated '<?name>' form. @AlexSkrypnyk ( #844 ) RandomContext ships six built-in generators ( string , name , machine_name , int , email , uuid ) selectable via [?name:type,args] , with subclasses able to register custom types by overriding a single method. Equivalent literals share a scenario-scoped cache key, so [?title] , [?title:string] , and [?title:string,10] all produce the same value within one scenario.

    • [ #258 ] Added BigPipe NOJS cookie bypass to 'DrupalContext'. @AlexSkrypnyk ( #821 ) Tagging a scenario with @bigpipe sets the big_pipe_nojs cookie on non-JS Mink drivers (BrowserKit, Goutte) so Drupal renders pages fully server-side instead of leaving placeholders that only the BigPipe JS would replace. This makes authenticated-user assertions like "I should see Log out" reliable on BigPipe-enabled sites without switching to a real browser.

    • [ #732 ] Added 'login_field' configuration to submit a custom user property as the login value. @AlexSkrypnyk ( #820 ) Sites that authenticate by email rather than username (via mail_login , email_registration , or similar contrib) can now set login_field: mail (or any other user property) under Drupal\DrupalExtension , and the auth manager submits that property value to the username field instead of the hardcoded name . The default remains name , so existing setups are unaffected.

    • [ #766 ] Added modern entity-field parser with 'field_parser' configuration flag. @AlexSkrypnyk ( #818 ) The new EntityFieldParser introduces double-quote escaping, named-column compound syntax ( country:"BE", locality:"Brussel" ), structured ParseException errors with file/line context, and aggregated multi-error reporting. Bare - is now treated as literal text in scalar mode, so entity reference titles like "My article - Part 2" no longer require escaping.

    • Added 'suppress_deprecations' configuration and 'BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS' environment variable. @AlexSkrypnyk ( #836 ) Both the suppress_deprecations config key and the BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS env var silence the extension's [Deprecation] notices to STDERR, with the env var winning over config. This lets teams roll forward through migrations without their CI failing on deprecation noise from extension-detected legacy patterns.

    • [ #647 ] Added 'BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP' env var to skip scenario teardown. @AlexSkrypnyk ( #845 ) Setting BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP=1 (or true / yes / on ) skips the AfterScenario teardown of entities, users, and roles, and intentionally leaves the last logged-in session open so a failing scenario's database state and browser session can be inspected directly. Intended for ad-hoc local debugging - leave it off in CI.

    • [ #479 ] Added verbose diagnostic output to AJAX timeout exception. @AlexSkrypnyk ( #838 ) iWaitForAjaxToFinish() now captures the current URL, jQuery.active count, animated-element count, and each active Drupal.ajax.instances entry (selector, event, URL) at the moment of timeout and embeds them in a structured multi-line error message. Replaces the previous single-line "Unable to complete AJAX request." message that gave no clue why the browser was busy.

    Breaking changes

    • Updated 'drupal/drupal-driver' to 3.x and migrated to capability-based API. @AlexSkrypnyk ( #803 ) The monolithic DriverInterface is replaced with capability interfaces ( AuthenticationCapabilityInterface , MailCapabilityInterface , ConfigCapabilityInterface , ContentCapabilityInterface , CacheCapabilityInterface , CronCapabilityInterface , LanguageCapabilityInterface , RoleCapabilityInterface , UserCapabilityInterface ) and every CRUD method is renamed to a verb-noun form. Migration: bump drupal/drupal-driver to ^3.0 , rename driver calls ( createNode → nodeCreate , runCron → cronRun , clearCache → cacheClear , startCollectingMail → mailStartCollecting , getMail → mailGet , sendMail → mailSend , etc.), and add capability-interface guards before invoking driver methods in subclasses.

    • [ #469 ] Added typed random tokens with '[?name:type,args]' syntax and deprecated '<?name>' form. @AlexSkrypnyk ( #844 ) The legacy <?name> random-token form still works in 6.0 but emits a [Deprecation] notice once per literal. Migration: replace <?name> with [?name] (equivalent default) or one of the typed forms ( [?slug:machine_name] , [?age:int,18,99] , [?email:email] , [?id:uuid] ); the legacy form is scheduled for removal in 6.1.

    • Renamed 'assert' action steps and tightened validator. @AlexSkrypnyk ( #837 ) Action methods that previously used assertXxx names are renamed to action-style names (e.g. assertCron → iRunCron , assertAuthenticatedByRole → iAmLoggedInAsUserWithRole , assertDrushCommand → iRunDrush ), and three negative-message steps move from @Given to @Then with matching method renames. Migration: see the rename table in MIGRATION.md and search-and-replace overridden method names in your subclasses; step text is unchanged for most steps but the three re-classified steps now require @Then semantics.

    • [ #824 ] Converted 'BatchContext' into 'BatchTrait' on 'DrupalContext'. @AlexSkrypnyk ( #835 ) BatchContext is deleted; its iWaitForTheBatchJobToFinish and thereIsAnItemInTheSystemQueue steps are now provided by DrupalContext via BatchTrait . Migration: remove Drupal\DrupalExtension\Context\BatchContext from the contexts: list in your behat.yml - the steps are loaded automatically with DrupalContext .

    • Moved driver and mail manager classes under 'Drupal\DrupalExtension\Manager' namespace. @AlexSkrypnyk ( #833 ) Drupal\DrupalDriverManager → Drupal\DrupalExtension\Manager\DriverManager (the Drupal prefix drops), Drupal\DrupalDriverManagerInterface → Drupal\DrupalExtension\Manager\DriverManagerInterface , Drupal\DrupalMailManager → Drupal\DrupalExtension\Manager\DrupalMailManager , Drupal\DrupalMailManagerInterface → Drupal\DrupalExtension\Manager\DrupalMailManagerInterface . Migration: update use statements and any FQCN references; the user and authentication managers retain their existing namespaces.

    • Moved 'ParametersAwareInterface' to root namespace alongside 'ParametersTrait'. @AlexSkrypnyk ( #832 ) The interface moved from Drupal\DrupalExtension\Context\ParametersAwareInterface to Drupal\DrupalExtension\ParametersAwareInterface . Migration: update use statements to import from the root namespace; signatures ( setParameters , getParameter ) are unchanged.

    • [ #825 ] Extracted Drupal AJAX handling into 'DrupalAjaxTrait'. @AlexSkrypnyk ( #830 ) The three Drupal-specific AJAX methods ( iWaitForAjaxToFinish , beforeJavascriptStep , afterJavascriptStep ) move from MinkContext into DrupalAjaxTrait . MinkContext composes the trait so existing consumers see no behavior change, but downstream subclasses that overrode these methods inline must now override the trait methods or compose DrupalAjaxTrait directly.

    • Moved 'ajax_timeout' to 'Drupal\DrupalExtension' and renamed parameters interface. @AlexSkrypnyk ( #829 ) ajax_timeout configuration moves from Drupal\MinkExtension to Drupal\DrupalExtension , and the parameters API drops its Drupal prefix: DrupalParametersAwareInterface → ParametersAwareInterface , DrupalParametersTrait → ParametersTrait , setDrupalParameters → setParameters , getDrupalParameter → getParameter , $drupalParameters → $parameters . Migration: relocate ajax_timeout in behat.yml and rename interface/trait/method/property references in subclasses.

    • [ #822 ] Rebased MessageContext on RawMinkContext and moved message selectors to Drupal\MinkExtension. @AlexSkrypnyk ( #827 ) MessageContext now extends RawMinkContext instead of RawDrupalContext , so it can be registered in any Mink s...

    Read more

    Contributors

    AlexSkrypnyk

    Assets 2 Loading

    Uh oh!

    There was an error while loading. Please reload this page .

    All reactions

    Open source →
  6. v5.4.0 16 Apr 2026
    Release notes

    What's new since v5.3.3

    Important

    This is the last 5.x release with DrupalDriver 2.x support. Only critical bug fixes will be worked on as patches for 2.4, if required.
    We are working on 6.x, which will use the updated DrupalDriver API.

    • [#662] Added drag-and-drop step definition for MinkContext. @AlexSkrypnyk (#800)
    • Changed default Drush binary to 'vendor/bin/drush' with automatic path resolution. @AlexSkrypnyk (#799)
    • Added configurable 'login_wait' to fix post-login race condition on JS-heavy sites. @AlexSkrypnyk (#798)

    Full Changelog: v5.3.3...v5.4.0

    @AlexSkrypnyk

    Open source →
    Release notes

    Version 6.0 enforces a consistent set of step-definition conventions across all bundled contexts. The conventions are documented in CONTRIBUTING.md and validated by scripts/docs.php ; CI fails on any violation.

    See UPGRADING.md for detailed migration instructions covering all breaking changes, and the table below for a summary of highlights and breaking changes.

    Highlights

    • Updated 'drupal/drupal-driver' to 3.x and migrated to capability-based API. @AlexSkrypnyk ( #803 ) The monolithic DriverInterface is replaced with capability interfaces ( AuthenticationCapabilityInterface , MailCapabilityInterface , ConfigCapabilityInterface , ContentCapabilityInterface , CacheCapabilityInterface , CronCapabilityInterface , LanguageCapabilityInterface , RoleCapabilityInterface , UserCapabilityInterface ) and every CRUD method is renamed to a verb-noun form. Migration: bump drupal/drupal-driver to ^3.0 , rename driver calls ( createNode → nodeCreate , runCron → cronRun , clearCache → cacheClear , startCollectingMail → mailStartCollecting , getMail → mailGet , sendMail → mailSend , etc.), and add capability-interface guards before invoking driver methods in subclasses.

    • [ #469 ] Added typed random tokens with '[?name:type,args]' syntax and deprecated '<?name>' form. @AlexSkrypnyk ( #844 ) RandomContext ships six built-in generators ( string , name , machine_name , int , email , uuid ) selectable via [?name:type,args] , with subclasses able to register custom types by overriding a single method. Equivalent literals share a scenario-scoped cache key, so [?title] , [?title:string] , and [?title:string,10] all produce the same value within one scenario.

    • [ #258 ] Added BigPipe NOJS cookie bypass to 'DrupalContext'. @AlexSkrypnyk ( #821 ) Tagging a scenario with @bigpipe sets the big_pipe_nojs cookie on non-JS Mink drivers (BrowserKit, Goutte) so Drupal renders pages fully server-side instead of leaving placeholders that only the BigPipe JS would replace. This makes authenticated-user assertions like "I should see Log out" reliable on BigPipe-enabled sites without switching to a real browser.

    • [ #732 ] Added 'login_field' configuration to submit a custom user property as the login value. @AlexSkrypnyk ( #820 ) Sites that authenticate by email rather than username (via mail_login , email_registration , or similar contrib) can now set login_field: mail (or any other user property) under Drupal\DrupalExtension , and the auth manager submits that property value to the username field instead of the hardcoded name . The default remains name , so existing setups are unaffected.

    • [ #766 ] Added modern entity-field parser with 'field_parser' configuration flag. @AlexSkrypnyk ( #818 ) The new EntityFieldParser introduces double-quote escaping, named-column compound syntax ( country:"BE", locality:"Brussel" ), structured ParseException errors with file/line context, and aggregated multi-error reporting. Bare - is now treated as literal text in scalar mode, so entity reference titles like "My article - Part 2" no longer require escaping.

    • Added 'suppress_deprecations' configuration and 'BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS' environment variable. @AlexSkrypnyk ( #836 ) Both the suppress_deprecations config key and the BEHAT_DRUPALEXTENSION_SUPPRESS_DEPRECATIONS env var silence the extension's [Deprecation] notices to STDERR, with the env var winning over config. This lets teams roll forward through migrations without their CI failing on deprecation noise from extension-detected legacy patterns.

    • [ #647 ] Added 'BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP' env var to skip scenario teardown. @AlexSkrypnyk ( #845 ) Setting BEHAT_DRUPALEXTENSION_DISABLE_CLEANUP=1 (or true / yes / on ) skips the AfterScenario teardown of entities, users, and roles, and intentionally leaves the last logged-in session open so a failing scenario's database state and browser session can be inspected directly. Intended for ad-hoc local debugging - leave it off in CI.

    • [ #479 ] Added verbose diagnostic output to AJAX timeout exception. @AlexSkrypnyk ( #838 ) iWaitForAjaxToFinish() now captures the current URL, jQuery.active count, animated-element count, and each active Drupal.ajax.instances entry (selector, event, URL) at the moment of timeout and embeds them in a structured multi-line error message. Replaces the previous single-line "Unable to complete AJAX request." message that gave no clue why the browser was busy.

    Breaking changes

    • Updated 'drupal/drupal-driver' to 3.x and migrated to capability-based API. @AlexSkrypnyk ( #803 ) The monolithic DriverInterface is replaced with capability interfaces ( AuthenticationCapabilityInterface , MailCapabilityInterface , ConfigCapabilityInterface , ContentCapabilityInterface , CacheCapabilityInterface , CronCapabilityInterface , LanguageCapabilityInterface , RoleCapabilityInterface , UserCapabilityInterface ) and every CRUD method is renamed to a verb-noun form. Migration: bump drupal/drupal-driver to ^3.0 , rename driver calls ( createNode → nodeCreate , runCron → cronRun , clearCache → cacheClear , startCollectingMail → mailStartCollecting , getMail → mailGet , sendMail → mailSend , etc.), and add capability-interface guards before invoking driver methods in subclasses.

    • [ #469 ] Added typed random tokens with '[?name:type,args]' syntax and deprecated '<?name>' form. @AlexSkrypnyk ( #844 ) The legacy <?name> random-token form still works in 6.0 but emits a [Deprecation] notice once per literal. Migration: replace <?name> with [?name] (equivalent default) or one of the typed forms ( [?slug:machine_name] , [?age:int,18,99] , [?email:email] , [?id:uuid] ); the legacy form is scheduled for removal in 6.1.

    • Renamed 'assert' action steps and tightened validator. @AlexSkrypnyk ( #837 ) Action methods that previously used assertXxx names are renamed to action-style names (e.g. assertCron → iRunCron , assertAuthenticatedByRole → iAmLoggedInAsUserWithRole , assertDrushCommand → iRunDrush ), and three negative-message steps move from @Given to @Then with matching method renames. Migration: see the rename table in MIGRATION.md and search-and-replace overridden method names in your subclasses; step text is unchanged for most steps but the three re-classified steps now require @Then semantics.

    • [ #824 ] Converted 'BatchContext' into 'BatchTrait' on 'DrupalContext'. @AlexSkrypnyk ( #835 ) BatchContext is deleted; its iWaitForTheBatchJobToFinish and thereIsAnItemInTheSystemQueue steps are now provided by DrupalContext via BatchTrait . Migration: remove Drupal\DrupalExtension\Context\BatchContext from the contexts: list in your behat.yml - the steps are loaded automatically with DrupalContext .

    • Moved driver and mail manager classes under 'Drupal\DrupalExtension\Manager' namespace. @AlexSkrypnyk ( #833 ) Drupal\DrupalDriverManager → Drupal\DrupalExtension\Manager\DriverManager (the Drupal prefix drops), Drupal\DrupalDriverManagerInterface → Drupal\DrupalExtension\Manager\DriverManagerInterface , Drupal\DrupalMailManager → Drupal\DrupalExtension\Manager\DrupalMailManager , Drupal\DrupalMailManagerInterface → Drupal\DrupalExtension\Manager\DrupalMailManagerInterface . Migration: update use statements and any FQCN references; the user and authentication managers retain their existing namespaces.

    • Moved 'ParametersAwareInterface' to root namespace alongside 'ParametersTrait'. @AlexSkrypnyk ( #832 ) The interface moved from Drupal\DrupalExtension\Context\ParametersAwareInterface to Drupal\DrupalExtension\ParametersAwareInterface . Migration: update use statements to import from the root namespace; signatures ( setParameters , getParameter ) are unchanged.

    • [ #825 ] Extracted Drupal AJAX handling into 'DrupalAjaxTrait'. @AlexSkrypnyk ( #830 ) The three Drupal-specific AJAX methods ( iWaitForAjaxToFinish , beforeJavascriptStep , afterJavascriptStep ) move from MinkContext into DrupalAjaxTrait . MinkContext composes the trait so existing consumers see no behavior change, but downstream subclasses that overrode these methods inline must now override the trait methods or compose DrupalAjaxTrait directly.

    • Moved 'ajax_timeout' to 'Drupal\DrupalExtension' and renamed parameters interface. @AlexSkrypnyk ( #829 ) ajax_timeout configuration moves from Drupal\MinkExtension to Drupal\DrupalExtension , and the parameters API drops its Drupal prefix: DrupalParametersAwareInterface → ParametersAwareInterface , DrupalParametersTrait → ParametersTrait , setDrupalParameters → setParameters , getDrupalParameter → getParameter , $drupalParameters → $parameters . Migration: relocate ajax_timeout in behat.yml and rename interface/trait/method/property references in subclasses.

    • [ #822 ] Rebased MessageContext on RawMinkContext and moved message selectors to Drupal\MinkExtension. @AlexSkrypnyk ( #827 ) MessageContext now extends RawMinkContext instead of RawDrupalContext , so it can be registered in any Mink suite without booting the Drupal driver; subclasses that depended on RawDrupalContext helpers must compose ParametersTrait themselves or change their base. The four message selectors ( message_selector , error_message_selector , success_message_selector , warning_message_selector ) move from Drupal\DrupalExtension.selectors: to Drupal\MinkExtension.selectors: ; the legacy location still works in 6.0 with a one-shot deprecation notice and is removed in 6.1.

    • [ #258 ] Added BigPipe NOJS cookie bypass to 'DrupalContext'. @AlexSkrypnyk ( #821 ) This is additive (opt-in via @bigpipe tag) but ships as part of ...

    Read more

    Contributors

    AlexSkrypnyk

    Assets 2 Loading

    Uh oh!

    There was an error while loading. Please reload this page .

    All reactions

    Open source →
  7. v5.3.3 15 Apr 2026
    Release notes

    What's new since v5.3.2

    Full Changelog: v5.3.2...v5.3.3

    @AlexSkrypnyk @idimopoulos

    Open source →
    Release notes

    Important

    This is the last 5.x release with DrupalDriver 2.x support. Only critical bug fixes will be worked on as patches for 2.4 , if required. We are working on 6.x , which will use the updated DrupalDriver API.

    • [ #662 ] Added drag-and-drop step definition for MinkContext. @AlexSkrypnyk ( #800 )

    • Changed default Drush binary to 'vendor/bin/drush' with automatic path resolution. @AlexSkrypnyk ( #799 )

    • Added configurable 'login_wait' to fix post-login race condition on JS-heavy sites. @AlexSkrypnyk ( #798 )

    Full Changelog : v5.3.3...v5.4.0

    @AlexSkrypnyk

    Contributors

    AlexSkrypnyk

    Assets 2 Loading

    Uh oh!

    There was an error while loading. Please reload this page .

    All reactions

    Open source →
  8. v5.3.2 18 Mar 2026
    Release notes

    What's new since v5.3.1

    • [#791] Fixed 'author' property triggering validation error in node creation. @AlexSkrypnyk (#792)
    • Added tests for attribute/annotation inheritance and changelog warning. @AlexSkrypnyk (#790)

    Full Changelog: v5.3.1...v5.3.2

    @AlexSkrypnyk

    Open source →
    Release notes
    • Fixed 'setBasicConfig()' storing all values as strings instead of native PHP types. @idimopoulos @AlexSkrypnyk ( #796 )

    • Updated Behat Screenshot config to remove deprecated option. @AlexSkrypnyk ( #797 )

    • Add Slack community badge to README @AlexSkrypnyk ( #793 )

    Full Changelog : v5.3.2...v5.3.3

    @AlexSkrypnyk @idimopoulos

    Contributors

    AlexSkrypnyk and idimopoulos

    Assets 2 Loading

    Uh oh!

    There was an error while loading. Please reload this page .

    All reactions

    Open source →
  9. v5.3.1 17 Mar 2026
    Release notes

    What's new since v5.3.0

    Full Changelog: v5.3.0...v5.3.1

    @AlexSkrypnyk

    Open source →
    Release notes
    • [ #791 ] Fixed 'author' property triggering validation error in node creation. @AlexSkrypnyk ( #792 )

    • Added tests for attribute/annotation inheritance and changelog warning. @AlexSkrypnyk ( #790 )

    Full Changelog : v5.3.1...v5.3.2

    @AlexSkrypnyk

    Contributors

    AlexSkrypnyk

    Assets 2 Loading

    Uh oh!

    There was an error while loading. Please reload this page .

    All reactions

    Open source →
  10. v5.3.0 17 Mar 2026
    Release notes

    Highlights

    • Converted standard Behat annotations to PHP 8 attributes.
    • Added comprehensive test coverage for all step definitions using positive and negative tests.
    • Added a documentation generator for step definitions to allow humans and AI agents to easily discover available steps and their usage.
    • Removed Drupal 6 and 7 driver support, including all related code and fixtures.

    Behavioural changes

    Behat annotations converted to PHP 8 attributes

    All standard Behat annotations (@Given, @When, @Then, @BeforeScenario,
    @AfterScenario, etc.) in src/ have been converted to PHP 8 attributes. The
    old annotation syntax is still supported by Behat, so this is not a breaking
    change for consumers
    .

    Warning

    If you extend any of the bundled context classes and override step or hook
    methods, you must switch your overrides from docblock annotations (@Given,
    @When, @Then, @BeforeScenario, etc.) to PHP 8 attributes (#[Given],
    #[When], #[Then], #[BeforeScenario], etc.). Behat resolves both the
    parent attribute and the child annotation independently, which causes a
    RedundantStepException for step definitions and duplicate execution for
    hooks. To safely override a method, either re-declare the step/hook using
    only the PHP 8 attribute on the child (and remove it from the parent by not
    registering the parent context), or override the method without any
    annotation or attribute to inherit the parent's definition.

    ConfigContext::setConfig() is now protected

    The setConfig() method visibility was changed from public to protected.
    If your project calls ConfigContext::setConfig() from outside the class, you
    will need to adjust your code.

    Role-based login always creates a fresh user

    The loggedInWithRole() method now always creates a new user instead of reusing
    a previously created user with the same role. This prevents stale login state
    from leaking between scenarios.

    Link assertion separated from click action

    The link existence assertion has been separated from the click action. Previously,
    clicking a non-existent link would throw a generic element-not-found exception.
    Now the assertion and click are distinct operations with clearer error messages.

    Parent term resolution in termCreate()

    termCreate() now resolves parent terms by name. When creating a taxonomy term
    with a parent field value, the extension will look up the parent term by name
    and use its term ID. Validation ensures the parent term exists before creation.

    Entity field validation in parseEntityFields()

    parseEntityFields() now validates that all fields specified in a Behat table
    row actually exist on the entity type. Previously, non-existent fields were
    silently ignored. Now a \RuntimeException is thrown listing the invalid fields.

    Table header validation in assertValidMessageTable()

    The error message when a message table has invalid headers has been improved to
    show the expected headers and what was actually provided.

    Double-quote escaping in entity reference values

    Entity reference values containing commas can now be wrapped in double quotes to
    prevent the compound separator from splitting them. For example:
    "Term with, comma" will be treated as a single value.


    Configuration changes

    behat.dist.yml provided

    A new behat.dist.yml file is included with all configuration values
    pre-filled, serving as a reference for available options and their defaults.


    New features

    Custom DocumentElement

    A custom DocumentElement class has been added to remove the DrupalFinder
    dependency from extension boot. This simplifies the extension initialisation
    and reduces external dependencies.

    Steps documentation generator

    A new documentation generator (scripts/docs.php) produces a summary of all
    available step definitions. Output can be posted to CI as a summary.


    Removed

    Drupal 6 and 7 driver support dropped

    All Drupal 6 and 7 driver support has been removed, including:

    • D6/D7-specific driver code and conditionals (#768)
    • Remaining D6/D7 support remnants, fixtures, and references (#760)

    Deprecated APIs removed

    • ScenarioTagTrait — removed entirely, use TagTrait instead.
    • RawDrupalContext magic property accessors — removed. Use the explicit
      getter/setter methods (getUserManager(), getAuthenticationManager(), etc.).

    Bug fixes

    AJAX wait no longer crashes on unstarted session

    iWaitForAjaxToFinish() now checks $this->getSession()->isStarted() before
    attempting to evaluate JavaScript. Previously, calling this step before a session
    was started (e.g. in API-only scenarios) would throw an uncaught driver
    exception.

    Stale config cache in cleanConfig()

    cleanConfig() was comparing the current configuration against a stale cached
    value instead of the original backup, causing it to miss changes made during
    a scenario. The cache is now properly invalidated before comparison.

    Config backup using original value

    ConfigContext was backing up the overridden value instead of the original when
    a config key was set multiple times in a scenario. It now correctly stores only
    the first (original) value.

    Stale login state between scenarios

    Login state could leak between scenarios when a user created in one scenario was
    reused in the next. Session cleanup now ensures a clean authentication state at
    the start of each scenario.


    Infrastructure and testing

    • Switched coding standards to Drupal (#757).
    • Added comprehensive test coverage for all Context classes (#740).
    • Added tests for Managers (#753).
    • Added more negative test coverage (#756).
    • Updated testing harness to support negative coverage (#755).
    • Increased coverage for Mink extension service container (#751).
    • Increased coverage for DrupalDriverManager (#748).
    • Fixed coverage merge (#750).
    • Added posting of the coverage as comments to the PR (#741).
    • Updated stack to support Ahoy command wrapper and added coverage support (#739).
    • Added examples to tests and updated docs generator to post summary to CI (#744).
    • Added instructions for AI agents (#743).
    • Renamed blackbox fixtures to generic names and updated region mappings (#747).
    • Merged FeatureContextTrait into FeatureContext (#746).
    • Replaced regex annotation with turnip in BatchContext::iWaitForTheBatchJobToFinish() (#745).
    • Simplified code (#781).
    • Reformatted configuration trees to use hierarchical indentation and added formatter fences (#771).
    • Added test for fresh REQUEST_TIME during cron and bumped drupal-driver to ^2.4.2 (#762).

    What's new since v5.2.1

    Full Changelog: v5.2.1...v5.3.0

    @AlexSkrypnyk

    Open source →
    Release notes
    • Moved Drupal configuration from provisioning scripts to deploy hooks. @AlexSkrypnyk ( #789 )

    • [ #787 ] Fixed computed base fields failing in parseEntityFields() @AlexSkrypnyk ( #788 )

    Full Changelog : v5.3.0...v5.3.1

    @AlexSkrypnyk

    Contributors

    AlexSkrypnyk

    Assets 2 Loading

    Uh oh!

    There was an error while loading. Please reload this page .

    All reactions

    Open source →
  11. v5.2.1 08 Mar 2026
    Release notes
    • Simplified code. @AlexSkrypnyk ( #781 )

    • [ #693 ] Converted standard Behat annotations to PHP 8 attributes. @AlexSkrypnyk ( #780 )

    • [ #500 ] Made ConfigContext::setConfig() protected @AlexSkrypnyk ( #779 )

    • [ #599 ] Fixed 'iWaitForAjaxToFinish()' crashing on unstarted session. @AlexSkrypnyk ( #778 )

    • [ #534 ] Fixed stale config cache in cleanConfig() breaking change detection @AlexSkrypnyk ( #777 )

    • [ #238 ] Added table header validation tests and improved error message in 'assertValidMessageTable()'. @AlexSkrypnyk ( #776 )

    • [ #501 ] Fixed config backup using overridden value instead of original @AlexSkrypnyk ( #775 )

    • Fix stale login state leaking between scenarios @AlexSkrypnyk ( #774 )

    • [ #770 ] Added behat.dist.yml with all configuration values pre-filled. @AlexSkrypnyk ( #773 )

    • [ #314 ] Added parent term resolution in termCreate() with validation and tests. @AlexSkrypnyk ( #772 )

    • Reformatted configuration trees to use hierarchical indentation and added formatter fences. @AlexSkrypnyk ( #771 )

    • [ #607 ] Removed Drupal 6 and 7 driver support. @AlexSkrypnyk ( #768 )

    • [ #642 ] Added double-quote escaping to prevent compound separator splitting entity reference values. @AlexSkrypnyk ( #767 )

    • [ #360 ] Added validation for non-existent entity fields in parseEntityFields(). @AlexSkrypnyk ( #765 )

    • [ #658 ] Added custom DocumentElement to remove DrupalFinder dependency from extension boot. @AlexSkrypnyk ( #764 )

    • [ #670 ] Always create fresh user in role-based login steps @AlexSkrypnyk ( #763 )

    • [ #179 ] Added test for fresh REQUEST_TIME during cron and bumped drupal-driver to ^2.4.2. @AlexSkrypnyk ( #762 )

    • [ #676 ] Separated link assertion from click action in . @AlexSkrypnyk ( #761 )

    • [ #616 ] Removed Drupal 6 and 7 support remnants. @AlexSkrypnyk ( #760 )

    • Removed deprecated ScenarioTagTrait and RawDrupalContext magic property accessors. @AlexSkrypnyk ( #758 )

    • [ #729 ] Switched coding standards to Drupal. @AlexSkrypnyk ( #757 )

    • [ #738 ] Added more negative test coverage. @AlexSkrypnyk ( #756 )

    • Updated testing harness to support negative coverage. @AlexSkrypnyk ( #755 )

    • Added tests for Managers. @AlexSkrypnyk ( #753 )

    • Increased coverage for Mink extension service container. @AlexSkrypnyk ( #751 )

    • Fixed coverage merge. @AlexSkrypnyk ( #750 )

    • Increased coverage for DrupalDriverManager. @AlexSkrypnyk ( #748 )

    • Renamed blackbox fixtures to generic names and updated region mappings. @AlexSkrypnyk ( #747 )

    • Merged FeatureContextTrait into FeatureContext @AlexSkrypnyk ( #746 )

    • Replaced regex annotation with turnip in BatchContext::iWaitForTheBatchJobToFinish() . @AlexSkrypnyk ( #745 )

    • Added examples to tests and updated docs generator to post summary to CI. @AlexSkrypnyk ( #744 )

    • Added instructions for AI agents. @AlexSkrypnyk ( #743 )

    • Added steps documentation generator. @AlexSkrypnyk ( #742 )

    • [ #738 ] Added posting of the coverage as comments to the PR. @AlexSkrypnyk ( #741 )

    • Added comprehensive test coverage for all Context classes @AlexSkrypnyk ( #740 )

    • [ #738 ] Updated stack to support Ahoy command wrapper and added coverage support. @AlexSkrypnyk ( #7 ...

    Read more

    Contributors

    AlexSkrypnyk

    Assets 2 Loading

    Uh oh!

    There was an error while loading. Please reload this page .

    All reactions

    Previous 1 2 3 4 5 6 Next

    Previous Next

    You can’t perform that action at this time.

    Open source →
  12. v5.2.0 03 Mar 2026

    Nothing published for this version

  13. v5.1.0 21 Oct 2024

    Nothing published for this version

  14. v5.0.0 13 Dec 2023

    Nothing published for this version

  15. v4.2.1 26 Apr 2022

    Nothing published for this version

  16. v4.1.0 01 Jun 2020

    Nothing published for this version

  17. v4.0.1 08 Oct 2019

    Nothing published for this version

  18. v4.0.0 27 Sep 2019

    Nothing published for this version

  19. v3.4.1 06 Dec 2017

    Nothing published for this version

  20. v3.4.0 17 Nov 2017

    Nothing published for this version

  21. v3.3.1 13 Sep 2017

    Nothing published for this version

  22. v3.3.0 15 Jun 2017

    Nothing published for this version

  23. v3.2.3 08 Jun 2017

    Nothing published for this version

  24. v3.2.2 30 Jun 2016

    Nothing published for this version

  25. v3.2.1 16 Jun 2016

    Nothing published for this version

  26. v3.2.0 09 Jun 2016

    Nothing published for this version

  27. v3.1.5 22 Dec 2015

    Nothing published for this version

  28. v3.1.4 21 Dec 2015

    Nothing published for this version

  29. v3.1.3 30 Nov 2015

    Nothing published for this version

  30. v3.1.2 16 Sep 2015

    Nothing published for this version

  31. v3.1.1 02 Sep 2015

    Nothing published for this version

  32. 3.1.0 26 Aug 2015

    Nothing published for this version

  33. v3.0.13 16 Sep 2015

    Nothing published for this version

  34. v3.0.12 25 Aug 2015

    Nothing published for this version

  35. v3.0.11 01 Jun 2015

    Nothing published for this version

  36. v3.0.10 06 May 2015

    Nothing published for this version

  37. v3.0.9 01 Apr 2015

    Nothing published for this version

  38. v3.0.8 25 Mar 2015

    Nothing published for this version

  39. v3.0.7 14 Feb 2015

    Nothing published for this version

  40. v3.0.6 02 Feb 2015

    Nothing published for this version

  41. v3.0.5 30 Dec 2014

    Nothing published for this version

  42. 3.0.4 23 Dec 2014

    Nothing published for this version

  43. v3.0.3 24 Nov 2014

    Nothing published for this version

  44. v3.0.2 11 Nov 2014

    Nothing published for this version

  45. v3.0.1 05 Nov 2014

    Nothing published for this version

  46. v3.0.0 03 Nov 2014

    Nothing published for this version

  47. v1.0.9 30 Dec 2014

    Nothing published for this version

  48. v1.0.8 23 Dec 2014

    Nothing published for this version

  49. v1.0.7 07 Nov 2014

    Nothing published for this version

  50. v1.0.6 07 Nov 2014

    Nothing published for this version

  51. v1.0.5 21 Oct 2014

    Nothing published for this version

  52. v1.0.4 19 Oct 2014

    Nothing published for this version

  53. v1.0.3 15 Oct 2014

    Nothing published for this version

  54. v1.0.2 21 Jun 2014

    Nothing published for this version

  55. v1.0.1 16 May 2014

    Nothing published for this version

  56. v1.0.0 06 May 2014

    Nothing published for this version

  57. v0.1.6 01 May 2014

    Nothing published for this version

  58. v0.1.5 18 Dec 2013

    Nothing published for this version

  59. v0.1.4 04 Dec 2013

    Nothing published for this version

  60. v0.1.3 24 Oct 2013

    Nothing published for this version

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive