Sorry, you need to enable JavaScript to visit this website.

Supercharging your Drupal testing with Behat Steps

Last updated: 19 Feb 2026

If you’ve ever tried to explain automated testing to a project manager while simultaneously taming a flaky CI pipeline, you already know: testing is essential… but it can also feel like dragging a boulder up a hill.

That’s exactly why we built Behat Steps(Opens in a new tab/window).

This little library grew out of years of shipping Drupal projects, dealing with shifting requirements, content-heavy sites, and “quick fixes” that turn into regression nightmares. After watching teams repeatedly write the same step definitions, reinvent the same assertions, and copy-paste similar helper methods, the issue became obvious:

Teams waste an enormous amount of time re-creating the same Behat steps.

So we fixed that.
And then we shared it.

Whether you’re working on enterprise platforms, brochures sites, or heavily editorial workflows, this library gives you a deep set of reusable, production-tested Behat steps specifically tuned for Drupal.

Let’s walk through what it is, how it works, and how to use it effectively — with or without AI in the mix.

Why Behat still deserves a place in your workflow

If you’ve ever been burned by a bug that “shouldn’t have happened,” then you already understand why automated testing matters.

Behat offers three real-world advantages:

  • Scenarios read like conversations, not code
  • Regression checks become predictable and repeatable
  • Requirements turn into living documentation, not forgotten Confluence pages

When written well, a Behat scenario tells a story that everyone — from QA to PM to developer — can follow:

Feature: User login

  Scenario: A user signs in successfully
    Given I am on "/user/login"
    When I fill in "Username" with "editor"
    And I fill in "Password" with "secret987"
    And I press "Log in"
    Then I should see "Welcome back"

Readable. Reviewable. Executable.

The real power, however, isn’t the Gherkin syntax — it’s the quality and reusability of the steps available. And that’s where Behat Steps shines.

What the Behat Steps library actually provides

The library is built around traits that you mix into your Behat contexts.
Each trait contains a collection of well-structured, reusable steps.

A few examples of what’s available:
    •    Navigation and path handling
    •    HTTP response and header assertions
    •    Waiting, DOM element interactions, JavaScript checks
    •    Drupal content creation, modification, and querying
    •    User and role management
    •    File uploads, media creation, taxonomy handling
    •    JSON and API response assertions

Instead of bloating your FeatureContext with custom PHP, you pull in the traits you need:

<?php
use Drupal\DrupalExtension\Context\DrupalContext;
use DrevOps\BehatSteps\PathTrait;
use DrevOps\BehatSteps\ResponseTrait;
use DrevOps\BehatSteps\WaitTrait;
use DrevOps\BehatSteps\Drupal\ContentTrait;
use DrevOps\BehatSteps\Drupal\UserTrait;
class FeatureContext extends DrupalContext {
  use PathTrait;
  use ResponseTrait;
  use WaitTrait;
  use ContentTrait;
  use UserTrait;
}

Traits keep things modular.
You only include what you need, and every trait has clearly defined, discoverable steps.

You’ll find the full catalogue of available steps under: vendor/drevops/behat-steps/STEPS.md(Opens in a new tab/window)

This file is your best friend — it documents all steps grouped by trait.

Getting started in a Drupal Project

One of the goals of this library is to remove friction, so setup is intentionally minimal.

1. Install the package

composer require --dev drevops/behat-steps

2. Add the traits you need to your Behat context

Most Drupal projects start with something like this:

<?php
use Drupal\DrupalExtension\Context\DrupalContext;
use DrevOps\BehatSteps\Drupal\ContentTrait;
use DrevOps\BehatSteps\Drupal\UserTrait;
use DrevOps\BehatSteps\PathTrait;
use DrevOps\BehatSteps\ResponseTrait;
class FeatureContext extends DrupalContext {
  use UserTrait;
  use ContentTrait;
  use PathTrait;
  use ResponseTrait;
}

You can expand this over time — you don’t need every trait on day one.

3. Keep existing behat.yml

The library doesn’t replace your Behat configuration.
It simply expands what your contexts can do.

Once this is in place, you can begin writing scenarios using any of the documented steps.

Going Further: More Advanced Testing Scenarios

