Home / Packages / @ivangrynenko/behat-ai-guide

@ivangrynenko/behat-ai-guide

Behat Ai Guide cursor rules

prpm install @ivangrynenko/behat-ai-guide
0 total downloads

📄 Full Prompt Content

---
description: This rule provides comprehensive guidance for AI assistants writing Behat tests for Drupal projects using the drevops/behat-steps package. It emphasizes reusing existing traits and steps rather than creating custom implementations. Contains the full STEPS.md reference embedded for easy access.
globs: *.feature,FeatureContext.php,*Context.php,behat.yml
alwaysApply: true
---

# AI Behat Test Writing Guide for Drupal Projects

## 🎯 Primary Directive

**ALWAYS prioritize using drevops/behat-steps traits and step definitions over writing custom steps.** The drevops/behat-steps package provides comprehensive test coverage for most Drupal testing scenarios.

## 📦 Essential Resources

Before writing ANY Behat test:
1. Check available steps in the [drevops/behat-steps STEPS.md](https://github.com/drevops/behat-steps/blob/main/STEPS.md) file or refer to the embedded reference below
2. Review trait source code in `vendor/drevops/behat-steps/src/` directory
3. Only create custom steps when absolutely necessary (functionality not covered by existing traits)

## 🔧 Setting Up FeatureContext

When creating or modifying FeatureContext.php, include the necessary traits from drevops/behat-steps. The traits are located in `vendor/drevops/behat-steps/src/`:

```php
<?php

namespace DrupalProject\Tests\Behat;

use Drupal\DrupalExtension\Context\DrupalContext;
// Generic traits from vendor/drevops/behat-steps/src/
use DrevOps\BehatSteps\CookieTrait;
use DrevOps\BehatSteps\DateTrait;
use DrevOps\BehatSteps\ElementTrait;
use DrevOps\BehatSteps\FieldTrait;
use DrevOps\BehatSteps\FileDownloadTrait;
use DrevOps\BehatSteps\KeyboardTrait;
use DrevOps\BehatSteps\LinkTrait;
use DrevOps\BehatSteps\PathTrait;
use DrevOps\BehatSteps\ResponseTrait;
use DrevOps\BehatSteps\WaitTrait;

// Drupal-specific traits from vendor/drevops/behat-steps/src/Drupal/
use DrevOps\BehatSteps\Drupal\BigPipeTrait;
use DrevOps\BehatSteps\Drupal\BlockTrait;
use DrevOps\BehatSteps\Drupal\ContentBlockTrait;
use DrevOps\BehatSteps\Drupal\ContentTrait;
use DrevOps\BehatSteps\Drupal\DraggableviewsTrait;
use DrevOps\BehatSteps\Drupal\EckTrait;
use DrevOps\BehatSteps\Drupal\EmailTrait;
use DrevOps\BehatSteps\Drupal\FieldTrait as DrupalFieldTrait;
use DrevOps\BehatSteps\Drupal\FileTrait;
use DrevOps\BehatSteps\Drupal\MediaTrait;
use DrevOps\BehatSteps\Drupal\MenuTrait;
use DrevOps\BehatSteps\Drupal\MetatagTrait;
use DrevOps\BehatSteps\Drupal\OverrideTrait;
use DrevOps\BehatSteps\Drupal\ParagraphsTrait;
use DrevOps\BehatSteps\Drupal\SearchApiTrait;
use DrevOps\BehatSteps\Drupal\TaxonomyTrait;
use DrevOps\BehatSteps\Drupal\TestmodeTrait;
use DrevOps\BehatSteps\Drupal\UserTrait;
use DrevOps\BehatSteps\Drupal\WatchdogTrait;

class FeatureContext extends DrupalContext {
    // Include only the traits you need for your tests
    // Generic traits
    use CookieTrait;
    use DateTrait;
    use ElementTrait;
    use FieldTrait;
    use FileDownloadTrait;
    use KeyboardTrait;
    use LinkTrait;
    use PathTrait;
    use ResponseTrait;
    use WaitTrait;
    
    // Drupal-specific traits
    use BlockTrait;
    use ContentTrait;
    use EmailTrait;
    use FileTrait;
    use MediaTrait;
    use TaxonomyTrait;
    use UserTrait;
    
    // Only add custom methods when drevops/behat-steps doesn't provide the functionality
}
```

## 🚫 When NOT to Create Custom Steps

Before creating ANY custom step, verify that drevops/behat-steps doesn't already provide it. Check the full reference below.

### Common Mistakes to Avoid:

1. **Creating custom user login steps**
   - ❌ Don't create: `Given I log in as an administrator`
   - ✅ Use UserTrait: `Given I am logged in as a user with the "administrator" role`

2. **Creating custom content creation steps**
   - ❌ Don't create: `Given I create an article titled :title`
   - ✅ Use ContentTrait: `Given "article" content:` with a table

3. **Creating custom field interaction steps**
   - ❌ Don't create: `When I fill in the body field with :text`
   - ✅ Use FieldTrait: `When I fill in "Body" with :text`

4. **Creating custom email verification steps**
   - ❌ Don't create: `Then I should receive an email`
   - ✅ Use EmailTrait: `Then an email is sent to :address`

5. **Creating custom element interaction steps**
   - ❌ Don't create: `When I click the submit button`
   - ✅ Use ElementTrait: `When I click on the element ".submit-button"`

## ✅ When to Create Custom Steps

Only create custom steps when:

1. **Business-specific logic** that wouldn't be reusable across projects
2. **Complex multi-step operations** that are repeated frequently in your tests
3. **Integration with third-party services** not covered by drevops/behat-steps
4. **Custom Drupal modules** with unique functionality

Example of a valid custom step:

```php
/**
 * @When I process the payment gateway response for order :order_id
 */
public function iProcessPaymentGatewayResponse($order_id) {
    // Custom implementation for your specific payment gateway
}
```

---

# Complete DrevOps Behat Steps Reference

The following is the complete reference from [drevops/behat-steps STEPS.md](https://github.com/drevops/behat-steps/blob/main/STEPS.md):

## Available steps

### Index of Generic steps

| Class | Description |
| --- | --- |
| [CookieTrait](#cookietrait) | Verify and inspect browser cookies. |
| [DateTrait](#datetrait) | Convert relative date expressions into timestamps or formatted dates. |
| [ElementTrait](#elementtrait) | Interact with HTML elements using CSS selectors and DOM attributes. |
| [FieldTrait](#fieldtrait) | Manipulate form fields and verify widget functionality. |
| [FileDownloadTrait](#filedownloadtrait) | Test file download functionality with content verification. |
| [KeyboardTrait](#keyboardtrait) | Simulate keyboard interactions in Drupal browser testing. |
| [LinkTrait](#linktrait) | Verify link elements with attribute and content assertions. |
| [PathTrait](#pathtrait) | Navigate and verify paths with URL validation. |
| [ResponseTrait](#responsetrait) | Verify HTTP responses with status code and header checks. |
| [WaitTrait](#waittrait) | Wait for a period of time or for AJAX to finish. |

### Index of Drupal steps

| Class | Description |
| --- | --- |
| [Drupal\BigPipeTrait](#drupalbigpipetrait) | Bypass Drupal BigPipe when rendering pages. |
| [Drupal\BlockTrait](#drupalblocktrait) | Manage Drupal blocks. |
| [Drupal\ContentBlockTrait](#drupalcontentblocktrait) | Manage Drupal content blocks. |
| [Drupal\ContentTrait](#drupalcontenttrait) | Manage Drupal content with workflow and moderation support. |
| [Drupal\DraggableviewsTrait](#drupaldraggableviewstrait) | Order items in the Drupal Draggable Views. |
| [Drupal\EckTrait](#drupalecktrait) | Manage Drupal ECK entities with custom type and bundle creation. |
| [Drupal\EmailTrait](#drupalemailtrait) | Test Drupal email functionality with content verification. |
| [Drupal\MediaTrait](#drupalmediatrait) | Manage Drupal media entities with type-specific field handling. |
| [Drupal\MenuTrait](#drupalmenutrait) | Manage Drupal menu systems and menu link rendering. |
| [Drupal\MetatagTrait](#drupalmetatagtrait) | Assert `<meta>` tags in page markup. |
| [Drupal\OverrideTrait](#drupaloverridetrait) | Override Drupal Extension behaviors. |
| [Drupal\ParagraphsTrait](#drupalparagraphstrait) | Manage Drupal paragraphs entities with structured field data. |
| [Drupal\SearchApiTrait](#drupalsearchapitrait) | Assert Drupal Search API with index and query operations. |
| [Drupal\TaxonomyTrait](#drupaltaxonomytrait) | Manage Drupal taxonomy terms with vocabulary organization. |
| [Drupal\TestmodeTrait](#drupaltestmodetrait) | Configure Drupal Testmode module for controlled testing scenarios. |
| [Drupal\UserTrait](#drupalusertrait) | Manage Drupal users with role and permission assignments. |
| [Drupal\WatchdogTrait](#drupalwatchdogtrait) | Assert Drupal does not trigger PHP errors during scenarios using Watchdog. |

---

## CookieTrait

[Source](vendor/drevops/behat-steps/src/CookieTrait.php)

>  Verify and inspect browser cookies.
>  - Assert cookie existence and values with exact or partial matching.
>  - Support both WebDriver and BrowserKit drivers for test compatibility.

### Available steps:

| Step | Description |
| --- | --- |
| `@Then a cookie with the name :name should exist` | Assert that a cookie exists |
| `@Then a cookie with the name :name and the value :value should exist` | Assert that a cookie exists with a specific value |
| `@Then a cookie with the name :name and a value containing :partial_value should exist` | Assert that a cookie exists with a value containing a partial value |
| `@Then a cookie with a name containing :partial_name should exist` | Assert that a cookie with a partial name exists |
| `@Then a cookie with a name containing :partial_name and the value :value should exist` | Assert that a cookie with a partial name and value exists |
| `@Then a cookie with a name containing :partial_name and a value containing :partial_value should exist` | Assert that a cookie with a partial name and partial value exists |
| `@Then a cookie with the name :name should not exist` | Assert that a cookie does not exist |
| `@Then a cookie with the name :name and the value :value should not exist` | Assert that a cookie with a specific value does not exist |
| `@Then a cookie with the name :name and a value containing :partial_value should not exist` | Assert that a cookie with a value containing a partial value does not exist |
| `@Then a cookie with a name containing :partial_name should not exist` | Assert that a cookie with a partial name does not exist |
| `@Then a cookie with a name containing :partial_name and the value :value should not exist` | Assert that a cookie with a partial name and value does not exist |
| `@Then a cookie with a name containing :partial_name and a value containing :partial_value should not exist` | Assert that a cookie with a partial name and partial value does not exist |

---

## DateTrait

[Source](vendor/drevops/behat-steps/src/DateTrait.php)

>  Convert relative date expressions into timestamps or formatted dates.
>  
>  Supports values and tables.
>  
>  Possible formats:
>  - `[relative:OFFSET]`
>  - `[relative:OFFSET#FORMAT]`
>
>  with:
>  - `OFFSET`: any format that can be parsed by `strtotime()`.
>  - `FORMAT`: `date()` format for additional processing.
>
>  Examples:
>  - `[relative:-1 day]` converted to `1893456000`
>  - `[relative:-1 day#Y-m-d]` converted to `2017-11-5`

---

## ElementTrait

[Source](vendor/drevops/behat-steps/src/ElementTrait.php)

>  Interact with HTML elements using CSS selectors and DOM attributes.
>  - Assert element visibility, attribute values, and viewport positioning.
>  - Execute JavaScript-based interactions with element state verification.
>  - Handle confirmation dialogs and scrolling operations.

### Available steps:

| Step | Description |
| --- | --- |
| `@Given I accept all confirmation dialogs` | Accept confirmation dialogs appearing on the page |
| `@Given I do not accept any confirmation dialogs` | Do not accept confirmation dialogs appearing on the page |
| `@When I click on the element :selector` | Click on the element defined by the selector |
| `@When I trigger the JS event :event on the element :selector` | Trigger a JavaScript event on an element |
| `@When I scroll to the element :selector` | Scroll to an element with ID |
| `@Then the element :selector with the attribute :attribute and the value :value should exist` | Assert an element with selector and attribute with a value exists |
| `@Then the element :selector with the attribute :attribute and the value containing :value should exist` | Assert an element with selector and attribute containing a value exists |
| `@Then the element :selector with the attribute :attribute and the value :value should not exist` | Assert an element with selector and attribute with a value does not exist |
| `@Then the element :selector with the attribute :attribute and the value containing :value should not exist` | Assert an element with selector and attribute containing a value does not exist |
| `@Then the element :selector should be at the top of the viewport` | Assert the element should be at the top of the viewport |
| `@Then the element :selector should be displayed` | Assert that element with specified CSS is visible on page |
| `@Then the element :selector should not be displayed` | Assert that element with specified CSS is not visible on page |
| `@Then the element :selector should be displayed within a viewport` | Assert that element with specified CSS is displayed within a viewport |
| `@Then the element :selector should be displayed within a viewport with a top offset of :number pixels` | Assert that element with specified CSS is displayed within a viewport with a top offset |
| `@Then the element :selector should not be displayed within a viewport with a top offset of :number pixels` | Assert that element with specified CSS is not displayed within a viewport with a top offset |
| `@Then the element :selector should not be displayed within a viewport` | Assert that element with specified CSS is visually hidden on page |

---

## FieldTrait

[Source](vendor/drevops/behat-steps/src/FieldTrait.php)

>  Manipulate form fields and verify widget functionality.
>  - Set field values for various input types including selects and WYSIWYG.
>  - Assert field existence, state, and selected options.
>  - Support for specialized widgets like color pickers and rich text editors.

### Available steps:

| Step | Description |
| --- | --- |
| `@When I fill in the color field :field with the value :value` | Fill value for color field |
| `@When I fill in the WYSIWYG field :field with the :value` | Set value for WYSIWYG field |
| `@Then the field :name should exist` | Assert that field exists on the page using id, name, label or value |
| `@Then the field :name should not exist` | Assert that field does not exist on the page using id, name, label or value |
| `@Then the field :name should be :enabled_or_disabled` | Assert whether the field has a state |
| `@Then the color field :field should have the value :value` | Assert that a color field has a value |
| `@Then the option :option should exist within the select element :selector` | Assert that a select has an option |
| `@Then the option :option should not exist within the select element :selector` | Assert that a select does not have an option |
| `@Then the option :option should be selected within the select element :selector` | Assert that a select option is selected |
| `@Then the option :option should not be selected within the select element :selector` | Assert that a select option is not selected |

---

## FileDownloadTrait

[Source](vendor/drevops/behat-steps/src/FileDownloadTrait.php)

>  Test file download functionality with content verification.
>  - Download files through links and URLs with session cookie handling.
>  - Verify file names, content, and extracted archives.
>  - Set up download directories and handle file cleanup.
>
>  Skip processing with tags: `@behat-steps-skip:fileDownloadBeforeScenario` or
>  `@behat-steps-skip:fileDownloadAfterScenario`
>  
>  Special tags:
>  - `@download` - enable download handling

### Available steps:

| Step | Description |
| --- | --- |
| `@When I download the file from the URL :url` | Download a file from the specified URL |
| `@When I download the file from the link :link` | Download the file from the specified HTML link |
| `@Then the downloaded file should contain:` | Assert the contents of the download file |
| `@Then the downloaded file name should be :name` | Assert the file name of the downloaded file |
| `@Then the downloaded file name should contain :name` | Assert the downloaded file name contains a specific string |
| `@Then the downloaded file should be a zip archive containing the files named:` | Assert the downloaded file should be a zip archive containing specific files |
| `@Then the downloaded file should be a zip archive containing the files partially named:` | Assert the downloaded file should be a zip archive containing files with partial names |
| `@Then the downloaded file should be a zip archive not containing the files partially named:` | Assert the downloaded file is a zip archive not containing files with partial names |

---

## KeyboardTrait

[Source](vendor/drevops/behat-steps/src/KeyboardTrait.php)

>  Simulate keyboard interactions in Drupal browser testing.
>  - Trigger key press events including special keys and key combinations.
>  - Assert keyboard navigation and shortcut functionality.
>  - Support for targeted key presses on specific page elements.

### Available steps:

| Step | Description |
| --- | --- |
| `@When I press the key :key` | Press a single keyboard key |
| `@When I press the key :key on the element :selector` | Press a single keyboard key on the element |
| `@When I press the keys :keys` | Press multiple keyboard keys |
| `@When I press the keys :keys on the element :selector` | Press multiple keyboard keys on the element |

---

## LinkTrait

[Source](vendor/drevops/behat-steps/src/LinkTrait.php)

>  Verify link elements with attribute and content assertions.
>  - Find links by title, URL, text content, and class attributes.
>  - Test link existence, visibility, and destination accuracy.
>  - Assert absolute and relative link paths.

### Available steps:

| Step | Description |
| --- | --- |
| `@When I click on the link with the title :title` | Click on the link with a title |
| `@Then the link :link with the href :href should exist` | Assert a link with a href exists |
| `@Then the link :link with the href :href within the element :selector should exist` | Assert link with a href exists within an element |
| `@Then the link :link with the href :href should not exist` | Assert link with a href does not exist |
| `@Then the link :link with the href :href within the element :selector should not exist` | Assert link with a href does not exist within an element |
| `@Then the link with the title :title should exist` | Assert that a link with a title exists |
| `@Then the link with the title :title should not exist` | Assert that a link with a title does not exist |
| `@Then the link :link should be an absolute link` | Assert that the link with a text is absolute |
| `@Then the link :link should not be an absolute link` | Assert that the link is not an absolute |

---

## PathTrait

[Source](vendor/drevops/behat-steps/src/PathTrait.php)

>  Navigate and verify paths with URL validation.
>  - Assert current page location with front page special handling.
>  - Configure basic authentication for protected path access.

### Available steps:

| Step | Description |
| --- | --- |
| `@Given the basic authentication with the username :username and the password :password` | Set basic authentication for the current session |
| `@Then the path should be :path` | Assert that the current page is a specified path |
| `@Then the path should not be :path` | Assert that the current page is not a specified path |

---

## ResponseTrait

[Source](vendor/drevops/behat-steps/src/ResponseTrait.php)

>  Verify HTTP responses with status code and header checks.
>  - Assert HTTP header presence and values.

### Available steps:

| Step | Description |
| --- | --- |
| `@Then the response should contain the header :header_name` | Assert that a response contains a header with specified name |
| `@Then the response should not contain the header :header_name` | Assert that a response does not contain a header with a specified name |
| `@Then the response header :header_name should contain the value :header_value` | Assert that a response contains a header with a specified name and value |
| `@Then the response header :header_name should not contain the value :header_value` | Assert a response does not contain a header with a specified name and value |

---

## WaitTrait

[Source](vendor/drevops/behat-steps/src/WaitTrait.php)

>  Wait for a period of time or for AJAX to finish.

### Available steps:

| Step | Description |
| --- | --- |
| `@When I wait for :seconds second(s)` | Wait for a specified number of seconds |
| `@When I wait for :seconds second(s) for AJAX to finish` | Wait for the AJAX calls to finish |

---

## Drupal\BigPipeTrait

[Source](vendor/drevops/behat-steps/src/Drupal/BigPipeTrait.php)

>  Bypass Drupal BigPipe when rendering pages.
>  
>  Activated by adding `@big_pipe` tag to the scenario.
>  
>  Skip processing with tags: `@behat-steps-skip:bigPipeBeforeScenario` or
>  `@behat-steps-skip:bigPipeBeforeStep`.

---

## Drupal\BlockTrait

[Source](vendor/drevops/behat-steps/src/Drupal/BlockTrait.php)

>  Manage Drupal blocks.
>  - Create and configure blocks with custom visibility conditions.
>  - Place blocks in regions and verify their rendering in the page.
>  - Automatically clean up created blocks after scenario completion.
>
>  Skip processing with tag: `@behat-steps-skip:blockAfterScenario`

### Available steps:

| Step | Description |
| --- | --- |
| `@Given the instance of :admin_label block exists with the following configuration:` | Create a block instance |
| `@Given the block :label has the following configuration:` | Configure an existing block identified by label |
| `@Given the block :label does not exist` | Remove a block specified by label |
| `@Given the block :label is enabled` | Enable a block specified by label |
| `@Given the block :label is disabled` | Disable a block specified by label |
| `@Given the block :label has the following :condition condition configuration:` | Set a visibility condition for a block |
| `@Given the block :label has the :condition condition removed` | Remove a visibility condition from the specified block |
| `@Then the block :label should exist` | Assert that a block with the specified label exists |
| `@Then the block :label should not exist` | Assert that a block with the specified label does not exist |
| `@Then the block :label should exist in the :region region` | Assert that a block with the specified label exists in a region |
| `@Then the block :label should not exist in the :region region` | Assert that a block with the specified label does not exist in a region |

---

## Drupal\ContentBlockTrait

[Source](vendor/drevops/behat-steps/src/Drupal/ContentBlockTrait.php)

>  Manage Drupal content blocks.
>  - Define reusable custom block content with structured field data.
>  - Create, edit, and verify block_content entities by type and description.
>  - Automatically clean up created entities after scenario completion.
>
>  Skip processing with tag: `@behat-steps-skip:contentBlockAfterScenario`

### Available steps:

| Step | Description |
| --- | --- |
| `@Given the following :type content blocks do not exist:` | Remove content blocks of a specified type with the given descriptions |
| `@Given the following :type content blocks exist:` | Create content blocks of the specified type with the given field values |
| `@When I edit the :type content block with the description :description` | Navigate to the edit page for a specified content block |
| `@Then the content block type :type should exist` | Assert that a content block type exists |

---

## Drupal\ContentTrait

[Source](vendor/drevops/behat-steps/src/Drupal/ContentTrait.php)

>  Manage Drupal content with workflow and moderation support.
>  - Create, find, and manipulate nodes with structured field data.
>  - Navigate to node pages by title and manage editorial workflows.
>  - Support content moderation transitions and scheduled publishing.

### Available steps:

| Step | Description |
| --- | --- |
| `@Given the content type :content_type does not exist` | Delete content type |
| `@Given the following :content_type content does not exist:` | Remove content defined by provided properties |
| `@When I visit the :content_type content page with the title :title` | Visit a page of a type with a specified title |
| `@When I visit the :content_type content edit page with the title :title` | Visit an edit page of a type with a specified title |
| `@When I visit the :content_type content delete page with the title :title` | Visit a delete page of a type with a specified title |
| `@When I visit the :content_type content scheduled transitions page with the title :title` | Visit a scheduled transitions page of a type with a specified title |
| `@When I change the moderation state of the :content_type content with the title :title to the :new_state state` | Change moderation state of a content with the specified title |

---

## Drupal\DraggableviewsTrait

[Source](vendor/drevops/behat-steps/src/Drupal/DraggableviewsTrait.php)

>  Order items in the Drupal Draggable Views.

### Available steps:

| Step | Description |
| --- | --- |
| `@When I save the draggable views items of the view :view_id and the display :views_display_id for the :bundle content in the following order:` | Save order of the Draggable Order items |

---

## Drupal\EckTrait

[Source](vendor/drevops/behat-steps/src/Drupal/EckTrait.php)

>  Manage Drupal ECK entities with custom type and bundle creation.
>  - Create structured ECK entities with defined field values.
>  - Assert entity type registration and visit entity pages.
>  - Automatically clean up created entities after scenario completion.
>
>  Skip processing with tag: `@behat-steps-skip:eckAfterScenario`

### Available steps:

| Step | Description |
| --- | --- |
| `@Given the following eck :bundle :entity_type entities exist:` | Create eck entities |
| `@Given the following eck :bundle :entity_type entities do not exist:` | Remove custom entities by field |
| `@When I visit eck :bundle :entity_type entity with the title :title` | Navigate to view entity page with specified type and title |
| `@When I edit eck :bundle :entity_type entity with the title :title` | Navigate to edit eck entity page with specified type and title |

---

## Drupal\EmailTrait

[Source](vendor/drevops/behat-steps/src/Drupal/EmailTrait.php)

>  Test Drupal email functionality with content verification.
>  - Capture and examine outgoing emails with header and body validation.
>  - Follow links and test attachments within email content.
>  - Configure mail handler systems for proper test isolation.
>
>  Skip processing with tags: `@behat-steps-skip:emailBeforeScenario` or
>  `@behat-steps-skip:emailAfterScenario`
>  
>  Special tags:
>  - `@email` - enable email tracking using a default handler
>  - `@email:{type}` - enable email tracking using a `{type}` handler
>  - `@debug` (enable detailed logs)

### Available steps:

| Step | Description |
| --- | --- |
| `@When I clear the test email system queue` | Clear test email system queue |
| `@When I follow link number :link_number in the email with the subject :subject` | Follow a specific link number in an email with the given subject |
| `@When I follow link number :link_number in the email with the subject containing :subject` | Follow a specific link number in an email whose subject contains the given substring |
| `@When I enable the test email system` | Enable the test email system |
| `@When I disable the test email system` | Disable test email system |
| `@Then an email is sent to :address` | Assert that an email should be sent to an address |
| `@Then no emails were sent` | Assert that no email messages should be sent |
| `@Then no emails were sent to :address` | Assert that no email messages should be sent to a specified address |
| `@Then an email :field contains:` | Assert that the email message field should contain specified content |
| `@Then an email :field is:` | Assert that the email message field should exactly match specified content |
| `@Then an email :field does not contain:` | Assert that the email message field should not contain specified content |
| `@Then an email to :address is sent` | Assert that an email is sent to a specific address |
| `@Then an email to :address is sent with the subject :subject` | Assert that an email with subject is sent to a specific address |
| `@Then an email to :address is sent with the subject containing :subject` | Assert that an email with subject containing text is sent to a specific address |
| `@Then an email to :address is not sent` | Assert that an email is not sent to a specific address |
| `@Then the file :file is attached to the email with the subject :subject` | Assert that a file is attached to an email message with specified subject |
| `@Then the file :file is attached to the email with the subject containing :subject` | Assert that a file is attached to an email message with a subject containing the specified substring |

### IMPORTANT Email Testing Notes:

**Always use @email tag for email testing scenarios** - the `@email` tag is required for each scenario that tests email functionality, not just at the feature level. Without this tag, email-related steps will fail with "email testing system is not activated" errors.

```gherkin
@api @email
Scenario: Test email notifications
  Given I am logged in as a user with the "administrator" role
  When I perform an action that triggers email
  Then an email is sent to "user@example.com"
  Then an email "subject" contains:
    """
    Welcome to our site
    """
```

---

## Drupal\FileTrait

[Source](vendor/drevops/behat-steps/src/Drupal/FileTrait.php)

> Manage Drupal file entities and operations.
> - Handle file uploads, downloads, and management operations.
> - Work with managed and unmanaged files in Drupal.
> - Automatically clean up created file entities after scenario completion.

Use `FileTrait` and `MediaTrait` from drevops/behat-steps along with built-in Drupal steps for file entities:

### Available steps:

| Step | Description |
| --- | --- |
| `@Given the following managed files:` | Create managed files with properties provided in the table (from DrupalContext) |
| `@Given the following managed files do not exist:` | Delete managed files defined by provided properties/fields (from DrupalContext) |
| `@Given the unmanaged file at the URI :uri exists` | Create an unmanaged file (from DrupalContext) |
| `@Given the unmanaged file at the URI :uri exists with :content` | Create an unmanaged file with specified content (from DrupalContext) |
| `@Then an unmanaged file at the URI :uri should exist` | Assert that an unmanaged file with specified URI exists (from DrupalContext) |
| `@Then an unmanaged file at the URI :uri should not exist` | Assert that an unmanaged file with specified URI does not exist (from DrupalContext) |
| `@Then an unmanaged file at the URI :uri should contain :content` | Assert that an unmanaged file exists and has specified content (from DrupalContext) |
| `@Then an unmanaged file at the URI :uri should not contain :content` | Assert that an unmanaged file exists and does not have specified content (from DrupalContext) |

---

## Drupal\MediaTrait

[Source](vendor/drevops/behat-steps/src/Drupal/MediaTrait.php)

>  Manage Drupal media entities with type-specific field handling.
>  - Create structured media items with proper file reference handling.
>  - Assert media browser functionality and edit media entity fields.
>  - Support for multiple media types with field value expansion handling.
>  - Automatically clean up created entities after scenario completion.
>
>  Skip processing with tag: `@behat-steps-skip:mediaAfterScenario`

### Available steps:

| Step | Description |
| --- | --- |
| `@Given :media_type media type does not exist` | Remove media type |
| `@Given the following media :media_type exist:` | Create media of a given type |
| `@Given the following media :media_type do not exist:` | Remove media defined by provided properties |
| `@When I edit the media :media_type with the name :name` | Navigate to edit media with specified type and name |

---

## Drupal\MenuTrait

[Source](vendor/drevops/behat-steps/src/Drupal/MenuTrait.php)

>  Manage Drupal menu systems and menu link rendering.
>  - Assert menu items by label, path, and containment hierarchy.
>  - Assert menu link visibility and active states in different regions.
>  - Create and manage menu hierarchies with parent-child relationships.
>  - Automatically clean up created menu links after scenario completion.
>
>  Skip processing with tag: `@behat-steps-skip:menuAfterScenario`

### Available steps:

| Step | Description |
| --- | --- |
| `@Given the menu :menu_name does not exist` | Remove a single menu by its label if it exists |
| `@Given the following menus:` | Create a menu if one does not exist |
| `@Given the following menu links do not exist in the menu :menu_name:` | Remove menu links by title |
| `@Given the following menu links exist in the menu :menu_name:` | Create menu links |

---

## Drupal\MetatagTrait

[Source](vendor/drevops/behat-steps/src/Drupal/MetatagTrait.php)

>  Assert `<meta>` tags in page markup.
>  - Assert presence and content of meta tags with proper attribute handling.

---

## Drupal\OverrideTrait

[Source](vendor/drevops/behat-steps/src/Drupal/OverrideTrait.php)

>  Override Drupal Extension behaviors.
>  - Automated entity deletion before creation to avoid duplicates.
>  - Improved user authentication handling for anonymous users.
>
>  Use with caution: depending on your version of Drupal Extension, PHP and
>  Composer, the step definition string (/^Given etc.../) may need to be defined
>  for these overrides. If you encounter errors about missing or duplicated
>  step definitions, do not include this trait and rather copy the contents of
>  this file into your feature context file and copy the step definition strings
>  from the Drupal Extension.

---

## Drupal\ParagraphsTrait

[Source](vendor/drevops/behat-steps/src/Drupal/ParagraphsTrait.php)

>  Manage Drupal paragraphs entities with structured field data.
>  - Create paragraph items with type-specific field values.
>  - Test nested paragraph structures and reference field handling.
>  - Attach paragraphs to various entity types with parent-child relationships.
>  - Automatically clean up created paragraph items after scenario completion.
>
>  Skip processing with tag: `@behat-steps-skip:paragraphsAfterScenario`

### Available steps:

| Step | Description |
| --- | --- |
| `@Given the following fields for the paragraph :paragraph_type exist in the field :parent_field within the :parent_bundle :parent_entity_type identified by the field :parent_lookup_field and the value :parent_lookup_value:` | Create a paragraph of the given type with fields within an existing entity |

---

## Drupal\SearchApiTrait

[Source](vendor/drevops/behat-steps/src/Drupal/SearchApiTrait.php)

>  Assert Drupal Search API with index and query operations.
>  - Add content to an index
>  - Run indexing for a specific number of items.

### Available steps:

| Step | Description |
| --- | --- |
| `@When I add the :content_type content with the title :title to the search index` | Index a node of a specific content type with a specific title |
| `@When I run search indexing for :count item(s)` | Run indexing for a specific number of items |

---

## Drupal\TaxonomyTrait

[Source](vendor/drevops/behat-steps/src/Drupal/TaxonomyTrait.php)

>  Manage Drupal taxonomy terms with vocabulary organization.
>  - Create term vocabulary structures using field values.
>  - Navigate to term pages
>  - Verify vocabulary configurations.

### Available steps:

| Step | Description |
| --- | --- |
| `@Given the following :vocabulary_machine_name vocabulary terms do not exist:` | Remove terms from a specified vocabulary |
| `@When I visit the :vocabulary_machine_name vocabulary :term_name term page` | Visit specified vocabulary term page |
| `@When I edit the :vocabulary_machine_name vocabulary :term_name term page` | Edit specified vocabulary term page |
| `@Then the vocabulary :machine_name with the name :name should exist` | Assert that a vocabulary with a specific name exists |
| `@Then the vocabulary :machine_name should not exist` | Assert that a vocabulary with a specific name does not exist |
| `@Then the taxonomy term :term_name from the vocabulary :vocabulary_machine_name should exist` | Assert that a taxonomy term exist by name |
| `@Then the taxonomy term :term_name from the vocabulary :vocabulary_machine_name should not exist` | Assert that a taxonomy term does not exist by name |

---

## Drupal\TestmodeTrait

[Source](vendor/drevops/behat-steps/src/Drupal/TestmodeTrait.php)

>  Configure Drupal Testmode module for controlled testing scenarios.
>  
>  Skip processing with tags: `@behat-steps-skip:testmodeBeforeScenario` and
>  `@behat-steps-skip:testmodeAfterScenario`.
>  
>  Special tags:
>  - `@testmode` - enable for scenario

---

## Drupal\UserTrait

[Source](vendor/drevops/behat-steps/src/Drupal/UserTrait.php)

>  Manage Drupal users with role and permission assignments.
>  - Create user accounts
>  - Create user roles
>  - Visit user profile pages for editing and deletion.
>  - Assert user roles and permissions.
>  - Assert user account status (active/inactive).

### Available steps:

| Step | Description |
| --- | --- |
| `@Given the following users do not exist:` | Remove users specified in a table |
| `@Given the password for the user :name is :password` | Set a password for a user |
| `@Given the last access time for the user :name is :datetime` | Set last access time for a user |
| `@Given the last login time for the user :name is :datetime` | Set last login time for a user |
| `@Given the role :role_name with the permissions :permissions` | Create a single role with specified permissions |
| `@Given the following roles:` | Create multiple roles from the specified table |
| `@When I visit :name user profile page` | Visit the profile page of the specified user |
| `@When I visit my own user profile page` | Visit the profile page of the current user |
| `@When I visit :name user profile edit page` | Visit the profile edit page of the specified user |
| `@When I visit my own user profile edit page` | Visit the profile edit page of the current user |
| `@When I visit :name user profile delete page` | Visit the profile delete page of the specified user |
| `@When I visit my own user profile delete page` | Visit the profile delete page of the current user |
| `@Then the user :name should have the role(s) :roles assigned` | Assert that a user has roles assigned |
| `@Then the user :name should not have the role(s) :roles assigned` | Assert that a user does not have roles assigned |
| `@Then the user :name should be blocked` | Assert that a user is blocked |
| `@Then the user :name should not be blocked` | Assert that a user is not blocked |

---

## Drupal\WatchdogTrait

[Source](vendor/drevops/behat-steps/src/Drupal/WatchdogTrait.php)

>  Assert Drupal does not trigger PHP errors during scenarios using Watchdog.
>  - Check for Watchdog messages after scenario completion.
>  - Optionally check only for specific message types.
>  - Optionally skip error checking for specific scenarios.
>
>  Skip processing with tags: `@behat-steps-skip:watchdogSetScenario` or
>  `@behat-steps-skip:watchdogAfterScenario`
>  
>  Special tags:
>  - `@watchdog:{type}` - limit watchdog messages to specific types.
>  - `@error` - add to scenarios that are expected to trigger an error.

---

## 📝 Best Practices

### 1. Trait Organization
Always check what traits are available in `vendor/drevops/behat-steps/src/` before creating custom steps:

```php
class FeatureContext extends DrupalContext {
    // Only include the traits you actually use
    use ContentTrait;  // For content management
    use UserTrait;     // For user operations
    use EmailTrait;    // For email testing
    
    // Custom methods only when absolutely necessary
}
```

### 2. Tag Usage for Special Features
```gherkin
# Enable email testing - REQUIRED for email steps
@email
Scenario: Test email functionality

# Enable JavaScript testing
@javascript
Scenario: Test AJAX functionality

# Skip certain trait behaviors
@behat-steps-skip:emailBeforeScenario
Scenario: Test without email initialization
```

### 3. Error Handling
When tests fail, check:
1. Is the correct trait included in FeatureContext?
2. Are you using the exact step definition from drevops/behat-steps?
3. Do you have the required tags (@api, @email, @javascript)?
4. Is the selector or field name correct?

### 4. Performance Optimization
- Use traits selectively - only include what you need
- Avoid creating wrapper steps around existing drevops/behat-steps
- Use batch operations where available (e.g., creating multiple users at once)

## 🔍 Quick Reference Checklist

Before writing any Behat test:

- [ ] Check the embedded reference above or [STEPS.md](https://github.com/drevops/behat-steps/blob/main/STEPS.md) for available steps
- [ ] Review trait source code in `vendor/drevops/behat-steps/src/`
- [ ] Include only necessary traits in FeatureContext
- [ ] Use proper tags (@api, @email, @javascript) as required
- [ ] Follow exact step syntax from drevops/behat-steps
- [ ] Only create custom steps for truly unique functionality
- [ ] Test that existing steps work before creating alternatives
- [ ] Document any custom steps thoroughly

## 📚 Additional Resources

- [DrevOps Behat Steps Documentation](https://github.com/drevops/behat-steps)
- [DrevOps Behat Steps STEPS.md](https://github.com/drevops/behat-steps/blob/main/STEPS.md)
- [Drupal Extension for Behat](https://www.drupal.org/project/drupalextension)

Remember: **The drevops/behat-steps package is battle-tested and covers most Drupal testing scenarios. Always use it instead of reinventing the wheel!**

💡 Suggested Test Inputs

Loading suggested inputs...

🎯 Community Test Results

Loading results...

📦 Package Info

Format
cursor
Type
rule
Category
general
License
MIT

🏷️ Tags