Cursor rule
.cursor/rules/behat-ai-guide.mdcThis 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.
Cursor rules
Quality
45/100
Scores the file, not the repository.Length
6,290 words
72 headings · 5 code blocksRepository
86
— · pushed 280 days agoLast changed
3 days ago
First indexed 3 days ago.1234567# AI Behat Test Writing Guide for Drupal Projects89## 🎯 Primary Directive1011**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.1213## 📦 Essential Resources1415Before writing ANY Behat test:161. 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 below172. Review trait source code in `vendor/drevops/behat-steps/src/` directory183. Only create custom steps when absolutely necessary (functionality not covered by existing traits)1920## 🔧 Setting Up FeatureContext2122When creating or modifying FeatureContext.php, include the necessary traits from drevops/behat-steps. The traits are located in `vendor/drevops/behat-steps/src/`:2324```php25<?php2627namespace DrupalProject\Tests\Behat;2829use Drupal\DrupalExtension\Context\DrupalContext;30// Generic traits from vendor/drevops/behat-steps/src/31use DrevOps\BehatSteps\CookieTrait;32use DrevOps\BehatSteps\DateTrait;33use DrevOps\BehatSteps\ElementTrait;34use DrevOps\BehatSteps\FieldTrait;35use DrevOps\BehatSteps\FileDownloadTrait;36use DrevOps\BehatSteps\KeyboardTrait;37use DrevOps\BehatSteps\LinkTrait;38use DrevOps\BehatSteps\PathTrait;39use DrevOps\BehatSteps\ResponseTrait;40use DrevOps\BehatSteps\WaitTrait;4142// Drupal-specific traits from vendor/drevops/behat-steps/src/Drupal/43use DrevOps\BehatSteps\Drupal\BigPipeTrait;44use DrevOps\BehatSteps\Drupal\BlockTrait;45use DrevOps\BehatSteps\Drupal\ContentBlockTrait;46use DrevOps\BehatSteps\Drupal\ContentTrait;47use DrevOps\BehatSteps\Drupal\DraggableviewsTrait;48use DrevOps\BehatSteps\Drupal\EckTrait;49use DrevOps\BehatSteps\Drupal\EmailTrait;50use DrevOps\BehatSteps\Drupal\FieldTrait as DrupalFieldTrait;51use DrevOps\BehatSteps\Drupal\FileTrait;52use DrevOps\BehatSteps\Drupal\MediaTrait;53use DrevOps\BehatSteps\Drupal\MenuTrait;54use DrevOps\BehatSteps\Drupal\MetatagTrait;55use DrevOps\BehatSteps\Drupal\OverrideTrait;56use DrevOps\BehatSteps\Drupal\ParagraphsTrait;57use DrevOps\BehatSteps\Drupal\SearchApiTrait;58use DrevOps\BehatSteps\Drupal\TaxonomyTrait;59use DrevOps\BehatSteps\Drupal\TestmodeTrait;60use DrevOps\BehatSteps\Drupal\UserTrait;61use DrevOps\BehatSteps\Drupal\WatchdogTrait;6263class FeatureContext extends DrupalContext {64 // Include only the traits you need for your tests65 // Generic traits66 use CookieTrait;67 use DateTrait;68 use ElementTrait;69 use FieldTrait;70 use FileDownloadTrait;71 use KeyboardTrait;72 use LinkTrait;73 use PathTrait;74 use ResponseTrait;75 use WaitTrait;7677 // Drupal-specific traits78 use BlockTrait;79 use ContentTrait;80 use EmailTrait;81 use FileTrait;82 use MediaTrait;83 use TaxonomyTrait;84 use UserTrait;8586 // Only add custom methods when drevops/behat-steps doesn't provide the functionality87}88```8990## 🚫 When NOT to Create Custom Steps9192Before creating ANY custom step, verify that drevops/behat-steps doesn't already provide it. Check the full reference below.9394### Common Mistakes to Avoid:95961. **Creating custom user login steps**97 - ❌ Don't create: `Given I log in as an administrator`98 - ✅ Use UserTrait: `Given I am logged in as a user with the "administrator" role`991002. **Creating custom content creation steps**101 - ❌ Don't create: `Given I create an article titled :title`102 - ✅ Use ContentTrait: `Given "article" content:` with a table1031043. **Creating custom field interaction steps**105 - ❌ Don't create: `When I fill in the body field with :text`106 - ✅ Use FieldTrait: `When I fill in "Body" with :text`1071084. **Creating custom email verification steps**109 - ❌ Don't create: `Then I should receive an email`110 - ✅ Use EmailTrait: `Then an email is sent to :address`1111125. **Creating custom element interaction steps**113 - ❌ Don't create: `When I click the submit button`114 - ✅ Use ElementTrait: `When I click on the element ".submit-button"`115116## ✅ When to Create Custom Steps117118Only create custom steps when:1191201. **Business-specific logic** that wouldn't be reusable across projects1212. **Complex multi-step operations** that are repeated frequently in your tests1223. **Integration with third-party services** not covered by drevops/behat-steps1234. **Custom Drupal modules** with unique functionality124125Example of a valid custom step:126127```php128/**129 * @When I process the payment gateway response for order :order_id130 */131public function iProcessPaymentGatewayResponse($order_id) {132 // Custom implementation for your specific payment gateway133}134```135136---137138# Complete DrevOps Behat Steps Reference139140The following is the complete reference from [drevops/behat-steps STEPS.md](https://github.com/drevops/behat-steps/blob/main/STEPS.md):141142## Available steps143144### Index of Generic steps145146| Class | Description |147| --- | --- |148| [CookieTrait](#cookietrait) | Verify and inspect browser cookies. |149| [DateTrait](#datetrait) | Convert relative date expressions into timestamps or formatted dates. |150| [ElementTrait](#elementtrait) | Interact with HTML elements using CSS selectors and DOM attributes. |151| [FieldTrait](#fieldtrait) | Manipulate form fields and verify widget functionality. |152| [FileDownloadTrait](#filedownloadtrait) | Test file download functionality with content verification. |153| [KeyboardTrait](#keyboardtrait) | Simulate keyboard interactions in Drupal browser testing. |154| [LinkTrait](#linktrait) | Verify link elements with attribute and content assertions. |155| [PathTrait](#pathtrait) | Navigate and verify paths with URL validation. |156| [ResponseTrait](#responsetrait) | Verify HTTP responses with status code and header checks. |157| [WaitTrait](#waittrait) | Wait for a period of time or for AJAX to finish. |158159### Index of Drupal steps160161| Class | Description |162| --- | --- |163| [Drupal\BigPipeTrait](#drupalbigpipetrait) | Bypass Drupal BigPipe when rendering pages. |164| [Drupal\BlockTrait](#drupalblocktrait) | Manage Drupal blocks. |165| [Drupal\ContentBlockTrait](#drupalcontentblocktrait) | Manage Drupal content blocks. |166| [Drupal\ContentTrait](#drupalcontenttrait) | Manage Drupal content with workflow and moderation support. |167| [Drupal\DraggableviewsTrait](#drupaldraggableviewstrait) | Order items in the Drupal Draggable Views. |168| [Drupal\EckTrait](#drupalecktrait) | Manage Drupal ECK entities with custom type and bundle creation. |169| [Drupal\EmailTrait](#drupalemailtrait) | Test Drupal email functionality with content verification. |170| [Drupal\MediaTrait](#drupalmediatrait) | Manage Drupal media entities with type-specific field handling. |171| [Drupal\MenuTrait](#drupalmenutrait) | Manage Drupal menu systems and menu link rendering. |172| [Drupal\MetatagTrait](#drupalmetatagtrait) | Assert `<meta>` tags in page markup. |173| [Drupal\OverrideTrait](#drupaloverridetrait) | Override Drupal Extension behaviors. |174| [Drupal\ParagraphsTrait](#drupalparagraphstrait) | Manage Drupal paragraphs entities with structured field data. |175| [Drupal\SearchApiTrait](#drupalsearchapitrait) | Assert Drupal Search API with index and query operations. |176| [Drupal\TaxonomyTrait](#drupaltaxonomytrait) | Manage Drupal taxonomy terms with vocabulary organization. |177| [Drupal\TestmodeTrait](#drupaltestmodetrait) | Configure Drupal Testmode module for controlled testing scenarios. |178| [Drupal\UserTrait](#drupalusertrait) | Manage Drupal users with role and permission assignments. |179| [Drupal\WatchdogTrait](#drupalwatchdogtrait) | Assert Drupal does not trigger PHP errors during scenarios using Watchdog. |180181---182183## CookieTrait184185[Source](vendor/drevops/behat-steps/src/CookieTrait.php)186187> Verify and inspect browser cookies.188> - Assert cookie existence and values with exact or partial matching.189> - Support both WebDriver and BrowserKit drivers for test compatibility.190191### Available steps:192193| Step | Description |194| --- | --- |195| `@Then a cookie with the name :name should exist` | Assert that a cookie exists |196| `@Then a cookie with the name :name and the value :value should exist` | Assert that a cookie exists with a specific value |197| `@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 |198| `@Then a cookie with a name containing :partial_name should exist` | Assert that a cookie with a partial name exists |199| `@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 |200| `@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 |201| `@Then a cookie with the name :name should not exist` | Assert that a cookie does not exist |202| `@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 |203| `@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 |204| `@Then a cookie with a name containing :partial_name should not exist` | Assert that a cookie with a partial name does not exist |205| `@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 |206| `@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 |207208---209210## DateTrait211212[Source](vendor/drevops/behat-steps/src/DateTrait.php)213214> Convert relative date expressions into timestamps or formatted dates.215>216> Supports values and tables.217>218> Possible formats:219> - `[relative:OFFSET]`220> - `[relative:OFFSET#FORMAT]`221>222> with:223> - `OFFSET`: any format that can be parsed by `strtotime()`.224> - `FORMAT`: `date()` format for additional processing.225>226> Examples:227> - `[relative:-1 day]` converted to `1893456000`228> - `[relative:-1 day#Y-m-d]` converted to `2017-11-5`229230---231232## ElementTrait233234[Source](vendor/drevops/behat-steps/src/ElementTrait.php)235236> Interact with HTML elements using CSS selectors and DOM attributes.237> - Assert element visibility, attribute values, and viewport positioning.238> - Execute JavaScript-based interactions with element state verification.239> - Handle confirmation dialogs and scrolling operations.240241### Available steps:242243| Step | Description |244| --- | --- |245| `@Given I accept all confirmation dialogs` | Accept confirmation dialogs appearing on the page |246| `@Given I do not accept any confirmation dialogs` | Do not accept confirmation dialogs appearing on the page |247| `@When I click on the element :selector` | Click on the element defined by the selector |248| `@When I trigger the JS event :event on the element :selector` | Trigger a JavaScript event on an element |249| `@When I scroll to the element :selector` | Scroll to an element with ID |250| `@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 |251| `@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 |252| `@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 |253| `@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 |254| `@Then the element :selector should be at the top of the viewport` | Assert the element should be at the top of the viewport |255| `@Then the element :selector should be displayed` | Assert that element with specified CSS is visible on page |256| `@Then the element :selector should not be displayed` | Assert that element with specified CSS is not visible on page |257| `@Then the element :selector should be displayed within a viewport` | Assert that element with specified CSS is displayed within a viewport |258| `@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 |259| `@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 |260| `@Then the element :selector should not be displayed within a viewport` | Assert that element with specified CSS is visually hidden on page |261262---263264## FieldTrait265266[Source](vendor/drevops/behat-steps/src/FieldTrait.php)267268> Manipulate form fields and verify widget functionality.269> - Set field values for various input types including selects and WYSIWYG.270> - Assert field existence, state, and selected options.271> - Support for specialized widgets like color pickers and rich text editors.272273### Available steps:274275| Step | Description |276| --- | --- |277| `@When I fill in the color field :field with the value :value` | Fill value for color field |278| `@When I fill in the WYSIWYG field :field with the :value` | Set value for WYSIWYG field |279| `@Then the field :name should exist` | Assert that field exists on the page using id, name, label or value |280| `@Then the field :name should not exist` | Assert that field does not exist on the page using id, name, label or value |281| `@Then the field :name should be :enabled_or_disabled` | Assert whether the field has a state |282| `@Then the color field :field should have the value :value` | Assert that a color field has a value |283| `@Then the option :option should exist within the select element :selector` | Assert that a select has an option |284| `@Then the option :option should not exist within the select element :selector` | Assert that a select does not have an option |285| `@Then the option :option should be selected within the select element :selector` | Assert that a select option is selected |286| `@Then the option :option should not be selected within the select element :selector` | Assert that a select option is not selected |287288---289290## FileDownloadTrait291292[Source](vendor/drevops/behat-steps/src/FileDownloadTrait.php)293294> Test file download functionality with content verification.295> - Download files through links and URLs with session cookie handling.296> - Verify file names, content, and extracted archives.297> - Set up download directories and handle file cleanup.298>299> Skip processing with tags: `@behat-steps-skip:fileDownloadBeforeScenario` or300> `@behat-steps-skip:fileDownloadAfterScenario`301>302> Special tags:303> - `@download` - enable download handling304305### Available steps:306307| Step | Description |308| --- | --- |309| `@When I download the file from the URL :url` | Download a file from the specified URL |310| `@When I download the file from the link :link` | Download the file from the specified HTML link |311| `@Then the downloaded file should contain:` | Assert the contents of the download file |312| `@Then the downloaded file name should be :name` | Assert the file name of the downloaded file |313| `@Then the downloaded file name should contain :name` | Assert the downloaded file name contains a specific string |314| `@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 |315| `@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 |316| `@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 |317318---319320## KeyboardTrait321322[Source](vendor/drevops/behat-steps/src/KeyboardTrait.php)323324> Simulate keyboard interactions in Drupal browser testing.325> - Trigger key press events including special keys and key combinations.326> - Assert keyboard navigation and shortcut functionality.327> - Support for targeted key presses on specific page elements.328329### Available steps:330331| Step | Description |332| --- | --- |333| `@When I press the key :key` | Press a single keyboard key |334| `@When I press the key :key on the element :selector` | Press a single keyboard key on the element |335| `@When I press the keys :keys` | Press multiple keyboard keys |336| `@When I press the keys :keys on the element :selector` | Press multiple keyboard keys on the element |337338---339340## LinkTrait341342[Source](vendor/drevops/behat-steps/src/LinkTrait.php)343344> Verify link elements with attribute and content assertions.345> - Find links by title, URL, text content, and class attributes.346> - Test link existence, visibility, and destination accuracy.347> - Assert absolute and relative link paths.348349### Available steps:350351| Step | Description |352| --- | --- |353| `@When I click on the link with the title :title` | Click on the link with a title |354| `@Then the link :link with the href :href should exist` | Assert a link with a href exists |355| `@Then the link :link with the href :href within the element :selector should exist` | Assert link with a href exists within an element |356| `@Then the link :link with the href :href should not exist` | Assert link with a href does not exist |357| `@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 |358| `@Then the link with the title :title should exist` | Assert that a link with a title exists |359| `@Then the link with the title :title should not exist` | Assert that a link with a title does not exist |360| `@Then the link :link should be an absolute link` | Assert that the link with a text is absolute |361| `@Then the link :link should not be an absolute link` | Assert that the link is not an absolute |362363---364365## PathTrait366367[Source](vendor/drevops/behat-steps/src/PathTrait.php)368369> Navigate and verify paths with URL validation.370> - Assert current page location with front page special handling.371> - Configure basic authentication for protected path access.372373### Available steps:374375| Step | Description |376| --- | --- |377| `@Given the basic authentication with the username :username and the password :password` | Set basic authentication for the current session |378| `@Then the path should be :path` | Assert that the current page is a specified path |379| `@Then the path should not be :path` | Assert that the current page is not a specified path |380381---382383## ResponseTrait384385[Source](vendor/drevops/behat-steps/src/ResponseTrait.php)386387> Verify HTTP responses with status code and header checks.388> - Assert HTTP header presence and values.389390### Available steps:391392| Step | Description |393| --- | --- |394| `@Then the response should contain the header :header_name` | Assert that a response contains a header with specified name |395| `@Then the response should not contain the header :header_name` | Assert that a response does not contain a header with a specified name |396| `@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 |397| `@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 |398399---400401## WaitTrait402403[Source](vendor/drevops/behat-steps/src/WaitTrait.php)404405> Wait for a period of time or for AJAX to finish.406407### Available steps:408409| Step | Description |410| --- | --- |411| `@When I wait for :seconds second(s)` | Wait for a specified number of seconds |412| `@When I wait for :seconds second(s) for AJAX to finish` | Wait for the AJAX calls to finish |413414---415416## Drupal\BigPipeTrait417418[Source](vendor/drevops/behat-steps/src/Drupal/BigPipeTrait.php)419420> Bypass Drupal BigPipe when rendering pages.421>422> Activated by adding `@big_pipe` tag to the scenario.423>424> Skip processing with tags: `@behat-steps-skip:bigPipeBeforeScenario` or425> `@behat-steps-skip:bigPipeBeforeStep`.426427---428429## Drupal\BlockTrait430431[Source](vendor/drevops/behat-steps/src/Drupal/BlockTrait.php)432433> Manage Drupal blocks.434> - Create and configure blocks with custom visibility conditions.435> - Place blocks in regions and verify their rendering in the page.436> - Automatically clean up created blocks after scenario completion.437>438> Skip processing with tag: `@behat-steps-skip:blockAfterScenario`439440### Available steps:441442| Step | Description |443| --- | --- |444| `@Given the instance of :admin_label block exists with the following configuration:` | Create a block instance |445| `@Given the block :label has the following configuration:` | Configure an existing block identified by label |446| `@Given the block :label does not exist` | Remove a block specified by label |447| `@Given the block :label is enabled` | Enable a block specified by label |448| `@Given the block :label is disabled` | Disable a block specified by label |449| `@Given the block :label has the following :condition condition configuration:` | Set a visibility condition for a block |450| `@Given the block :label has the :condition condition removed` | Remove a visibility condition from the specified block |451| `@Then the block :label should exist` | Assert that a block with the specified label exists |452| `@Then the block :label should not exist` | Assert that a block with the specified label does not exist |453| `@Then the block :label should exist in the :region region` | Assert that a block with the specified label exists in a region |454| `@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 |455456---457458## Drupal\ContentBlockTrait459460[Source](vendor/drevops/behat-steps/src/Drupal/ContentBlockTrait.php)461462> Manage Drupal content blocks.463> - Define reusable custom block content with structured field data.464> - Create, edit, and verify block_content entities by type and description.465> - Automatically clean up created entities after scenario completion.466>467> Skip processing with tag: `@behat-steps-skip:contentBlockAfterScenario`468469### Available steps:470471| Step | Description |472| --- | --- |473| `@Given the following :type content blocks do not exist:` | Remove content blocks of a specified type with the given descriptions |474| `@Given the following :type content blocks exist:` | Create content blocks of the specified type with the given field values |475| `@When I edit the :type content block with the description :description` | Navigate to the edit page for a specified content block |476| `@Then the content block type :type should exist` | Assert that a content block type exists |477478---479480## Drupal\ContentTrait481482[Source](vendor/drevops/behat-steps/src/Drupal/ContentTrait.php)483484> Manage Drupal content with workflow and moderation support.485> - Create, find, and manipulate nodes with structured field data.486> - Navigate to node pages by title and manage editorial workflows.487> - Support content moderation transitions and scheduled publishing.488489### Available steps:490491| Step | Description |492| --- | --- |493| `@Given the content type :content_type does not exist` | Delete content type |494| `@Given the following :content_type content does not exist:` | Remove content defined by provided properties |495| `@When I visit the :content_type content page with the title :title` | Visit a page of a type with a specified title |496| `@When I visit the :content_type content edit page with the title :title` | Visit an edit page of a type with a specified title |497| `@When I visit the :content_type content delete page with the title :title` | Visit a delete page of a type with a specified title |498| `@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 |499| `@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 |500501---502503## Drupal\DraggableviewsTrait504505[Source](vendor/drevops/behat-steps/src/Drupal/DraggableviewsTrait.php)506507> Order items in the Drupal Draggable Views.508509### Available steps:510511| Step | Description |512| --- | --- |513| `@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 |514515---516517## Drupal\EckTrait518519[Source](vendor/drevops/behat-steps/src/Drupal/EckTrait.php)520521> Manage Drupal ECK entities with custom type and bundle creation.522> - Create structured ECK entities with defined field values.523> - Assert entity type registration and visit entity pages.524> - Automatically clean up created entities after scenario completion.525>526> Skip processing with tag: `@behat-steps-skip:eckAfterScenario`527528### Available steps:529530| Step | Description |531| --- | --- |532| `@Given the following eck :bundle :entity_type entities exist:` | Create eck entities |533| `@Given the following eck :bundle :entity_type entities do not exist:` | Remove custom entities by field |534| `@When I visit eck :bundle :entity_type entity with the title :title` | Navigate to view entity page with specified type and title |535| `@When I edit eck :bundle :entity_type entity with the title :title` | Navigate to edit eck entity page with specified type and title |536537---538539## Drupal\EmailTrait540541[Source](vendor/drevops/behat-steps/src/Drupal/EmailTrait.php)542543> Test Drupal email functionality with content verification.544> - Capture and examine outgoing emails with header and body validation.545> - Follow links and test attachments within email content.546> - Configure mail handler systems for proper test isolation.547>548> Skip processing with tags: `@behat-steps-skip:emailBeforeScenario` or549> `@behat-steps-skip:emailAfterScenario`550>551> Special tags:552> - `@email` - enable email tracking using a default handler553> - `@email:{type}` - enable email tracking using a `{type}` handler554> - `@debug` (enable detailed logs)555556### Available steps:557558| Step | Description |559| --- | --- |560| `@When I clear the test email system queue` | Clear test email system queue |561| `@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 |562| `@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 |563| `@When I enable the test email system` | Enable the test email system |564| `@When I disable the test email system` | Disable test email system |565| `@Then an email is sent to :address` | Assert that an email should be sent to an address |566| `@Then no emails were sent` | Assert that no email messages should be sent |567| `@Then no emails were sent to :address` | Assert that no email messages should be sent to a specified address |568| `@Then an email :field contains:` | Assert that the email message field should contain specified content |569| `@Then an email :field is:` | Assert that the email message field should exactly match specified content |570| `@Then an email :field does not contain:` | Assert that the email message field should not contain specified content |571| `@Then an email to :address is sent` | Assert that an email is sent to a specific address |572| `@Then an email to :address is sent with the subject :subject` | Assert that an email with subject is sent to a specific address |573| `@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 |574| `@Then an email to :address is not sent` | Assert that an email is not sent to a specific address |575| `@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 |576| `@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 |577578### IMPORTANT Email Testing Notes:579580**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.581582```gherkin583@api @email584Scenario: Test email notifications585 Given I am logged in as a user with the "administrator" role586 When I perform an action that triggers email587 Then an email is sent to "user@example.com"588 Then an email "subject" contains:589 """590 Welcome to our site591 """592```593594---595596## Drupal\FileTrait597598[Source](vendor/drevops/behat-steps/src/Drupal/FileTrait.php)599600> Manage Drupal file entities and operations.601> - Handle file uploads, downloads, and management operations.602> - Work with managed and unmanaged files in Drupal.603> - Automatically clean up created file entities after scenario completion.604605Use `FileTrait` and `MediaTrait` from drevops/behat-steps along with built-in Drupal steps for file entities:606607### Available steps:608609| Step | Description |610| --- | --- |611| `@Given the following managed files:` | Create managed files with properties provided in the table (from DrupalContext) |612| `@Given the following managed files do not exist:` | Delete managed files defined by provided properties/fields (from DrupalContext) |613| `@Given the unmanaged file at the URI :uri exists` | Create an unmanaged file (from DrupalContext) |614| `@Given the unmanaged file at the URI :uri exists with :content` | Create an unmanaged file with specified content (from DrupalContext) |615| `@Then an unmanaged file at the URI :uri should exist` | Assert that an unmanaged file with specified URI exists (from DrupalContext) |616| `@Then an unmanaged file at the URI :uri should not exist` | Assert that an unmanaged file with specified URI does not exist (from DrupalContext) |617| `@Then an unmanaged file at the URI :uri should contain :content` | Assert that an unmanaged file exists and has specified content (from DrupalContext) |618| `@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) |619620---621622## Drupal\MediaTrait623624[Source](vendor/drevops/behat-steps/src/Drupal/MediaTrait.php)625626> Manage Drupal media entities with type-specific field handling.627> - Create structured media items with proper file reference handling.628> - Assert media browser functionality and edit media entity fields.629> - Support for multiple media types with field value expansion handling.630> - Automatically clean up created entities after scenario completion.631>632> Skip processing with tag: `@behat-steps-skip:mediaAfterScenario`633634### Available steps:635636| Step | Description |637| --- | --- |638| `@Given :media_type media type does not exist` | Remove media type |639| `@Given the following media :media_type exist:` | Create media of a given type |640| `@Given the following media :media_type do not exist:` | Remove media defined by provided properties |641| `@When I edit the media :media_type with the name :name` | Navigate to edit media with specified type and name |642643---644645## Drupal\MenuTrait646647[Source](vendor/drevops/behat-steps/src/Drupal/MenuTrait.php)648649> Manage Drupal menu systems and menu link rendering.650> - Assert menu items by label, path, and containment hierarchy.651> - Assert menu link visibility and active states in different regions.652> - Create and manage menu hierarchies with parent-child relationships.653> - Automatically clean up created menu links after scenario completion.654>655> Skip processing with tag: `@behat-steps-skip:menuAfterScenario`656657### Available steps:658659| Step | Description |660| --- | --- |661| `@Given the menu :menu_name does not exist` | Remove a single menu by its label if it exists |662| `@Given the following menus:` | Create a menu if one does not exist |663| `@Given the following menu links do not exist in the menu :menu_name:` | Remove menu links by title |664| `@Given the following menu links exist in the menu :menu_name:` | Create menu links |665666---667668## Drupal\MetatagTrait669670[Source](vendor/drevops/behat-steps/src/Drupal/MetatagTrait.php)671672> Assert `<meta>` tags in page markup.673> - Assert presence and content of meta tags with proper attribute handling.674675---676677## Drupal\OverrideTrait678679[Source](vendor/drevops/behat-steps/src/Drupal/OverrideTrait.php)680681> Override Drupal Extension behaviors.682> - Automated entity deletion before creation to avoid duplicates.683> - Improved user authentication handling for anonymous users.684>685> Use with caution: depending on your version of Drupal Extension, PHP and686> Composer, the step definition string (/^Given etc.../) may need to be defined687> for these overrides. If you encounter errors about missing or duplicated688> step definitions, do not include this trait and rather copy the contents of689> this file into your feature context file and copy the step definition strings690> from the Drupal Extension.691692---693694## Drupal\ParagraphsTrait695696[Source](vendor/drevops/behat-steps/src/Drupal/ParagraphsTrait.php)697698> Manage Drupal paragraphs entities with structured field data.699> - Create paragraph items with type-specific field values.700> - Test nested paragraph structures and reference field handling.701> - Attach paragraphs to various entity types with parent-child relationships.702> - Automatically clean up created paragraph items after scenario completion.703>704> Skip processing with tag: `@behat-steps-skip:paragraphsAfterScenario`705706### Available steps:707708| Step | Description |709| --- | --- |710| `@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 |711712---713714## Drupal\SearchApiTrait715716[Source](vendor/drevops/behat-steps/src/Drupal/SearchApiTrait.php)717718> Assert Drupal Search API with index and query operations.719> - Add content to an index720> - Run indexing for a specific number of items.721722### Available steps:723724| Step | Description |725| --- | --- |726| `@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 |727| `@When I run search indexing for :count item(s)` | Run indexing for a specific number of items |728729---730731## Drupal\TaxonomyTrait732733[Source](vendor/drevops/behat-steps/src/Drupal/TaxonomyTrait.php)734735> Manage Drupal taxonomy terms with vocabulary organization.736> - Create term vocabulary structures using field values.737> - Navigate to term pages738> - Verify vocabulary configurations.739740### Available steps:741742| Step | Description |743| --- | --- |744| `@Given the following :vocabulary_machine_name vocabulary terms do not exist:` | Remove terms from a specified vocabulary |745| `@When I visit the :vocabulary_machine_name vocabulary :term_name term page` | Visit specified vocabulary term page |746| `@When I edit the :vocabulary_machine_name vocabulary :term_name term page` | Edit specified vocabulary term page |747| `@Then the vocabulary :machine_name with the name :name should exist` | Assert that a vocabulary with a specific name exists |748| `@Then the vocabulary :machine_name should not exist` | Assert that a vocabulary with a specific name does not exist |749| `@Then the taxonomy term :term_name from the vocabulary :vocabulary_machine_name should exist` | Assert that a taxonomy term exist by name |750| `@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 |751752---753754## Drupal\TestmodeTrait755756[Source](vendor/drevops/behat-steps/src/Drupal/TestmodeTrait.php)757758> Configure Drupal Testmode module for controlled testing scenarios.759>760> Skip processing with tags: `@behat-steps-skip:testmodeBeforeScenario` and761> `@behat-steps-skip:testmodeAfterScenario`.762>763> Special tags:764> - `@testmode` - enable for scenario765766---767768## Drupal\UserTrait769770[Source](vendor/drevops/behat-steps/src/Drupal/UserTrait.php)771772> Manage Drupal users with role and permission assignments.773> - Create user accounts774> - Create user roles775> - Visit user profile pages for editing and deletion.776> - Assert user roles and permissions.777> - Assert user account status (active/inactive).778779### Available steps:780781| Step | Description |782| --- | --- |783| `@Given the following users do not exist:` | Remove users specified in a table |784| `@Given the password for the user :name is :password` | Set a password for a user |785| `@Given the last access time for the user :name is :datetime` | Set last access time for a user |786| `@Given the last login time for the user :name is :datetime` | Set last login time for a user |787| `@Given the role :role_name with the permissions :permissions` | Create a single role with specified permissions |788| `@Given the following roles:` | Create multiple roles from the specified table |789| `@When I visit :name user profile page` | Visit the profile page of the specified user |790| `@When I visit my own user profile page` | Visit the profile page of the current user |791| `@When I visit :name user profile edit page` | Visit the profile edit page of the specified user |792| `@When I visit my own user profile edit page` | Visit the profile edit page of the current user |793| `@When I visit :name user profile delete page` | Visit the profile delete page of the specified user |794| `@When I visit my own user profile delete page` | Visit the profile delete page of the current user |795| `@Then the user :name should have the role(s) :roles assigned` | Assert that a user has roles assigned |796| `@Then the user :name should not have the role(s) :roles assigned` | Assert that a user does not have roles assigned |797| `@Then the user :name should be blocked` | Assert that a user is blocked |798| `@Then the user :name should not be blocked` | Assert that a user is not blocked |799800---801802## Drupal\WatchdogTrait803804[Source](vendor/drevops/behat-steps/src/Drupal/WatchdogTrait.php)805806> Assert Drupal does not trigger PHP errors during scenarios using Watchdog.807> - Check for Watchdog messages after scenario completion.808> - Optionally check only for specific message types.809> - Optionally skip error checking for specific scenarios.810>811> Skip processing with tags: `@behat-steps-skip:watchdogSetScenario` or812> `@behat-steps-skip:watchdogAfterScenario`813>814> Special tags:815> - `@watchdog:{type}` - limit watchdog messages to specific types.816> - `@error` - add to scenarios that are expected to trigger an error.817818---819820## 📝 Best Practices821822### 1. Trait Organization823Always check what traits are available in `vendor/drevops/behat-steps/src/` before creating custom steps:824825```php826class FeatureContext extends DrupalContext {827 // Only include the traits you actually use828 use ContentTrait; // For content management829 use UserTrait; // For user operations830 use EmailTrait; // For email testing831832 // Custom methods only when absolutely necessary833}834```835836### 2. Tag Usage for Special Features837```gherkin838# Enable email testing - REQUIRED for email steps839@email840Scenario: Test email functionality841842# Enable JavaScript testing843@javascript844Scenario: Test AJAX functionality845846# Skip certain trait behaviors847@behat-steps-skip:emailBeforeScenario848Scenario: Test without email initialization849```850851### 3. Error Handling852When tests fail, check:8531. Is the correct trait included in FeatureContext?8542. Are you using the exact step definition from drevops/behat-steps?8553. Do you have the required tags (@api, @email, @javascript)?8564. Is the selector or field name correct?857858### 4. Performance Optimization859- Use traits selectively - only include what you need860- Avoid creating wrapper steps around existing drevops/behat-steps861- Use batch operations where available (e.g., creating multiple users at once)862863## 🔍 Quick Reference Checklist864865Before writing any Behat test:866867- [ ] Check the embedded reference above or [STEPS.md](https://github.com/drevops/behat-steps/blob/main/STEPS.md) for available steps868- [ ] Review trait source code in `vendor/drevops/behat-steps/src/`869- [ ] Include only necessary traits in FeatureContext870- [ ] Use proper tags (@api, @email, @javascript) as required871- [ ] Follow exact step syntax from drevops/behat-steps872- [ ] Only create custom steps for truly unique functionality873- [ ] Test that existing steps work before creating alternatives874- [ ] Document any custom steps thoroughly875876## 📚 Additional Resources877878- [DrevOps Behat Steps Documentation](https://github.com/drevops/behat-steps)879- [DrevOps Behat Steps STEPS.md](https://github.com/drevops/behat-steps/blob/main/STEPS.md)880- [Drupal Extension for Behat](https://www.drupal.org/project/drupalextension)881882Remember: **The drevops/behat-steps package is battle-tested and covers most Drupal testing scenarios. Always use it instead of reinventing the wheel!**883
Also in ivangrynenko/cursorrules
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| ivangrynenko/cursorrules.cursor/rules/accessibility-standards.mdc · 86 | Cursor rules | ui | 44/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/api-standards.mdc · 86 | Cursor rules | api | 44/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/behat-steps.mdc · 86 | Cursor rules | lint-formatstyleperformanceagent-behaviour | 42/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/build-optimization.mdc · 86 | Cursor rules | build | 48/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/confluence-editing-standards.mdc · 86 | Cursor rules | stylearchsecuritydeployment | 60/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/debugging-standards.mdc · 86 | Cursor rules | no sections | 30/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/docker-compose-standards.mdc · 86 | Cursor rules | style | 62/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/drupal-broken-access-control.mdc · 86 | Cursor rules | stylesecurity | 52/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/drupal-cryptographic-failures.mdc · 86 | Cursor rules | security | 48/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/drupal-database-standards.mdc · 86 | Cursor rules | database | 30/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/drupal-injection.mdc · 86 | Cursor rules | securitydo-not | 55/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/drupal-insecure-design.mdc · 86 | Cursor rules | security | 48/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/drupal-integrity-failures.mdc · 86 | Cursor rules | style | 60/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/drupal-logging-failures.mdc · 86 | Cursor rules | security | 48/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/drupal-security-misconfiguration.mdc · 86 | Cursor rules | security | 48/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/drupal-vulnerable-components.mdc · 86 | Cursor rules | stylesecurity | 67/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/git-commit-standards.mdc · 86 | Cursor rules | git | 44/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/github-actions-standards.mdc · 86 | Cursor rules | no sections | 44/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/improve-cursorrules-efficiency.mdc · 86 | Cursor rules | no sections | 34/100 | 3 days ago | |
| ivangrynenko/cursorrules.cursor/rules/javascript-cryptographic-failures.mdc · 86 | Cursor rules | security | 40/100 | 3 days ago |
Diff against .cursor/rules/accessibility-standards.mdc Diff against .cursor/rules/api-standards.mdc Diff against .cursor/rules/behat-steps.mdc Diff against .cursor/rules/build-optimization.mdc Diff against .cursor/rules/confluence-editing-standards.mdc Diff against .cursor/rules/debugging-standards.mdc Diff against .cursor/rules/docker-compose-standards.mdc Diff against .cursor/rules/drupal-broken-access-control.mdc Diff against .cursor/rules/drupal-cryptographic-failures.mdc Diff against .cursor/rules/drupal-database-standards.mdc Diff against .cursor/rules/drupal-injection.mdc Diff against .cursor/rules/drupal-insecure-design.mdc Diff against .cursor/rules/drupal-integrity-failures.mdc Diff against .cursor/rules/drupal-logging-failures.mdc Diff against .cursor/rules/drupal-security-misconfiguration.mdc Diff against .cursor/rules/drupal-vulnerable-components.mdc Diff against .cursor/rules/git-commit-standards.mdc Diff against .cursor/rules/github-actions-standards.mdc Diff against .cursor/rules/improve-cursorrules-efficiency.mdc Diff against .cursor/rules/javascript-cryptographic-failures.mdc
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 3 days ago | |
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 3 days ago | |
| skillrecordings/egghead-next.cursor/rules/project-update-user-rules.mdc · 1.4k | Cursor rules | buildtestlint-formatstyle+7 | 96/100 | 3 days ago | |
| nerds-odd-e/doughnut.cursor/rules/cli.mdc · 49 | Cursor rules | setupbuildteststyle+4 | 96/100 | 3 days ago | |
| skillrecordings/egghead-next.cursor/rules/gh-task-plan.mdc · 1.4k | Cursor rules | teststylearchtypes+2 | 96/100 | 3 days ago | |
| skillrecordings/egghead-next.cursor/rules/project-update-rules.mdc · 1.4k | Cursor rules | buildtestlint-formatstyle+7 | 96/100 | 3 days ago |