Most Behat examples online are too simplistic to represent real projects.
Here are deeper, more realistic examples to show the breadth of what you can do with these steps.

A Full Content Workflow Example (Creation → Moderation → Verification)

This scenario layers traits for content, users, paths, and responses:

Feature: Article publishing workflow
  
  Background:
    Given the following users exist:
      | name    | mail               | roles            |
      | editor  | [email protected] | content_editor   |
      | reviewer| [email protected] | content_review |
  
  Scenario: Editor creates an article, reviewer publishes it, and it becomes publicly accessible
    Given the following "article" content exists:
      | title              | field_summary                 | status | moderation_state |
      | Reviewable Story   | This requires review approval | 0      | draft            |
    And I am logged in as "editor"
    
    When I visit the "article" content page with the title "Reviewable Story"
    Then the page should contain "Reviewable Story"
    And the response status code should be 200
    
    When I update the "article" content titled "Reviewable Story":
      | moderation_state | needs_review |
    Then the "article" content titled "Reviewable Story" should have "moderation_state" set to "needs_review"
    And I am logged in as "reviewer"
    
    When I publish the "article" content titled "Reviewable Story"
    Then the "article" content titled "Reviewable Story" should be published
    And I am an anonymous user
    
    When I visit the "article" content page with the title "Reviewable Story"
    Then the response status code should be 200
    And I should see "Reviewable Story"

This is something teams manually test every sprint — automating it saves hours.

Advanced Front-End checks (JS, Responsive Behaviour, Interaction)

Behat isn’t only about backend behaviours.
These steps make browser-based testing much more robust.

Scenario: Mega menu collapses and expands correctly on mobile
 Given I set the viewport to "375x812"
 And I am on "/"

 When I click on the element ".menu-toggle"
 Then the element ".main-menu" should have the class "open"

 When I click on the element ".menu-toggle"
 Then the element ".main-menu" should not have the class "open"

 And there should be no javascript errors

This scenario touches responsive behaviour, JS, and DOM state — all achievable with existing traits.

Integration-Level assertions (Headers, JSON, Redirects)

Behat Steps includes powerful low-level assertions that go beyond simple page checks.

JSON API endpoint validation

Scenario: Article API returns expected structure
 Given there is an "article" content item titled "API Story"
 When I send a GET request to "/api/articles?title=API+Story"
 Then the response status code should be 200
 And the response header "Content-Type" should contain "application/json"
 And the JSON response should have a property "data[0].title" with the value "API Story"
 And the JSON response should not have a property "data[0].internal_notes"

Redirect verification

Scenario: Old URL redirects to canonical article path
 Given there is an "article" content item titled "Legacy Piece"
 And the "Legacy Piece" article has an alias "/stories/legacy-piece"
 When I go to "/old/legacy-piece"
 Then the response status code should be 301
 And the response header "Location" should contain "/stories/legacy-piece"

These checks catch the kind of issues that often slip through manual testing.

Where AI fits into all this

Teams often say they’re “too busy” to write tests — which is ironic, because those same teams spend far more time debugging regressions later.

This is where AI becomes a multiplier, not a replacement:

  • You can describe a workflow in plain English
    and ask your AI assistant to generate a Behat scenario using steps from the DrevOps traits.
  • You can paste HTML fragments, and AI can propose selectors and element steps.
  • You can feed an entire acceptance criteria document into AI
    and get a first draft of scenarios that cover each rule.

It turns “writing tests” into “refining tests,” which is significantly faster.

The combination of well-documented reusable steps and AI-assisted drafting greatly lowers the barrier to Behat adoption for busy teams.

If you want to explore further…

Behat Steps(Opens in a new tab/window) is fully open source.
It’s built from real project needs, used daily in actual delivery work, and improved incrementally based on the odd bug, the occasional edge case, and the “why does Drupal behave this way?” moment we’ve all had.

If you’re curious:
    •    Install it
    •    Add a few traits
    •    Automate one important user journey
    •    Build from there

And if you find gaps, ideas, or inconsistencies, the GitHub repo is a great place to open an issue or contribute an example.

The more voices involved, the better the library becomes — not just for us, but for everyone using Behat with Drupal.

  • Blog
  • Testing