Two files, one repository
ivangrynenko/cursorrules ships 3 formats across 40 indexed files. The question worth asking is whether the second one says anything the first does not.
| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 0 | 30 | 36 | 0% |
| Commands | 0 | 8 | 0 | 0% |
| Section tags | 2 | 7 | 2 | 18% |
What each file covers
Sections
0 shared · 30 only in A · 36 only in B- − CLAUDE.md
- − Project Overview
- − Common Development Tasks
- − Running Tests
- − Run all tests
- − Run individual test scripts
- − Testing the Installer
- − Test installation interactively
- − Test with specific options
- − Test with debug mode
- − Test installation to custom directory
- − Test installation via curl (non-interactive)
- − Linting and Code Quality
- − Architecture and Code Structure
- − Project Organization
- − Rule Categories
- − Key Design Patterns
- − Installation Flow
- − Versioning System
- − Version Management
- − .cursor/UPDATE.md File Purpose
- − Known Issues and Solutions
- − Curl Piping Issues (Fixed in v1.0.6)
- − Testing Coverage Gaps
- − Important Considerations
- − When Adding New Rules
- − When Modifying the Installer
- − Testing Guidelines
- − Security Considerations
- − Contributing
- + Behat Steps - Claude Memory
- + Available steps
- + Index of Generic steps
- + Index of Drupal steps
- + CookieTrait
- + DateTrait
- + ElementTrait
- + FileDownloadTrait
- + KeyboardTrait
- + LinkTrait
- + PathTrait
- + ResponseTrait
- + WaitTrait
- + Drupal\BigPipeTrait
- + Drupal\BlockTrait
- + Drupal\ContentBlockTrait
- + Drupal\ContentTrait
- + Drupal\DraggableviewsTrait
- + Drupal\EckTrait
- + Drupal\EmailTrait
- + Drupal\FieldTrait
- + Drupal\FileTrait
- + Drupal\MediaTrait
- + Drupal\MenuTrait
- + Drupal\MetatagTrait
- + Drupal\OverrideTrait
- + Drupal\ParagraphsTrait
- + Drupal\SearchApiTrait
- + Drupal\TaxonomyTrait
- + Drupal\TestmodeTrait
- + Drupal\UserTrait
- + Drupal\WatchdogTrait
- + Steps Format Guidelines
- + Common Behat Step Patterns
- + Skipping Before Scenario Hooks
- + Code Style Conventions
Commands
0 shared · 8 only in A · 0 only in B- − php install.php
- − php install.php --core
- − php install.php --web-stack
- − php install.php --python
- − php install.php --all
- − php install.php --debug --core
- − php install.php --all --destination=my/custom/path
- − php -l install.php
Section tags
2 shared · 7 only in A · 2 only in B- − test
- − architecture
- − testing-strategy
- − git-pr
- − security
- − deployment
- − do-not
- + lint-format
- + performance
- code-style
- agent-behaviour
Line diff
ivangrynenko/cursorrules · CLAUDE.md
@@ −1 @@
1# CLAUDE.md
2
3This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
5## Project Overview
6
7This is a repository for managing and distributing Cursor AI rules, particularly focused on web development with strong emphasis on PHP/Drupal, frontend frameworks, and security best practices. The project provides an interactive PHP installer that allows developers to selectively install rule sets into their projects.
8
9## Common Development Tasks
10
11### Running Tests
12```bash
13# Run all tests
14cd .tests && ./run-all-tests.sh
15
16# Run individual test scripts
17cd .tests
18./test-copy.sh # Test basic installation functionality
19./test-debug.sh # Test debug mode
20./test-invalid-option.sh # Test invalid option handling
21./test-conflicting-options.sh # Test conflicting options
22./test-missing-files.sh # Test missing file handling
23```
24
25### Testing the Installer
26```bash
27# Test installation interactively
28php install.php
29
30# Test with specific options
31php install.php --core # Install core rules only
32php install.php --web-stack # Install web stack rules (includes core)
33php install.php --python # Install Python rules (includes core)
34php install.php --all # Install all rules
35
36# Test with debug mode
37php install.php --debug --core
38
39# Test installation to custom directory
40php install.php --all --destination=my/custom/path
41
42# Test installation via curl (non-interactive)
43curl -s https://raw.githubusercontent.com/ivangrynenko/cursor-rules/main/install.php | php -- --ws
44cat install.php | php -- --core # Test piped input locally
45```
46
47### Linting and Code Quality
48- PHP syntax validation: `php -l install.php`
49- No specific linting commands configured - consider adding phpcs/phpmd
50
51## Architecture and Code Structure
52
53### Project Organization
54- **install.php**: Main installer script (current version defined by CURSOR_RULES_VERSION constant)
55- **.cursor/rules/**: Contains 56 MDC rule files organized by category
56- **.cursor/UPDATE.md**: Installation receipt file tracking installed version and configuration (created by installer)
57- **.tests/**: Bash test scripts for installer validation
58- **.github/workflows/**: CI/CD pipeline using GitHub Actions for PHP 8.3
59- **AGENTS.md**: Comprehensive guide for using Cursor Rules (created by installer)
60
61### Rule Categories
621. **Core Rules** (7 files): Git standards, testing guidelines, README maintenance
632. **Web Development Rules**:
64 - Frontend: JavaScript, React, Vue, Tailwind, accessibility
65 - Backend: PHP/Drupal standards, database
66 - Security: OWASP Top 10 implementations for Drupal
67 - DevOps: Docker, Lagoon, Vortex configurations
683. **Python Rules** (10 files): Security-focused rules following OWASP standards
69
70### Key Design Patterns
71- **Installer Architecture**:
72 - Stateless design - each execution is independent
73 - Builder pattern for rule set construction
74 - Strategy pattern for interactive vs non-interactive modes
75 - Factory pattern for rule set management
76
77### Installation Flow
781. User executes install.php (directly or via curl)
792. Script detects if running interactively or with parameters
803. Creates .cursor/rules directory structure
814. Downloads and installs selected rule files from GitHub
825. Creates/overwrites .cursor/UPDATE.md file as an installation receipt
836. Creates/updates AGENTS.md documentation (unless --yes flag overwrites)
84
85## Versioning System
86
87### Version Management
88- **Version Constant**: Defined in install.php as `CURSOR_RULES_VERSION`
89- **Version History**: Tracked in GitHub releases and repository documentation
90- **Release Process**:
91 1. Update CURSOR_RULES_VERSION constant in install.php
92 2. Update version history in repository documentation
93 3. Create GitHub release matching the version number
94 4. Tag the release in git
95
96### .cursor/UPDATE.md File Purpose
97The UPDATE.md file serves as an installation receipt that:
98- Records the version of cursor-rules that was installed
99- Documents the installation date and time
100- Lists the number of rule files installed
101- Shows the installation type (core, web-stack, Python, etc.)
102- Records any tag filters that were applied
103- Gets created/overwritten by the installer on each run
104- Helps users identify which version and configuration they have installed
105
106## Known Issues and Solutions
107
108### Curl Piping Issues (Fixed in v1.0.6)
109When piping the installer through curl, several PHP-specific behaviors can cause problems:
110
111**Problem**: Script hangs when using `curl ... | php` commands
112**Root Causes**:
1131. `$_SERVER['PHP_SELF']` becomes "Standard input code" instead of script name when piped
1142. PHP continues waiting for STDIN input even after script completion
1153. Arguments may not parse correctly when using `--` separator with piped input
116
117**Solutions Implemented**:
1181. **Entry Point Detection**: Check for both normal execution and "Standard input code"
119 ```php
120 if (basename(__FILE__) === basename($_SERVER['PHP_SELF'] ?? '') ||
121 ($_SERVER['PHP_SELF'] ?? '') === 'Standard input code')
122 ```
123
1242. **STDIN Cleanup**: Always close STDIN before exit to prevent hanging
125 ```php
126 if (defined('STDIN') && is_resource(STDIN)) {
127 fclose(STDIN);
128 }
129 ```
130
1313. **Argument Parsing**: Handle both with and without `--` separator
132 ```php
133 if (!stream_isatty(STDIN) && $_SERVER['PHP_SELF'] === 'Standard input code') {
134 // Parse arguments from argv when piped
135 }
136 ```
137
138### Testing Coverage Gaps
139**Issue**: Test suite only covered direct PHP execution, not curl piping scenarios
140**Recommendation**: Add tests for:
141- `curl ... | php` execution paths
142- `cat install.php | php` scenarios
143- Argument parsing with and without `--` separator
144- STDIN handling in different contexts
145
146## Important Considerations
147
148### When Adding New Rules
149- Follow MDC format (Markdown with custom rule syntax)
150- Place in appropriate category under .cursor/rules/
151- Update the rule arrays in install.php (core_rules, web_stack_rules, python_rules)
152- Add rule to README.md documentation table
153- Consider rule dependencies (e.g., web stack includes core rules)
154
155### When Modifying the Installer
156- Maintain PHP 8.3+ compatibility
157- Preserve both interactive and non-interactive modes
158- Update CURSOR_RULES_VERSION constant when making changes
159- Ensure all tests pass before committing
160- Test with both local files and GitHub downloads
161
162### Testing Guidelines
163- All tests are bash scripts in .tests/ directory
164- Tests use temporary directories to avoid affecting the actual installation
165- Each test should output clear success/failure messages
166- GitHub Actions runs all tests on push/PR to main branch
167
168## Security Considerations
169- Never commit sensitive information or API keys
170- Rule files should not contain hardcoded credentials
171- Installer validates file permissions and directory creation
172- Downloaded files are fetched over HTTPS from GitHub
173
174## Contributing
175- Follow conventional commits format (fix:, feat:, docs:, etc.)
176- Update relevant documentation when adding features
177- Ensure all tests pass before submitting PR
178- New rules should include clear descriptions and examples
ivangrynenko/cursorrules · .cursor/rules/behat-steps.mdc
@@ +1 @@
1---
2description:
3globs: *.feature,FeatureContext.php,*Context.php
4alwaysApply: false
5---
6# Behat Steps - Claude Memory
7
8## Available steps
9
10### Index of Generic steps
11
12| Class | Description |
13| --- | --- |
14| [CookieTrait](mdc:#cookietrait) | Verify and inspect browser cookies. |
15| [DateTrait](mdc:#datetrait) | Convert relative date expressions into timestamps or formatted dates. |
16| [ElementTrait](mdc:#elementtrait) | Interact with HTML elements using CSS selectors and DOM attributes. |
17| [FileDownloadTrait](mdc:#filedownloadtrait) | Test file download functionality with content verification. |
18| [KeyboardTrait](mdc:#keyboardtrait) | Simulate keyboard interactions in Drupal browser testing. |
19| [LinkTrait](mdc:#linktrait) | Verify link elements with attribute and content assertions. |
20| [PathTrait](mdc:#pathtrait) | Navigate and verify paths with URL validation. |
21| [ResponseTrait](mdc:#responsetrait) | Verify HTTP responses with status code and header checks. |
22| [WaitTrait](mdc:#waittrait) | Wait for a period of time or for AJAX to finish. |
23
24### Index of Drupal steps
25
26| Class | Description |
27| --- | --- |
28| [Drupal\BigPipeTrait](mdc:#drupalbigpipetrait) | Bypass Drupal BigPipe when rendering pages. |
29| [Drupal\BlockTrait](mdc:#drupalblocktrait) | Manage Drupal blocks. |
30| [Drupal\ContentBlockTrait](mdc:#drupalcontentblocktrait) | Manage Drupal content blocks. |
31| [Drupal\ContentTrait](mdc:#drupalcontenttrait) | Manage Drupal content with workflow and moderation support. |
32| [Drupal\DraggableviewsTrait](mdc:#drupaldraggableviewstrait) | Order items in the Drupal Draggable Views. |
33| [Drupal\EckTrait](mdc:#drupalecktrait) | Manage Drupal ECK entities with custom type and bundle creation. |
34| [Drupal\EmailTrait](mdc:#drupalemailtrait) | Test Drupal email functionality with content verification. |
35| [Drupal\FieldTrait](mdc:#drupalfieldtrait) | Manipulate Drupal form fields and verify widget functionality. |
36| [Drupal\FileTrait](mdc:#drupalfiletrait) | Manage Drupal file entities with upload and storage operations. |
37| [Drupal\MediaTrait](mdc:#drupalmediatrait) | Manage Drupal media entities with type-specific field handling. |
38| [Drupal\MenuTrait](mdc:#drupalmenutrait) | Manage Drupal menu systems and menu link rendering. |
39| [Drupal\MetatagTrait](mdc:#drupalmetatagtrait) | Assert `<meta>` tags in page markup. |
40| [Drupal\OverrideTrait](mdc:#drupaloverridetrait) | Override Drupal Extension behaviors. |
41| [Drupal\ParagraphsTrait](mdc:#drupalparagraphstrait) | Manage Drupal paragraphs entities with structured field data. |
42| [Drupal\SearchApiTrait](mdc:#drupalsearchapitrait) | Assert Drupal Search API with index and query operations. |
43| [Drupal\TaxonomyTrait](mdc:#drupaltaxonomytrait) | Manage Drupal taxonomy terms with vocabulary organization. |
44| [Drupal\TestmodeTrait](mdc:#drupaltestmodetrait) | Configure Drupal Testmode module for controlled testing scenarios. |
45| [Drupal\UserTrait](mdc:#drupalusertrait) | Manage Drupal users with role and permission assignments. |
46| [Drupal\WatchdogTrait](mdc:#drupalwatchdogtrait) | Assert Drupal does not trigger PHP errors during scenarios using Watchdog. |
47
48
49---
50
51## CookieTrait
52
53[Source](mdc:src/CookieTrait.php), [Example](mdc:tests/behat/features/cookie.feature)
54
55> Verify and inspect browser cookies.
56> - Assert cookie existence and values with exact or partial matching.
57> - Support both WebDriver and BrowserKit drivers for test compatibility.
58
59
60<details>
61 <summary><code>@Then a cookie with the name :name should exist</code></summary>
62
63<br/>
64Assert that a cookie exists
65<br/><br/>
66
67```gherkin
68Then a cookie with the name "session_id" should exist
69
70```
71
72</details>
73
74<details>
75 <summary><code>@Then a cookie with the name :name and the value :value should exist</code></summary>
76
77<br/>
78Assert that a cookie exists with a specific value
79<br/><br/>
80
81```gherkin
82Then a cookie with the name "language" and the value "en" should exist
83
84```
85
86</details>
87
88<details>
89 <summary><code>@Then a cookie with the name :name and a value containing :partial_value should exist</code></summary>
90
91<br/>
92Assert that a cookie exists with a value containing a partial value
93<br/><br/>
94
95```gherkin
96Then a cookie with the name "preferences" and a value containing "darkmode" should exist
97
98```
99
100</details>
101
102<details>
103 <summary><code>@Then a cookie with a name containing :partial_name should exist</code></summary>
104
105<br/>
106Assert that a cookie with a partial name exists
107<br/><br/>
108
109```gherkin
110Then a cookie with a name containing "session" should exist
111
112```
113
114</details>
115
116<details>
117 <summary><code>@Then a cookie with a name containing :partial_name and the value :value should exist</code></summary>
118
119<br/>
120Assert that a cookie with a partial name and value exists
121<br/><br/>
122
123```gherkin
124Then a cookie with a name containing "user" and the value "admin" should exist
125
126```
127
128</details>
129
130<details>
131 <summary><code>@Then a cookie with a name containing :partial_name and a value containing :partial_value should exist</code></summary>
132
133<br/>
134Assert that a cookie with a partial name and partial value exists
135<br/><br/>
136
137```gherkin
138Then a cookie with a name containing "user" and a value containing "admin" should exist
139
140```
141
142</details>
143
144<details>
145 <summary><code>@Then a cookie with the name :name should not exist</code></summary>
146
147<br/>
148Assert that a cookie does not exist
149<br/><br/>
150
151```gherkin
152Then a cookie with name "old_session" should not exist
153
154```
155
156</details>
157
158<details>
159 <summary><code>@Then a cookie with the name :name and the value :value should not exist</code></summary>
160
161<br/>
162Assert that a cookie with a specific value does not exist
163<br/><br/>
164
165```gherkin
166Then a cookie with the name "language" and the value "fr" should not exist
167
168```
169
170</details>
171
172<details>
173 <summary><code>@Then a cookie with the name :name and a value containing :partial_value should not exist</code></summary>
174
175<br/>
176Assert that a cookie with a value containing a partial value does not exist
177<br/><br/>
178
179```gherkin
180Then a cookie with the name "preferences" and a value containing "lightmode" should not exist
181
182```
183
184</details>
185
186<details>
187 <summary><code>@Then a cookie with a name containing :partial_name should not exist</code></summary>
188
189<br/>
190Assert that a cookie with a partial name does not exist
191<br/><br/>
192
193```gherkin
194Then a cookie with a name containing "old" should not exist
195
196```
197
198</details>
199
200<details>
201 <summary><code>@Then a cookie with a name containing :partial_name and the value :value should not exist</code></summary>
202
203<br/>
204Assert that a cookie with a partial name and value does not exist
205<br/><br/>
206
207```gherkin
208Then a cookie with a name containing "user" and the value "guest" should not exist
209
210```
211
212</details>
213
214<details>
215 <summary><code>@Then a cookie with a name containing :partial_name and a value containing :partial_value should not exist</code></summary>
216
217<br/>
218Assert that a cookie with a partial name and partial value does not exist
219<br/><br/>
220
221```gherkin
222Then a cookie with a name containing "user" and a value containing "guest" should not exist
223
224```
225
226</details>
227
228## DateTrait
229
230[Source](mdc:src/DateTrait.php), [Example](mdc:tests/behat/features/date.feature)
231
232> Convert relative date expressions into timestamps or formatted dates.
233> <br/><br/>
234> Supports values and tables.
235> <br/><br/>
236> Possible formats:
237> - `[relative:OFFSET]`
238> - `[relative:OFFSET#FORMAT]`
239>
240> with:
241> - `OFFSET`: any format that can be parsed by `strtotime()`.
242> - `FORMAT`: `date()` format for additional processing.
243>
244> Examples:
245> - `[relative:-1 day]` converted to `1893456000`
246> - `[relative:-1 day#Y-m-d]` converted to `2017-11-5`
247
248
249## ElementTrait
250
251[Source](mdc:src/ElementTrait.php), [Example](mdc:tests/behat/features/element.feature)
252
253> Interact with HTML elements using CSS selectors and DOM attributes.
254> - Assert element visibility, attribute values, and viewport positioning.
255> - Execute JavaScript-based interactions with element state verification.
256> - Handle confirmation dialogs and scrolling operations.
257
258
259<details>
260 <summary><code>@Given I accept all confirmation dialogs</code></summary>
261
262<br/>
263Accept confirmation dialogs appearing on the page
264<br/><br/>
265
266```gherkin
267Given I accept all confirmation dialogs
268
269```
270
271</details>
272
273<details>
274 <summary><code>@Given I do not accept any confirmation dialogs</code></summary>
275
276<br/>
277Do not accept confirmation dialogs appearing on the page
278<br/><br/>
279
280```gherkin
281Given I do not accept any confirmation dialogs
282
283```
284
285</details>
286
287<details>
288 <summary><code>@When I click on the element :selector</code></summary>
289
290<br/>
291Click on the element defined by the selector
292<br/><br/>
293
294```gherkin
295When I click on the element ".button"
296
297```
298
299</details>
300
301<details>
302 <summary><code>@When I trigger the JS event :event on the element :selector</code></summary>
303
304<br/>
305When I trigger the JS event :event on the element :selector
306<br/><br/>
307
308```gherkin
309When I trigger the JS event "click" on the element "#submit-button"
310
311```
312
313</details>
314
315<details>
316 <summary><code>@When I scroll to the element :selector</code></summary>
317
318<br/>
319Scroll to an element with ID
320<br/><br/>
321
322```gherkin
323When I scroll to the element "#footer"
324
325```
326
327</details>
328
329<details>
330 <summary><code>@Then the element :selector with the attribute :attribute and the value :value should exist</code></summary>
331
332<br/>
333Assert an element with selector and attribute with a value exists
334<br/><br/>
335
336```gherkin
337Then the element "#main-content" with the attribute "class" and the value "content-wrapper" should exist
338
339```
340
341</details>
342
343<details>
344 <summary><code>@Then the element :selector with the attribute :attribute and the value containing :value should exist</code></summary>
345
346<br/>
347Assert an element with selector and attribute containing a value exists
348<br/><br/>
349
350```gherkin
351Then the element "#main-content" with the attribute "class" and the value containing "content" should exist
352
353```
354
355</details>
356
357<details>
358 <summary><code>@Then the element :selector with the attribute :attribute and the value :value should not exist</code></summary>
359
360<br/>
361Assert an element with selector and attribute with a value exists
362<br/><br/>
363
364```gherkin
365Then the element "#main-content" with the attribute "class" and the value "hidden" should not exist
366
367```
368
369</details>
370
371<details>
372 <summary><code>@Then the element :selector with the attribute :attribute and the value containing :value should not exist</code></summary>
373
374<br/>
375Assert an element with selector and attribute containing a value does not exist
376<br/><br/>
377
378```gherkin
379Then the element "#main-content" with the attribute "class" and the value containing "hidden" should not exist
380
381```
382
383</details>
384
385<details>
386 <summary><code>@Then the element :selector should be at the top of the viewport</code></summary>
387
388<br/>
389Assert the element :selector should be at the top of the viewport
390<br/><br/>
391
392```gherkin
393Then the element "#header" should be at the top of the viewport
394
395```
396
397</details>
398
399<details>
400 <summary><code>@Then the element :selector should be displayed</code></summary>
401
402<br/>
403Assert that element with specified CSS is visible on page
404<br/><br/>
405
406```gherkin
407Then the element ".alert-success" should be displayed
408
409```
410
411</details>
412
413<details>
414 <summary><code>@Then the element :selector should not be displayed</code></summary>
415
416<br/>
417Assert that element with specified CSS is not visible on page
418<br/><br/>
419
420```gherkin
421Then the element ".error-message" should not be displayed
422
423```
424
425</details>
426
427<details>
428 <summary><code>@Then the element :selector should be displayed within a viewport</code></summary>
429
430<br/>
431Assert that element with specified CSS is displayed within a viewport
432<br/><br/>
433
434```gherkin
435Then the element ".hero-banner" should be displayed within a viewport
436
437```
438
439</details>
440
441<details>
442 <summary><code>@Then the element :selector should be displayed within a viewport with a top offset of :number pixels</code></summary>
443
444<br/>
445Assert that element with specified CSS is displayed within a viewport with a top offset
446<br/><br/>
447
448```gherkin
449Then the element ".sticky-header" should be displayed within a viewport with a top offset of 50 pixels
450
451```
452
453</details>
454
455<details>
456 <summary><code>@Then the element :selector should not be displayed within a viewport with a top offset of :number pixels</code></summary>
457
458<br/>
459Assert that element with specified CSS is not displayed within a viewport with a top offset
460<br/><br/>
461
462```gherkin
463Then the element ".below-fold-content" should not be displayed within a viewport with a top offset of 0 pixels
464
465```
466
467</details>
468
469<details>
470 <summary><code>@Then the element :selector should not be displayed within a viewport</code></summary>
471
472<br/>
473Assert that element with specified CSS is visually hidden on page
474<br/><br/>
475
476```gherkin
477Then the element ".visually-hidden" should not be displayed within a viewport
478
479```
480
481</details>
482
483## FileDownloadTrait
484
485[Source](mdc:src/FileDownloadTrait.php), [Example](mdc:tests/behat/features/file_download.feature)
486
487> Test file download functionality with content verification.
488> - Download files through links and URLs with session cookie handling.
489> - Verify file names, content, and extracted archives.
490> - Set up download directories and handle file cleanup.
491>
492> Skip processing with tags: `@behat-steps-skip:fileDownloadBeforeScenario` or
493> `@behat-steps-skip:fileDownloadAfterScenario`
494> <br/><br/>
495> Special tags:
496> - `@download` - enable download handling
497
498
499<details>
500 <summary><code>@When I download the file from the URL :url</code></summary>
501
502<br/>
503Download a file from the specified URL
504<br/><br/>
505
506```gherkin
507When I download the file from the URL "/sites/default/files/document.pdf"
508When I download the file from the URL "https://example.com/files/report.xlsx"
509
510```
511
512</details>
513
514<details>
515 <summary><code>@When I download the file from the link :link</code></summary>
516
517<br/>
518Download the file from the specified HTML link
519<br/><br/>
520
521```gherkin
522When I download the file from the link "Download PDF"
523When I download the file from the link "Get Report"
524
525```
526
527</details>
528
529<details>
530 <summary><code>@Then the downloaded file should contain:</code></summary>
531
532<br/>
533Assert the contents of the download file
534<br/><br/>
535
536```gherkin
537Then the downloaded file should contain:
538"""
539Financial Report 2023
540"""
541
542```
543
544</details>
545
546<details>
547 <summary><code>@Then the downloaded file name should be :name</code></summary>
548
549<br/>
550Assert the file name of the downloaded file
551<br/><br/>
552
553```gherkin
554Then the downloaded file name should be "report.pdf"
555
556```
557
558</details>
559
560<details>
561 <summary><code>@Then the downloaded file name should contain :name</code></summary>
562
563<br/>
564Assert the downloaded file name contains a specific string
565<br/><br/>
566
567```gherkin
568Then the downloaded file name should contain "report"
569
570```
571
572</details>
573
574<details>
575 <summary><code>@Then the downloaded file should be a zip archive containing the files named:</code></summary>
576
577<br/>
578Assert the downloaded file should be a zip archive containing specific files
579<br/><br/>
580
581```gherkin
582Then the downloaded file should be a zip archive containing the files named:
583| document.pdf |
584| image.jpg |
585| data.csv |
586
587```
588
589</details>
590
591<details>
592 <summary><code>@Then the downloaded file should be a zip archive containing the files partially named:</code></summary>
593
594<br/>
595Assert the downloaded file should be a zip archive containing files with partial names
596<br/><br/>
597
598```gherkin
599Then the downloaded file should be a zip archive containing the files partially named:
600| report |
601| data |
602| image |
603
604```
605
606</details>
607
608<details>
609 <summary><code>@Then the downloaded file should be a zip archive not containing the files partially named:</code></summary>
610
611<br/>
612Assert the downloaded file is a zip archive not containing files with partial names
613<br/><br/>
614
615```gherkin
616Then the downloaded file should be a zip archive not containing the files partially named:
617| confidential |
618| private |
619| draft |
620
621```
622
623</details>
624
625## KeyboardTrait
626
627[Source](mdc:src/KeyboardTrait.php), [Example](mdc:tests/behat/features/keyboard.feature)
628
629> Simulate keyboard interactions in Drupal browser testing.
630> - Trigger key press events including special keys and key combinations.
631> - Assert keyboard navigation and shortcut functionality.
632> - Support for targeted key presses on specific page elements.
633
634
635<details>
636 <summary><code>@When I press the key :key</code></summary>
637
638<br/>
639Press a single keyboard key
640<br/><br/>
641
642```gherkin
643When I press the key "a"
644When I press the key "tab"
645
646```
647
648</details>
649
650<details>
651 <summary><code>@When I press the key :key on the element :selector</code></summary>
652
653<br/>
654Press a single keyboard key on the element
655<br/><br/>
656
657```gherkin
658When I press the key "a" on the element "#edit-title"
659When I press the key "tab" on the element "#edit-title"
660
661```
662
663</details>
664
665<details>
666 <summary><code>@When I press the keys :keys</code></summary>
667
668<br/>
669Press multiple keyboard keys
670<br/><br/>
671
672```gherkin
673When I press the keys "abc"
674
675```
676
677</details>
678
679<details>
680 <summary><code>@When I press the keys :keys on the element :selector</code></summary>
681
682<br/>
683Press multiple keyboard keys on the element
684<br/><br/>
685
686```gherkin
687When I press the keys "abc" on the element "#edit-title"
688
689```
690
691</details>
692
693## LinkTrait
694
695[Source](mdc:src/LinkTrait.php), [Example](mdc:tests/behat/features/link.feature)
696
697> Verify link elements with attribute and content assertions.
698> - Find links by title, URL, text content, and class attributes.
699> - Test link existence, visibility, and destination accuracy.
700> - Assert absolute and relative link paths.
701
702
703<details>
704 <summary><code>@When I click on the link with the title :title</code></summary>
705
706<br/>
707Click on the link with a title
708<br/><br/>
709
710```gherkin
711When I click on the link with the title "Return to site content"
712
713```
714
715</details>
716
717<details>
718 <summary><code>@Then the link :link with the href :href should exist</code></summary>
719
720<br/>
721Assert a link with a href exists
722<br/><br/>
723
724```gherkin
725Then the link "About us" with the href "/about-us" should exist
726Then the link "About us" with the href "/about*" should exist
727
728```
729
730</details>
731
732<details>
733 <summary><code>@Then the link :link with the href :href within the element :selector should exist</code></summary>
734
735<br/>
736Assert link with a href exists within an element
737<br/><br/>
738
739```gherkin
740Then the link "About us" with the href "/about-us" within the element ".main-nav" should exist
741Then the link "About us" with the href "/about*" within the element ".main-nav" should exist
742
743```
744
745</details>
746
747<details>
748 <summary><code>@Then the link :link with the href :href should not exist</code></summary>
749
750<br/>
751Assert link with a href does not exist
752<br/><br/>
753
754```gherkin
755Then the link "About us" with the href "/about-us" should not exist
756Then the link "About us" with the href "/about*" should not exist
757
758```
759
760</details>
761
762<details>
763 <summary><code>@Then the link :link with the href :href within the element :selector should not exist</code></summary>
764
765<br/>
766Assert link with a href does not exist within an element
767<br/><br/>
768
769```gherkin
770Then the link "About us" with the href "/about-us" within the element ".main-nav" should not exist
771Then the link "About us" with the href "/about*" within the element ".main-nav" should not exist
772
773```
774
775</details>
776
777<details>
778 <summary><code>@Then the link with the title :title should exist</code></summary>
779
780<br/>
781Assert that a link with a title exists
782<br/><br/>
783
784```gherkin
785Then the link with the title "Return to site content" should exist
786
787```
788
789</details>
790
791<details>
792 <summary><code>@Then the link with the title :title should not exist</code></summary>
793
794<br/>
795Assert that a link with a title does not exist
796<br/><br/>
797
798```gherkin
799Then the link with the title "Some non-existing title" should not exist
800
801```
802
803</details>
804
805<details>
806 <summary><code>@Then the link :link should be an absolute link</code></summary>
807
808<br/>
809Assert that the link with a text is absolute
810<br/><br/>
811
812```gherkin
813Then the link "my-link-title" should be an absolute link
814
815```
816
817</details>
818
819<details>
820 <summary><code>@Then the link :link should not be an absolute link</code></summary>
821
822<br/>
823Assert that the link is not an absolute
824<br/><br/>
825
826```gherkin
827Then the link "Return to site content" should not be an absolute link
828
829```
830
831</details>
832
833## PathTrait
834
835[Source](mdc:src/PathTrait.php), [Example](mdc:tests/behat/features/path.feature)
836
837> Navigate and verify paths with URL validation.
838> - Assert current page location with front page special handling.
839> - Configure basic authentication for protected path access.
840
841
842<details>
843 <summary><code>@Given the basic authentication with the username :username and the password :password</code></summary>
844
845<br/>
846Set basic authentication for the current session
847<br/><br/>
848
849```gherkin
850Given the basic authentication with the username "myusername" and the password "mypassword"
851
852```
853
854</details>
855
856<details>
857 <summary><code>@Then the path should be :path</code></summary>
858
859<br/>
860Assert that the current page is a specified path
861<br/><br/>
862
863```gherkin
864Then the path should be "/about-us"
865Then the path should be "<front>"
866
867```
868
869</details>
870
871<details>
872 <summary><code>@Then the path should not be :path</code></summary>
873
874<br/>
875Assert that the current page is not a specified path
876<br/><br/>
877
878```gherkin
879Then the path should not be "/about-us"
880Then the path should not be "<front>"
881
882```
883
884</details>
885
886## ResponseTrait
887
888[Source](mdc:src/ResponseTrait.php), [Example](mdc:tests/behat/features/response.feature)
889
890> Verify HTTP responses with status code and header checks.
891> - Assert HTTP header presence and values.
892
893
894<details>
895 <summary><code>@Then the response should contain the header :header_name</code></summary>
896
897<br/>
898Assert that a response contains a header with specified name
899<br/><br/>
900
901```gherkin
902Then the response should contain the header "Connection"
903
904```
905
906</details>
907
908<details>
909 <summary><code>@Then the response should not contain the header :header_name</code></summary>
910
911<br/>
912Assert that a response does not contain a header with a specified name
913<br/><br/>
914
915```gherkin
916Then the response should not contain the header "Connection"
917
918```
919
920</details>
921
922<details>
923 <summary><code>@Then the response header :header_name should contain the value :header_value</code></summary>
924
925<br/>
926Assert that a response contains a header with a specified name and value
927<br/><br/>
928
929```gherkin
930Then the response header "Connection" should contain the value "Keep-Alive"
931
932```
933
934</details>
935
936<details>
937 <summary><code>@Then the response header :header_name should not contain the value :header_value</code></summary>
938
939<br/>
940Assert a response does not contain a header with a specified name and value
941<br/><br/>
942
943```gherkin
944Then the response header "Connection" should not contain the value "Keep-Alive"
945
946```
947
948</details>
949
950## WaitTrait
951
952[Source](mdc:src/WaitTrait.php), [Example](mdc:tests/behat/features/wait.feature)
953
954> Wait for a period of time or for AJAX to finish.
955
956
957<details>
958 <summary><code>@When I wait for :seconds second(s)</code></summary>
959
960<br/>
961Wait for a specified number of seconds
962<br/><br/>
963
964```gherkin
965When I wait for 5 seconds
966When I wait for 1 second
967
968```
969
970</details>
971
972<details>
973 <summary><code>@When I wait for :seconds second(s) for AJAX to finish</code></summary>
974
975<br/>
976Wait for the AJAX calls to finish
977<br/><br/>
978
979```gherkin
980When I wait for 5 seconds for AJAX to finish
981When I wait for 1 second for AJAX to finish
982
983```
984
985</details>
986
987
988
989## Drupal\BigPipeTrait
990
991[Source](mdc:src/Drupal/BigPipeTrait.php), [Example](mdc:tests/behat/features/drupal_big_pipe.feature)
992
993> Bypass Drupal BigPipe when rendering pages.
994> <br/><br/>
995> Activated by adding `@big_pipe` tag to the scenario.
996> <br/><br/>
997> Skip processing with tags: `@behat-steps-skip:bigPipeBeforeScenario` or
998> `@behat-steps-skip:bigPipeBeforeStep`.
999
1000
1001## Drupal\BlockTrait
1002
1003[Source](mdc:src/Drupal/BlockTrait.php), [Example](mdc:tests/behat/features/drupal_block.feature)
1004
1005> Manage Drupal blocks.
1006> - Create and configure blocks with custom visibility conditions.
1007> - Place blocks in regions and verify their rendering in the page.
1008> - Automatically clean up created blocks after scenario completion.
1009>
1010> Skip processing with tag: `@behat-steps-skip:blockAfterScenario`
1011
1012
1013<details>
1014 <summary><code>@Given the instance of :admin_label block exists with the following configuration:</code></summary>
1015
1016<br/>
1017Create a block instance
1018<br/><br/>
1019
1020```gherkin
1021Given the instance of "My block" block exists with the following configuration:
1022 | label | My block |
1023 | label_display | 1 |
1024 | region | content |
1025 | status | 1 |
1026
1027```
1028
1029</details>
1030
1031<details>
1032 <summary><code>@Given the block :label has the following configuration:</code></summary>
1033
1034<br/>
1035Configure an existing block identified by label
1036<br/><br/>
1037
1038```gherkin
1039Given the block "My block" has the following configuration:
1040| label_display | 1 |
1041| region | content |
1042| status | 1 |
1043
1044```
1045
1046</details>
1047
1048<details>
1049 <summary><code>@Given the block :label does not exist</code></summary>
1050
1051<br/>
1052Remove a block specified by label
1053<br/><br/>
1054
1055```gherkin
1056Given the block "My block" does not exist
1057
1058```
1059
1060</details>
1061
1062<details>
1063 <summary><code>@Given the block :label is enabled</code></summary>
1064
1065<br/>
1066Enable a block specified by label
1067<br/><br/>
1068
1069```gherkin
1070Given the block "My block" is enabled
1071
1072```
1073
1074</details>
1075
1076<details>
1077 <summary><code>@Given the block :label is disabled</code></summary>
1078
1079<br/>
1080Disable a block specified by label
1081<br/><br/>
1082
1083```gherkin
1084Given the block "My block" is disabled
1085
1086```
1087
1088</details>
1089
1090<details>
1091 <summary><code>@Given the block :label has the following :condition condition configuration:</code></summary>
1092
1093<br/>
1094Set a visibility condition for a block
1095<br/><br/>
1096
1097```gherkin
1098Given the block "My block" has the following "request_path" condition configuration:
1099| pages | /node/1\r\n/about |
1100| negate | 0 |
1101
1102```
1103
1104</details>
1105
1106<details>
1107 <summary><code>@Given the block :label has the :condition condition removed</code></summary>
1108
1109<br/>
1110Remove a visibility condition from the specified block
1111<br/><br/>
1112
1113```gherkin
1114Given the block "My block" has the "request_path" condition removed
1115
1116```
1117
1118</details>
1119
1120<details>
1121 <summary><code>@Then the block :label should exist</code></summary>
1122
1123<br/>
1124Assert that a block with the specified label exists
1125<br/><br/>
1126
1127```gherkin
1128Then the block "My block" should exist
1129
1130```
1131
1132</details>
1133
1134<details>
1135 <summary><code>@Then the block :label should not exist</code></summary>
1136
1137<br/>
1138Assert that a block with the specified label does not exist
1139<br/><br/>
1140
1141```gherkin
1142Then the block "My block" should not exist
1143
1144```
1145
1146</details>
1147
1148<details>
1149 <summary><code>@Then the block :label should exist in the :region region</code></summary>
1150
1151<br/>
1152Assert that a block with the specified label exists in a region
1153<br/><br/>
1154
1155```gherkin
1156Then the block "My block" should exist in the "content" region
1157
1158```
1159
1160</details>
1161
1162<details>
1163 <summary><code>@Then the block :label should not exist in the :region region</code></summary>
1164
1165<br/>
1166Assert that a block with the specified label does not exist in a region
1167<br/><br/>
1168
1169```gherkin
1170Then the block "My block" should not exist in the "content" region
1171
1172```
1173
1174</details>
1175
1176## Drupal\ContentBlockTrait
1177
1178[Source](mdc:src/Drupal/ContentBlockTrait.php), [Example](mdc:tests/behat/features/drupal_content_block.feature)
1179
1180> Manage Drupal content blocks.
1181> - Define reusable custom block content with structured field data.
1182> - Create, edit, and verify block_content entities by type and description.
1183> - Automatically clean up created entities after scenario completion.
1184>
1185> Skip processing with tag: `@behat-steps-skip:contentBlockAfterScenario`
1186
1187
1188<details>
1189 <summary><code>@Given the following :type content blocks do not exist:</code></summary>
1190
1191<br/>
1192Remove content blocks of a specified type with the given descriptions
1193<br/><br/>
1194
1195```gherkin
1196Given the following "basic" content blocks do not exist:
1197| [TEST] Footer Block |
1198| [TEST] Contact Form |
1199
1200```
1201
1202</details>
1203
1204<details>
1205 <summary><code>@Given the following :type content blocks exist:</code></summary>
1206
1207<br/>
1208Create content blocks of the specified type with the given field values
1209<br/><br/>
1210
1211```gherkin
1212Given the following "basic" content blocks exist:
1213| info | status | body | created |
1214| [TEST] Footer Contact | 1 | Call us at 555-1234 | 2023-01-17 8:00am |
1215| [TEST] Copyright | 1 | © 2023 Example Company | 2023-01-18 9:00am |
1216
1217```
1218
1219</details>
1220
1221<details>
1222 <summary><code>@When I edit the :type content block with the description :description</code></summary>
1223
1224<br/>
1225Navigate to the edit page for a specified content block
1226<br/><br/>
1227
1228```gherkin
1229When I edit the "basic" content block with the description "[TEST] Footer Block"
1230
1231```
1232
1233</details>
1234
1235<details>
1236 <summary><code>@Then the content block type :type should exist</code></summary>
1237
1238<br/>
1239Assert that a content block type exists
1240<br/><br/>
1241
1242```gherkin
1243Then the content block type "Search" should exist
1244
1245```
1246
1247</details>
1248
1249## Drupal\ContentTrait
1250
1251[Source](mdc:src/Drupal/ContentTrait.php), [Example](mdc:tests/behat/features/drupal_content.feature)
1252
1253> Manage Drupal content with workflow and moderation support.
1254> - Create, find, and manipulate nodes with structured field data.
1255> - Navigate to node pages by title and manage editorial workflows.
1256> - Support content moderation transitions and scheduled publishing.
1257
1258
1259<details>
1260 <summary><code>@Given the content type :content_type does not exist</code></summary>
1261
1262<br/>
1263Delete content type
1264<br/><br/>
1265
1266```gherkin
1267Given the content type "article" does not exist
1268
1269```
1270
1271</details>
1272
1273<details>
1274 <summary><code>@Given the following :content_type content does not exist:</code></summary>
1275
1276<br/>
1277Remove content defined by provided properties
1278<br/><br/>
1279
1280```gherkin
1281Given the following "article" content does not exist:
1282 | title |
1283 | Test article |
1284 | Another test article |
1285
1286```
1287
1288</details>
1289
1290<details>
1291 <summary><code>@When I visit the :content_type content page with the title :title</code></summary>
1292
1293<br/>
1294Visit a page of a type with a specified title
1295<br/><br/>
1296
1297```gherkin
1298When I visit the "article" content page with the title "Test article"
1299
1300```
1301
1302</details>
1303
1304<details>
1305 <summary><code>@When I visit the :content_type content edit page with the title :title</code></summary>
1306
1307<br/>
1308Visit an edit page of a type with a specified title
1309<br/><br/>
1310
1311```gherkin
1312When I visit the "article" content edit page with the title "Test article"
1313
1314```
1315
1316</details>
1317
1318<details>
1319 <summary><code>@When I visit the :content_type content delete page with the title :title</code></summary>
1320
1321<br/>
1322Visit a delete page of a type with a specified title
1323<br/><br/>
1324
1325```gherkin
1326When I visit the "article" content delete page with the title "Test article"
1327
1328```
1329
1330</details>
1331
1332<details>
1333 <summary><code>@When I visit the :content_type content scheduled transitions page with the title :title</code></summary>
1334
1335<br/>
1336Visit a scheduled transitions page of a type with a specified title
1337<br/><br/>
1338
1339```gherkin
1340When I visit the "article" content scheduled transitions page with the title "Test article"
1341
1342```
1343
1344</details>
1345
1346<details>
1347 <summary><code>@When I change the moderation state of the :content_type content with the title :title to the :new_state state</code></summary>
1348
1349<br/>
1350Change moderation state of a content with the specified title
1351<br/><br/>
1352
1353```gherkin
1354When I change the moderation state of the "article" content with the title "Test article" to the "published" state
1355
1356```
1357
1358</details>
1359
1360## Drupal\DraggableviewsTrait
1361
1362[Source](mdc:src/Drupal/DraggableviewsTrait.php), [Example](mdc:tests/behat/features/drupal_draggableviews.feature)
1363
1364> Order items in the Drupal Draggable Views.
1365
1366
1367<details>
1368 <summary><code>@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:</code></summary>
1369
1370<br/>
1371Save order of the Draggable Order items
1372<br/><br/>
1373
1374```gherkin
1375When I save the draggable views items of the view "draggableviews_demo" and the display "page_1" for the "article" content in the following order:
1376 | First Article |
1377 | Second Article |
1378 | Third Article |
1379
1380```
1381
1382</details>
1383
1384## Drupal\EckTrait
1385
1386[Source](mdc:src/Drupal/EckTrait.php), [Example](mdc:tests/behat/features/drupal_eck.feature)
1387
1388> Manage Drupal ECK entities with custom type and bundle creation.
1389> - Create structured ECK entities with defined field values.
1390> - Assert entity type registration and visit entity pages.
1391> - Automatically clean up created entities after scenario completion.
1392>
1393> Skip processing with tag: `@behat-steps-skip:eckAfterScenario`
1394
1395
1396<details>
1397 <summary><code>@Given the following eck :bundle :entity_type entities exist:</code></summary>
1398
1399<br/>
1400Create eck entities
1401<br/><br/>
1402
1403```gherkin
1404Given the following eck "contact" "contact_type" entities exist:
1405| title | field_marine_animal | field_fish_type | ... |
1406| Snook | Fish | Marine fish | 10 |
1407| ... | ... | ... | ... |
1408
1409```
1410
1411</details>
1412
1413<details>
1414 <summary><code>@Given the following eck :bundle :entity_type entities do not exist:</code></summary>
1415
1416<br/>
1417Remove custom entities by field
1418<br/><br/>
1419
1420```gherkin
1421Given the following eck "contact" "contact_type" entities do not exist:
1422| field | value |
1423| field_a | Entity label |
1424
1425```
1426
1427</details>
1428
1429<details>
1430 <summary><code>@When I visit eck :bundle :entity_type entity with the title :title</code></summary>
1431
1432<br/>
1433Navigate to view entity page with specified type and title
1434<br/><br/>
1435
1436```gherkin
1437When I visit eck "contact" "contact_type" entity with the title "Test contact"
1438
1439```
1440
1441</details>
1442
1443<details>
1444 <summary><code>@When I edit eck :bundle :entity_type entity with the title :title</code></summary>
1445
1446<br/>
1447Navigate to edit eck entity page with specified type and title
1448<br/><br/>
1449
1450```gherkin
1451When I edit eck "contact" "contact_type" entity with the title "Test contact"
1452
1453```
1454
1455</details>
1456
1457## Drupal\EmailTrait
1458
1459[Source](mdc:src/Drupal/EmailTrait.php), [Example](mdc:tests/behat/features/drupal_email.feature)
1460
1461> Test Drupal email functionality with content verification.
1462> - Capture and examine outgoing emails with header and body validation.
1463> - Follow links and test attachments within email content.
1464> - Configure mail handler systems for proper test isolation.
1465>
1466> Skip processing with tags: `@behat-steps-skip:emailBeforeScenario` or
1467> `@behat-steps-skip:emailAfterScenario`
1468> <br/><br/>
1469> Special tags:
1470> - `@email` - enable email tracking using a default handler
1471> - `@email:{type}` - enable email tracking using a `{type}` handler
1472> - `@debug` (enable detailed logs)
1473
1474
1475<details>
1476 <summary><code>@When I clear the test email system queue</code></summary>
1477
1478<br/>
1479Clear test email system queue
1480<br/><br/>
1481
1482```gherkin
1483When I clear the test email system queue
1484
1485```
1486
1487</details>
1488
1489<details>
1490 <summary><code>@When I follow link number :link_number in the email with the subject :subject</code></summary>
1491
1492<br/>
1493Follow a specific link number in an email with the given subject
1494<br/><br/>
1495
1496```gherkin
1497When I follow link number "1" in the email with the subject "Account Verification"
1498
1499```
1500
1501</details>
1502
1503<details>
1504 <summary><code>@When I follow link number :link_number in the email with the subject containing :subject</code></summary>
1505
1506<br/>
1507Follow a specific link number in an email whose subject contains the given substring
1508<br/><br/>
1509
1510```gherkin
1511When I follow link number "1" in the email with the subject containing "Verification"
1512
1513```
1514
1515</details>
1516
1517<details>
1518 <summary><code>@When I enable the test email system</code></summary>
1519
1520<br/>
1521Enable the test email system
1522<br/><br/>
1523
1524```gherkin
1525When I enable the test email system
1526
1527```
1528
1529</details>
1530
1531<details>
1532 <summary><code>@When I disable the test email system</code></summary>
1533
1534<br/>
1535Disable test email system
1536<br/><br/>
1537
1538```gherkin
1539When I disable the test email system
1540
1541```
1542
1543</details>
1544
1545<details>
1546 <summary><code>@Then an email should be sent to the :address</code></summary>
1547
1548<br/>
1549Assert that an email should be sent to an address
1550<br/><br/>
1551
1552```gherkin
1553Then an email should be sent to the "user@example.com"
1554
1555```
1556
1557</details>
1558
1559<details>
1560 <summary><code>@Then no emails should have been sent</code></summary>
1561
1562<br/>
1563Assert that no email messages should be sent
1564<br/><br/>
1565
1566```gherkin
1567Then no emails should have been sent
1568
1569```
1570
1571</details>
1572
1573<details>
1574 <summary><code>@Then no emails should have been sent to the :address</code></summary>
1575
1576<br/>
1577Assert that no email messages should be sent to a specified address
1578<br/><br/>
1579
1580```gherkin
1581Then no emails should have been sent to the "user@example.com"
1582
1583```
1584
1585</details>
1586
1587<details>
1588 <summary><code>@Then the email header :header should contain:</code></summary>
1589
1590<br/>
1591Assert that the email message header should contain specified content
1592<br/><br/>
1593
1594```gherkin
1595Then the email header "Subject" should contain:
1596"""
1597Account details
1598"""
1599
1600```
1601
1602</details>
1603
1604<details>
1605 <summary><code>@Then the email header :header should exactly be:</code></summary>
1606
1607<br/>
1608Assert that the email message header should be the exact specified content
1609<br/><br/>
1610
1611```gherkin
1612Then the email header "Subject" should exactly be:
1613"""
1614Your Account Details
1615"""
1616
1617```
1618
1619</details>
1620
1621<details>
1622 <summary><code>@Then an email should be sent to the address :address with the content:</code></summary>
1623
1624<br/>
1625Assert that an email should be sent to an address with the exact content in the body
1626<br/><br/>
1627
1628```gherkin
1629Then an email should be sent to the address "user@example.com" with the content:
1630"""
1631Welcome to our site!
1632Click the link below to verify your account.
1633"""
1634
1635```
1636
1637</details>
1638
1639<details>
1640 <summary><code>@Then an email should be sent to the address :address with the content containing:</code></summary>
1641
1642<br/>
1643Assert that an email should be sent to an address with the body containing specific content
1644<br/><br/>
1645
1646```gherkin
1647Then an email should be sent to the address "user@example.com" with the content containing:
1648"""
1649verification link
1650"""
1651
1652```
1653
1654</details>
1655
1656<details>
1657 <summary><code>@Then an email should be sent to the address :address with the content not containing:</code></summary>
1658
1659<br/>
1660Assert that an email should be sent to an address with the body not containing specific content
1661<br/><br/>
1662
1663```gherkin
1664Then an email should be sent to the address "user@example.com" with the content not containing:
1665"""
1666password
1667"""
1668
1669```
1670
1671</details>
1672
1673<details>
1674 <summary><code>@Then an email should not be sent to the address :address with the content:</code></summary>
1675
1676<br/>
1677Assert that an email should not be sent to an address with the exact content in the body
1678<br/><br/>
1679
1680```gherkin
1681Then an email should not be sent to the address "wrong@example.com" with the content:
1682"""
1683Welcome to our site!
1684"""
1685
1686```
1687
1688</details>
1689
1690<details>
1691 <summary><code>@Then an email should not be sent to the address :address with the content containing:</code></summary>
1692
1693<br/>
1694Assert that an email should not be sent to an address with the body containing specific content
1695<br/><br/>
1696
1697```gherkin
1698Then an email should not be sent to the address "wrong@example.com" with the content containing:
1699"""
1700verification link
1701"""
1702
1703```
1704
1705</details>
1706
1707<details>
1708 <summary><code>@Then the email field :field should contain:</code></summary>
1709
1710<br/>
1711Assert that the email field should contain a value
1712<br/><br/>
1713
1714```gherkin
1715Then the email field "body" should contain:
1716"""
1717Please verify your account
1718"""
1719
1720```
1721
1722</details>
1723
1724<details>
1725 <summary><code>@Then the email field :field should be:</code></summary>
1726
1727<br/>
1728Assert that the email field should exactly match a value
1729<br/><br/>
1730
1731```gherkin
1732Then the email field "subject" should be:
1733"""
1734Account Verification
1735"""
1736
1737```
1738
1739</details>
1740
1741<details>
1742 <summary><code>@Then the email field :field should not contain:</code></summary>
1743
1744<br/>
1745Assert that the email field should not contain a value
1746<br/><br/>
1747
1748```gherkin
1749Then the email field "body" should not contain:
1750"""
1751password
1752"""
1753
1754```
1755
1756</details>
1757
1758<details>
1759 <summary><code>@Then the email field :field should not be:</code></summary>
1760
1761<br/>
1762Assert that the email field should not exactly match a value
1763<br/><br/>
1764
1765```gherkin
1766Then the email field "subject" should not be:
1767"""
1768Password Reset
1769"""
1770
1771```
1772
1773</details>
1774
1775<details>
1776 <summary><code>@Then the file :file_name should be attached to the email with the subject :subject</code></summary>
1777
1778<br/>
1779Assert that a file is attached to an email message with specified subject
1780<br/><br/>
1781
1782```gherkin
1783Then the file "document.pdf" should be attached to the email with the subject "Your document"
1784
1785```
1786
1787</details>
1788
1789<details>
1790 <summary><code>@Then the file :file_name should be attached to the email with the subject containing :subject</code></summary>
1791
1792<br/>
1793Assert that a file is attached to an email message with a subject containing the specified substring
1794<br/><br/>
1795
1796```gherkin
1797Then the file "report.xlsx" should be attached to the email with the subject containing "Monthly Report"
1798
1799```
1800
1801</details>
1802
1803## Drupal\FieldTrait
1804
1805[Source](mdc:src/Drupal/FieldTrait.php), [Example](mdc:tests/behat/features/drupal_field.feature)
1806
1807> Manipulate Drupal form fields and verify widget functionality.
1808> - Set field values for various input types including selects and WYSIWYG.
1809> - Assert field existence, state, and selected options.
1810> - Support for specialized widgets like color pickers and rich text editors.
1811
1812
1813<details>
1814 <summary><code>@When I fill in the color field :field with the value :value</code></summary>
1815
1816<br/>
1817Fill value for color field
1818<br/><br/>
1819
1820```gherkin
1821When I fill in the color field "#edit-text-color" with the value "#3366FF"
1822
1823```
1824
1825</details>
1826
1827<details>
1828 <summary><code>@When I fill in the WYSIWYG field :field with the :value</code></summary>
1829
1830<br/>
1831Set value for WYSIWYG field
1832<br/><br/>
1833
1834```gherkin
1835When I fill in the WYSIWYG field "edit-body-0-value" with the "<p>This is a <strong>formatted</strong> paragraph.</p>"
1836
1837```
1838
1839</details>
1840
1841<details>
1842 <summary><code>@Then the field :name should exist</code></summary>
1843
1844<br/>
1845Assert that field exists on the page using id,name,label or value
1846<br/><br/>
1847
1848```gherkin
1849Then the field "Body" should exist
1850Then the field "field_body" should exist
1851
1852```
1853
1854</details>
1855
1856<details>
1857 <summary><code>@Then the field :name should not exist</code></summary>
1858
1859<br/>
1860Assert that field does not exist on the page using id,name,label or value
1861<br/><br/>
1862
1863```gherkin
1864Then the field "Body" should not exist
1865Then the field "field_body" should not exist
1866
1867```
1868
1869</details>
1870
1871<details>
1872 <summary><code>@Then the field :name should be :enabled_or_disabled</code></summary>
1873
1874<br/>
1875Assert whether the field has a state
1876<br/><br/>
1877
1878```gherkin
1879Then the field "Body" should be "disabled"
1880Then the field "field_body" should be "disabled"
1881Then the field "Tags" should be "enabled"
1882Then the field "field_tags" should be "not enabled"
1883
1884```
1885
1886</details>
1887
1888<details>
1889 <summary><code>@Then the color field :field should have the value :value</code></summary>
1890
1891<br/>
1892Assert that a color field has a value
1893<br/><br/>
1894
1895```gherkin
1896Then the color field "#edit-background-color" should have the value "#FF5733"
1897
1898```
1899
1900</details>
1901
1902<details>
1903 <summary><code>@Then the option :option should exist within the select element :selector</code></summary>
1904
1905<br/>
1906Assert that a select has an option
1907<br/><br/>
1908
1909```gherkin
1910Then the option "Administrator" should exist within the select element "edit-roles"
1911
1912```
1913
1914</details>
1915
1916<details>
1917 <summary><code>@Then the option :option should not exist within the select element :selector</code></summary>
1918
1919<br/>
1920Assert that a select does not have an option
1921<br/><br/>
1922
1923```gherkin
1924Then the option "Guest" should not exist within the select element "edit-roles"
1925
1926```
1927
1928</details>
1929
1930<details>
1931 <summary><code>@Then the option :option should be selected within the select element :selector</code></summary>
1932
1933<br/>
1934Assert that a select option is selected
1935<br/><br/>
1936
1937```gherkin
1938Then the option "Administrator" should be selected within the select element "edit-roles"
1939
1940```
1941
1942</details>
1943
1944<details>
1945 <summary><code>@Then the option :option should not be selected within the select element :selector</code></summary>
1946
1947<br/>
1948Assert that a select option is not selected
1949<br/><br/>
1950
1951```gherkin
1952Then the option "Editor" should not be selected within the select element "edit-roles"
1953
1954```
1955
1956</details>
1957
1958## Drupal\FileTrait
1959
1960[Source](mdc:src/Drupal/FileTrait.php), [Example](mdc:tests/behat/features/drupal_file.feature)
1961
1962> Manage Drupal file entities with upload and storage operations.
1963> - Create managed and unmanaged files with specific URIs and content.
1964> - Verify file existence, content, and proper storage locations.
1965> - Set up file system directories and clean up created files.
1966>
1967> Skip processing with tags: `@behat-steps-skip:fileBeforeScenario` or
1968> `@behat-steps-skip:fileAfterScenario`
1969
1970
1971<details>
1972 <summary><code>@Given the following managed files:</code></summary>
1973
1974<br/>
1975Create managed files with properties provided in the table
1976<br/><br/>
1977
1978```gherkin
1979Given the following managed files:
1980| path | uri | status |
1981| document.pdf | public://document.pdf | 1 |
1982| image.jpg | public://images/pic.jpg| 1 |
1983
1984```
1985
1986</details>
1987
1988<details>
1989 <summary><code>@Given the following managed files do not exist:</code></summary>
1990
1991<br/>
1992Delete managed files defined by provided properties/fields
1993<br/><br/>
1994
1995```gherkin
1996Given no managed files:
1997| filename |
1998| myfile.jpg |
1999| otherfile.jpg |
2000 Given no managed files:
2001 | uri |
2002 | public://myfile.jpg |
2003 | public://otherfile.jpg |
2004
2005```
2006
2007</details>
2008
2009<details>
2010 <summary><code>@Given the unmanaged file at the URI :uri exists</code></summary>
2011
2012<br/>
2013Create an unmanaged file
2014<br/><br/>
2015
2016```gherkin
2017Given the unmanaged file at the URI "public://sample.txt" exists
2018
2019```
2020
2021</details>
2022
2023<details>
2024 <summary><code>@Given the unmanaged file at the URI :uri exists with :content</code></summary>
2025
2026<br/>
2027Create an unmanaged file with specified content
2028<br/><br/>
2029
2030```gherkin
2031Given the unmanaged file at the URI "public://data.txt" exists with "Sample content"
2032
2033```
2034
2035</details>
2036
2037<details>
2038 <summary><code>@Then an unmanaged file at the URI :uri should exist</code></summary>
2039
2040<br/>
2041Assert that an unmanaged file with specified URI exists
2042<br/><br/>
2043
2044```gherkin
2045Then an unmanaged file at the URI "public://sample.txt" should exist
2046
2047```
2048
2049</details>
2050
2051<details>
2052 <summary><code>@Then an unmanaged file at the URI :uri should not exist</code></summary>
2053
2054<br/>
2055Assert that an unmanaged file with specified URI does not exist
2056<br/><br/>
2057
2058```gherkin
2059Then an unmanaged file at the URI "public://temp.txt" should not exist
2060
2061```
2062
2063</details>
2064
2065<details>
2066 <summary><code>@Then an unmanaged file at the URI :uri should contain :content</code></summary>
2067
2068<br/>
2069Assert that an unmanaged file exists and has specified content
2070<br/><br/>
2071
2072```gherkin
2073Then an unmanaged file at the URI "public://config.txt" should contain "debug=true"
2074
2075```
2076
2077</details>
2078
2079<details>
2080 <summary><code>@Then an unmanaged file at the URI :uri should not contain :content</code></summary>
2081
2082<br/>
2083Assert that an unmanaged file exists and does not have specified content
2084<br/><br/>
2085
2086```gherkin
2087Then an unmanaged file at the URI "public://config.txt" should not contain "debug=false"
2088
2089```
2090
2091</details>
2092
2093## Drupal\MediaTrait
2094
2095[Source](mdc:src/Drupal/MediaTrait.php), [Example](mdc:tests/behat/features/drupal_media.feature)
2096
2097> Manage Drupal media entities with type-specific field handling.
2098> - Create structured media items with proper file reference handling.
2099> - Assert media browser functionality and edit media entity fields.
2100> - Support for multiple media types with field value expansion handling.
2101> - Automatically clean up created entities after scenario completion.
2102>
2103> Skip processing with tag: `@behat-steps-skip:mediaAfterScenario`
2104
2105
2106<details>
2107 <summary><code>@Given :media_type media type does not exist</code></summary>
2108
2109<br/>
2110Remove media type
2111<br/><br/>
2112
2113```gherkin
2114Given "video" media type does not exist
2115
2116```
2117
2118</details>
2119
2120<details>
2121 <summary><code>@Given the following media :media_type exist:</code></summary>
2122
2123<br/>
2124Create media of a given type
2125<br/><br/>
2126
2127```gherkin
2128Given "video" media:
2129| name | field1 | field2 | field3 |
2130| My media | file.jpg | value | value |
2131| ... | ... | ... | ... |
2132
2133```
2134
2135</details>
2136
2137<details>
2138 <summary><code>@Given the following media :media_type do not exist:</code></summary>
2139
2140<br/>
2141Remove media defined by provided properties
2142<br/><br/>
2143
2144```gherkin
2145Given the following media "image" do not exist:
2146| name |
2147| Media item |
2148| Another media item |
2149
2150```
2151
2152</details>
2153
2154<details>
2155 <summary><code>@When I edit the media :media_type with the name :name</code></summary>
2156
2157<br/>
2158Navigate to edit media with specified type and name
2159<br/><br/>
2160
2161```gherkin
2162When I edit "document" media "Test document"
2163
2164```
2165
2166</details>
2167
2168## Drupal\MenuTrait
2169
2170[Source](mdc:src/Drupal/MenuTrait.php), [Example](mdc:tests/behat/features/drupal_menu.feature)
2171
2172> Manage Drupal menu systems and menu link rendering.
2173> - Assert menu items by label, path, and containment hierarchy.
2174> - Assert menu link visibility and active states in different regions.
2175> - Create and manage menu hierarchies with parent-child relationships.
2176> - Automatically clean up created menu links after scenario completion.
2177>
2178> Skip processing with tag: `@behat-steps-skip:menuAfterScenario`
2179
2180
2181<details>
2182 <summary><code>@Given the menu :menu_name does not exist</code></summary>
2183
2184<br/>
2185Remove a single menu by its label if it exists
2186<br/><br/>
2187
2188```gherkin
2189Given the menu "Test Menu" does not exist
2190
2191```
2192
2193</details>
2194
2195<details>
2196 <summary><code>@Given the following menus:</code></summary>
2197
2198<br/>
2199Create a menu if one does not exist
2200<br/><br/>
2201
2202```gherkin
2203Given the following menus:
2204| label | description |
2205| Footer Menu | Links displayed in the footer |
2206| Secondary Menu | Secondary navigation menu |
2207
2208```
2209
2210</details>
2211
2212<details>
2213 <summary><code>@Given the following menu links do not exist in the menu :menu_name:</code></summary>
2214
2215<br/>
2216Remove menu links by title
2217<br/><br/>
2218
2219```gherkin
2220Given the following menu links do not exist in the menu "Main navigation":
2221| About Us |
2222| Contact |
2223
2224```
2225
2226</details>
2227
2228<details>
2229 <summary><code>@Given the following menu links exist in the menu :menu_name :</code></summary>
2230
2231<br/>
2232Create menu links
2233<br/><br/>
2234
2235```gherkin
2236Given the following menu links exist in the menu "Main navigation":
2237| title | enabled | uri | parent |
2238| Products | 1 | /products | |
2239| Latest Products | 1 | /products/latest | Products |
2240
2241```
2242
2243</details>
2244
2245## Drupal\MetatagTrait
2246
2247[Source](mdc:src/Drupal/MetatagTrait.php), [Example](mdc:tests/behat/features/drupal_metatag.feature)
2248
2249> Assert `<meta>` tags in page markup.
2250> - Assert presence and content of meta tags with proper attribute handling.
2251
2252
2253## Drupal\OverrideTrait
2254
2255[Source](mdc:src/Drupal/OverrideTrait.php), [Example](mdc:tests/behat/features/drupal_override.feature)
2256
2257> Override Drupal Extension behaviors.
2258> - Automated entity deletion before creation to avoid duplicates.
2259> - Improved user authentication handling for anonymous users.
2260>
2261> Use with caution: depending on your version of Drupal Extension, PHP and
2262> Composer, the step definition string (/^Given etc.../) may need to be defined
2263> for these overrides. If you encounter errors about missing or duplicated
2264> step definitions, do not include this trait and rather copy the contents of
2265> this file into your feature context file and copy the step definition strings
2266> from the Drupal Extension.
2267
2268
2269## Drupal\ParagraphsTrait
2270
2271[Source](mdc:src/Drupal/ParagraphsTrait.php), [Example](mdc:tests/behat/features/drupal_paragraphs.feature)
2272
2273> Manage Drupal paragraphs entities with structured field data.
2274> - Create paragraph items with type-specific field values.
2275> - Test nested paragraph structures and reference field handling.
2276> - Attach paragraphs to various entity types with parent-child relationships.
2277> - Automatically clean up created paragraph items after scenario completion.
2278>
2279> Skip processing with tag: `@behat-steps-skip:paragraphsAfterScenario`
2280
2281
2282<details>
2283 <summary><code>@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:</code></summary>
2284
2285<br/>
2286Create a paragraph of the given type with fields within an existing entity
2287<br/><br/>
2288
2289```gherkin
2290Given the following fields for the paragraph "text" exist in the field "field_component" within the "landing_page" "node" identified by the field "title" and the value "My landing page":
2291| field_paragraph_title | My paragraph title |
2292| field_paragraph_longtext:value | My paragraph message |
2293| field_paragraph_longtext:format | full_html |
2294| ... | ... |
2295
2296```
2297
2298</details>
2299
2300## Drupal\SearchApiTrait
2301
2302[Source](mdc:src/Drupal/SearchApiTrait.php), [Example](mdc:tests/behat/features/drupal_search_api.feature)
2303
2304> Assert Drupal Search API with index and query operations.
2305> - Add content to an index
2306> - Run indexing for a specific number of items.
2307
2308
2309<details>
2310 <summary><code>@When I add the :content_type content with the title :title to the search index</code></summary>
2311
2312<br/>
2313Index a node of a specific content type with a specific title
2314<br/><br/>
2315
2316```gherkin
2317When I add the "article" content with the title "Test Article" to the search index
2318
2319```
2320
2321</details>
2322
2323<details>
2324 <summary><code>@When I run search indexing for :count item(s)</code></summary>
2325
2326<br/>
2327Run indexing for a specific number of items
2328<br/><br/>
2329
2330```gherkin
2331When I run search indexing for 5 items
2332When I run search indexing for 1 item
2333
2334```
2335
2336</details>
2337
2338## Drupal\TaxonomyTrait
2339
2340[Source](mdc:src/Drupal/TaxonomyTrait.php), [Example](mdc:tests/behat/features/drupal_taxonomy.feature)
2341
2342> Manage Drupal taxonomy terms with vocabulary organization.
2343> - Create term vocabulary structures using field values.
2344> - Navigate to term pages
2345> - Verify vocabulary configurations.
2346
2347
2348<details>
2349 <summary><code>@Given the following :vocabulary_machine_name vocabulary terms do not exist:</code></summary>
2350
2351<br/>
2352Remove terms from a specified vocabulary
2353<br/><br/>
2354
2355```gherkin
2356Given the following "fruits" vocabulary terms do not exist:
2357 | Apple |
2358 | Pear |
2359
2360```
2361
2362</details>
2363
2364<details>
2365 <summary><code>@When I visit the :vocabulary_machine_name vocabulary :term_name term page</code></summary>
2366
2367<br/>
2368Visit specified vocabulary term page
2369<br/><br/>
2370
2371```gherkin
2372When I visit the "fruits" vocabulary "Apple" term page
2373
2374```
2375
2376</details>
2377
2378<details>
2379 <summary><code>@When I edit the :vocabulary_machine_name vocabulary :term_name term page</code></summary>
2380
2381<br/>
2382Edit specified vocabulary term page
2383<br/><br/>
2384
2385```gherkin
2386When I edit the "fruits" vocabulary "Apple" term page
2387
2388```
2389
2390</details>
2391
2392<details>
2393 <summary><code>@Then the vocabulary :machine_name with the name :name should exist</code></summary>
2394
2395<br/>
2396Assert that a vocabulary with a specific name exists
2397<br/><br/>
2398
2399```gherkin
2400Then the vocabulary "topics" with the name "Topics" should exist
2401
2402```
2403
2404</details>
2405
2406<details>
2407 <summary><code>@Then the vocabulary :machine_name should not exist</code></summary>
2408
2409<br/>
2410Assert that a vocabulary with a specific name does not exist
2411<br/><br/>
2412
2413```gherkin
2414Then the vocabulary "topics" should not exist
2415
2416```
2417
2418</details>
2419
2420<details>
2421 <summary><code>@Then the taxonomy term :term_name from the vocabulary :vocabulary_machine_name should exist</code></summary>
2422
2423<br/>
2424Assert that a taxonomy term exist by name
2425<br/><br/>
2426
2427```gherkin
2428Then the taxonomy term "Apple" from the vocabulary "Fruits" should exist
2429
2430```
2431
2432</details>
2433
2434<details>
2435 <summary><code>@Then the taxonomy term :term_name from the vocabulary :vocabulary_machine_name should not exist</code></summary>
2436
2437<br/>
2438Assert that a taxonomy term does not exist by name
2439<br/><br/>
2440
2441```gherkin
2442Then the taxonomy term "Apple" from the vocabulary "Fruits" should not exist
2443
2444```
2445
2446</details>
2447
2448## Drupal\TestmodeTrait
2449
2450[Source](mdc:src/Drupal/TestmodeTrait.php), [Example](mdc:tests/behat/features/drupal_testmode.feature)
2451
2452> Configure Drupal Testmode module for controlled testing scenarios.
2453> <br/><br/>
2454> Skip processing with tags: `@behat-steps-skip:testmodeBeforeScenario` and
2455> `@behat-steps-skip:testmodeAfterScenario`.
2456> <br/><br/>
2457> Special tags:
2458> - `@testmode` - enable for scenario
2459
2460
2461## Drupal\UserTrait
2462
2463[Source](mdc:src/Drupal/UserTrait.php), [Example](mdc:tests/behat/features/drupal_user.feature)
2464
2465> Manage Drupal users with role and permission assignments.
2466> - Create user accounts
2467> - Create user roles
2468> - Visit user profile pages for editing and deletion.
2469> - Assert user roles and permissions.
2470> - Assert user account status (active/inactive).
2471
2472
2473<details>
2474 <summary><code>@Given the following users do not exist:</code></summary>
2475
2476<br/>
2477Remove users specified in a table
2478<br/><br/>
2479
2480```gherkin
2481Given the following users do not exist:
2482 | name |
2483 | John |
2484 | Jane |
2485 Given the following users do not exist:
2486 | mail |
2487 | john@example.com |
2488 | jane@example.com |
2489
2490```
2491
2492</details>
2493
2494<details>
2495 <summary><code>@Given the password for the user :name is :password</code></summary>
2496
2497<br/>
2498Set a password for a user
2499<br/><br/>
2500
2501```gherkin
2502Given the password for the user "John" is "password"
2503
2504```
2505
2506</details>
2507
2508<details>
2509 <summary><code>@Given the last access time for the user :name is :datetime</code></summary>
2510
2511<br/>
2512Set last access time for a user
2513<br/><br/>
2514
2515```gherkin
2516Given the last access time for the user "John" is "Friday, 22 November 2024 13:46:14"
2517Given the last access time for the user "John" is "1732319174"
2518
2519```
2520
2521</details>
2522
2523<details>
2524 <summary><code>@Given the last login time for the user :name is :datetime</code></summary>
2525
2526<br/>
2527Set last login time for a user
2528<br/><br/>
2529
2530```gherkin
2531Given the last login time for the user "John" is "Friday, 22 November 2024 13:46:14"
2532Given the last login time for the user "John" is "1732319174"
2533
2534```
2535
2536</details>
2537
2538<details>
2539 <summary><code>@Given the role :role_name with the permissions :permissions</code></summary>
2540
2541<br/>
2542Create a single role with specified permissions
2543<br/><br/>
2544
2545```gherkin
2546Given the role "Content Manager" with the permissions "access content, create article content, edit any article content"
2547
2548```
2549
2550</details>
2551
2552<details>
2553 <summary><code>@Given the following roles:</code></summary>
2554
2555<br/>
2556Create multiple roles from the specified table
2557<br/><br/>
2558
2559```gherkin
2560Given the following roles:
2561| name | permissions |
2562| Content Editor | access content, create article content |
2563| Content Approver | access content, edit any article content |
2564
2565```
2566
2567</details>
2568
2569<details>
2570 <summary><code>@When I visit :name user profile page</code></summary>
2571
2572<br/>
2573Visit the profile page of the specified user
2574<br/><br/>
2575
2576```gherkin
2577When I visit "John" user profile page
2578
2579```
2580
2581</details>
2582
2583<details>
2584 <summary><code>@When I visit my own user profile page</code></summary>
2585
2586<br/>
2587Visit the profile page of the current user
2588<br/><br/>
2589
2590```gherkin
2591When I visit my own user profile page
2592
2593```
2594
2595</details>
2596
2597<details>
2598 <summary><code>@When I visit :name user profile edit page</code></summary>
2599
2600<br/>
2601Visit the profile edit page of the specified user
2602<br/><br/>
2603
2604```gherkin
2605When I visit "John" user profile edit page
2606
2607```
2608
2609</details>
2610
2611<details>
2612 <summary><code>@When I visit my own user profile edit page</code></summary>
2613
2614<br/>
2615Visit the profile edit page of the current user
2616<br/><br/>
2617
2618```gherkin
2619When I visit my own user profile edit page
2620
2621```
2622
2623</details>
2624
2625<details>
2626 <summary><code>@When I visit :name user profile delete page</code></summary>
2627
2628<br/>
2629Visit the profile delete page of the specified user
2630<br/><br/>
2631
2632```gherkin
2633When I visit "John" user profile delete page
2634
2635```
2636
2637</details>
2638
2639<details>
2640 <summary><code>@When I visit my own user profile delete page</code></summary>
2641
2642<br/>
2643Visit the profile delete page of the current user
2644<br/><br/>
2645
2646```gherkin
2647When I visit my own user profile delete page
2648
2649```
2650
2651</details>
2652
2653<details>
2654 <summary><code>@Then the user :name should have the role(s) :roles assigned</code></summary>
2655
2656<br/>
2657Assert that a user has roles assigned
2658<br/><br/>
2659
2660```gherkin
2661Then the user "John" should have the roles "administrator, editor" assigned
2662
2663```
2664
2665</details>
2666
2667<details>
2668 <summary><code>@Then the user :name should not have the role(s) :roles assigned</code></summary>
2669
2670<br/>
2671Assert that a user does not have roles assigned
2672<br/><br/>
2673
2674```gherkin
2675Then the user "John" should not have the roles "administrator, editor" assigned
2676
2677```
2678
2679</details>
2680
2681<details>
2682 <summary><code>@Then the user :name should be blocked</code></summary>
2683
2684<br/>
2685Assert that a user is blocked
2686<br/><br/>
2687
2688```gherkin
2689Then the user "John" should be blocked
2690
2691```
2692
2693</details>
2694
2695<details>
2696 <summary><code>@Then the user :name should not be blocked</code></summary>
2697
2698<br/>
2699Assert that a user is not blocked
2700<br/><br/>
2701
2702```gherkin
2703Then the user "John" should not be blocked
2704
2705```
2706
2707</details>
2708
2709## Drupal\WatchdogTrait
2710
2711[Source](mdc:src/Drupal/WatchdogTrait.php), [Example](mdc:tests/behat/features/drupal_watchdog.feature)
2712
2713> Assert Drupal does not trigger PHP errors during scenarios using Watchdog.
2714> - Check for Watchdog messages after scenario completion.
2715> - Optionally check only for specific message types.
2716> - Optionally skip error checking for specific scenarios.
2717>
2718> Skip processing with tags: `@behat-steps-skip:watchdogSetScenario` or
2719> `@behat-steps-skip:watchdogAfterScenario`
2720> <br/><br/>
2721> Special tags:
2722> - `@watchdog:{type}` - limit watchdog messages to specific types.
2723> - `@error` - add to scenarios that are expected to trigger an error.
2724
2725## Steps Format Guidelines
2726- **General Guidelines**:
2727 - Use tuple format instead of regular expressions
2728 - Use descriptive placeholder names
2729 - Use `the following` for tabled content
2730 - Use `with` for properties: `Then the link with the title :title should exist`
2731 - Avoid optional words like `(the|a)`
2732 - Omit unnecessary suffixes like `on the page`
2733 - Method names should begin with the trait name: `userAssertHasRoles()`
2734
2735- **Given Steps**:
2736 - Define test prerequisites
2737 - Use words like `exists` or `have`
2738 - Avoid using `should` or `should not`
2739 - Avoid using `Given I`
2740
2741- **When Steps**:
2742 - Describe an action with an action verb
2743 - Use the format `When I <verb>`
2744
2745- **Then Steps**:
2746 - Specify assertions and expectations
2747 - Use `should` and `should not` for assertions
2748 - Start with the entity being asserted
2749 - Avoid using `Then I`
2750 - Methods should include the `Assert` prefix
2751
2752## Common Behat Step Patterns
2753- Block assertions:
2754 - `I should see the block with label "..."`
2755 - `I should see the block with label "..." in the region "..."`
2756
2757- Content block operations:
2758 - `the content block type "..." should exist`
2759 - `the following "..." content blocks exist:`
2760 - `I edit the "..." content block with the description "..."`
2761
2762- Email testing:
2763 - `I enable the test email system`
2764 - `I clear the test email system queue`
2765 - `an email should be sent to the "..."`
2766
2767## Skipping Before Scenario Hooks
2768Some traits provide `beforeScenario` hook implementations that can be disabled by adding `behat-steps-skip:METHOD_NAME` tag to your test.
2769
2770Example: To skip `beforeScenario` hook from `ElementTrait`, add `@behat-steps-skip:ElementTrait` tag to the feature.
2771
2772## Code Style Conventions
2773- Code is written using Drupal coding standards
2774- Local variables and method arguments: `snake_case`
2775- Method names and class properties: `camelCase`
2776
@@ −1 +1 @@
1−# CLAUDE.md
1+---
2+description:
3+globs: *.feature,FeatureContext.php,*Context.php
4+alwaysApply: false
5+---
6+# Behat Steps - Claude Memory
27
3−This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
8+## Available steps
49
5−## Project Overview
10+### Index of Generic steps
611
7−This is a repository for managing and distributing Cursor AI rules, particularly focused on web development with strong emphasis on PHP/Drupal, frontend frameworks, and security best practices. The project provides an interactive PHP installer that allows developers to selectively install rule sets into their projects.
12+| Class | Description |
13+| --- | --- |
14+| [CookieTrait](mdc:#cookietrait) | Verify and inspect browser cookies. |
15+| [DateTrait](mdc:#datetrait) | Convert relative date expressions into timestamps or formatted dates. |
16+| [ElementTrait](mdc:#elementtrait) | Interact with HTML elements using CSS selectors and DOM attributes. |
17+| [FileDownloadTrait](mdc:#filedownloadtrait) | Test file download functionality with content verification. |
18+| [KeyboardTrait](mdc:#keyboardtrait) | Simulate keyboard interactions in Drupal browser testing. |
19+| [LinkTrait](mdc:#linktrait) | Verify link elements with attribute and content assertions. |
20+| [PathTrait](mdc:#pathtrait) | Navigate and verify paths with URL validation. |
21+| [ResponseTrait](mdc:#responsetrait) | Verify HTTP responses with status code and header checks. |
22+| [WaitTrait](mdc:#waittrait) | Wait for a period of time or for AJAX to finish. |
823
9−## Common Development Tasks
24+### Index of Drupal steps
1025
11−### Running Tests
12−```bash
13−# Run all tests
14−cd .tests && ./run-all-tests.sh
26+| Class | Description |
27+| --- | --- |
28+| [Drupal\BigPipeTrait](mdc:#drupalbigpipetrait) | Bypass Drupal BigPipe when rendering pages. |
29+| [Drupal\BlockTrait](mdc:#drupalblocktrait) | Manage Drupal blocks. |
30+| [Drupal\ContentBlockTrait](mdc:#drupalcontentblocktrait) | Manage Drupal content blocks. |
31+| [Drupal\ContentTrait](mdc:#drupalcontenttrait) | Manage Drupal content with workflow and moderation support. |
32+| [Drupal\DraggableviewsTrait](mdc:#drupaldraggableviewstrait) | Order items in the Drupal Draggable Views. |
33+| [Drupal\EckTrait](mdc:#drupalecktrait) | Manage Drupal ECK entities with custom type and bundle creation. |
34+| [Drupal\EmailTrait](mdc:#drupalemailtrait) | Test Drupal email functionality with content verification. |
35+| [Drupal\FieldTrait](mdc:#drupalfieldtrait) | Manipulate Drupal form fields and verify widget functionality. |
36+| [Drupal\FileTrait](mdc:#drupalfiletrait) | Manage Drupal file entities with upload and storage operations. |
37+| [Drupal\MediaTrait](mdc:#drupalmediatrait) | Manage Drupal media entities with type-specific field handling. |
38+| [Drupal\MenuTrait](mdc:#drupalmenutrait) | Manage Drupal menu systems and menu link rendering. |
39+| [Drupal\MetatagTrait](mdc:#drupalmetatagtrait) | Assert `<meta>` tags in page markup. |
40+| [Drupal\OverrideTrait](mdc:#drupaloverridetrait) | Override Drupal Extension behaviors. |
41+| [Drupal\ParagraphsTrait](mdc:#drupalparagraphstrait) | Manage Drupal paragraphs entities with structured field data. |
42+| [Drupal\SearchApiTrait](mdc:#drupalsearchapitrait) | Assert Drupal Search API with index and query operations. |
43+| [Drupal\TaxonomyTrait](mdc:#drupaltaxonomytrait) | Manage Drupal taxonomy terms with vocabulary organization. |
44+| [Drupal\TestmodeTrait](mdc:#drupaltestmodetrait) | Configure Drupal Testmode module for controlled testing scenarios. |
45+| [Drupal\UserTrait](mdc:#drupalusertrait) | Manage Drupal users with role and permission assignments. |
46+| [Drupal\WatchdogTrait](mdc:#drupalwatchdogtrait) | Assert Drupal does not trigger PHP errors during scenarios using Watchdog. |
1547
16−# Run individual test scripts
17−cd .tests
18−./test-copy.sh # Test basic installation functionality
19−./test-debug.sh # Test debug mode
20−./test-invalid-option.sh # Test invalid option handling
21−./test-conflicting-options.sh # Test conflicting options
22−./test-missing-files.sh # Test missing file handling
48+
49+---
50+
51+## CookieTrait
52+
53+[Source](mdc:src/CookieTrait.php), [Example](mdc:tests/behat/features/cookie.feature)
54+
55+> Verify and inspect browser cookies.
56+> - Assert cookie existence and values with exact or partial matching.
57+> - Support both WebDriver and BrowserKit drivers for test compatibility.
58+
59+
60+<details>
61+ <summary><code>@Then a cookie with the name :name should exist</code></summary>
62+
63+<br/>
64+Assert that a cookie exists
65+<br/><br/>
66+
67+```gherkin
68+Then a cookie with the name "session_id" should exist
69+
2370 ```
2471
25−### Testing the Installer
26−```bash
27−# Test installation interactively
28−php install.php
72+</details>
2973
30−# Test with specific options
31−php install.php --core # Install core rules only
32−php install.php --web-stack # Install web stack rules (includes core)
33−php install.php --python # Install Python rules (includes core)
34−php install.php --all # Install all rules
74+<details>
75+ <summary><code>@Then a cookie with the name :name and the value :value should exist</code></summary>
3576
36−# Test with debug mode
37−php install.php --debug --core
77+<br/>
78+Assert that a cookie exists with a specific value
79+<br/><br/>
3880
39−# Test installation to custom directory
40−php install.php --all --destination=my/custom/path
81+```gherkin
82+Then a cookie with the name "language" and the value "en" should exist
4183
42−# Test installation via curl (non-interactive)
43−curl -s https://raw.githubusercontent.com/ivangrynenko/cursor-rules/main/install.php | php -- --ws
44−cat install.php | php -- --core # Test piped input locally
4584 ```
4685
47−### Linting and Code Quality
48−- PHP syntax validation: `php -l install.php`
49−- No specific linting commands configured - consider adding phpcs/phpmd
86+</details>
5087
51−## Architecture and Code Structure
88+<details>
89+ <summary><code>@Then a cookie with the name :name and a value containing :partial_value should exist</code></summary>
5290
53−### Project Organization
54−- **install.php**: Main installer script (current version defined by CURSOR_RULES_VERSION constant)
55−- **.cursor/rules/**: Contains 56 MDC rule files organized by category
56−- **.cursor/UPDATE.md**: Installation receipt file tracking installed version and configuration (created by installer)
57−- **.tests/**: Bash test scripts for installer validation
58−- **.github/workflows/**: CI/CD pipeline using GitHub Actions for PHP 8.3
59−- **AGENTS.md**: Comprehensive guide for using Cursor Rules (created by installer)
91+<br/>
92+Assert that a cookie exists with a value containing a partial value
93+<br/><br/>
6094
61−### Rule Categories
62−1. **Core Rules** (7 files): Git standards, testing guidelines, README maintenance
63−2. **Web Development Rules**:
64− - Frontend: JavaScript, React, Vue, Tailwind, accessibility
65− - Backend: PHP/Drupal standards, database
66− - Security: OWASP Top 10 implementations for Drupal
67− - DevOps: Docker, Lagoon, Vortex configurations
68−3. **Python Rules** (10 files): Security-focused rules following OWASP standards
95+```gherkin
96+Then a cookie with the name "preferences" and a value containing "darkmode" should exist
6997
70−### Key Design Patterns
71−- **Installer Architecture**:
72− - Stateless design - each execution is independent
73− - Builder pattern for rule set construction
74− - Strategy pattern for interactive vs non-interactive modes
75− - Factory pattern for rule set management
98+```
7699
77−### Installation Flow
78−1. User executes install.php (directly or via curl)
79−2. Script detects if running interactively or with parameters
80−3. Creates .cursor/rules directory structure
81−4. Downloads and installs selected rule files from GitHub
82−5. Creates/overwrites .cursor/UPDATE.md file as an installation receipt
83−6. Creates/updates AGENTS.md documentation (unless --yes flag overwrites)
100+</details>
84101
85−## Versioning System
102+<details>
103+ <summary><code>@Then a cookie with a name containing :partial_name should exist</code></summary>
86104
87−### Version Management
88−- **Version Constant**: Defined in install.php as `CURSOR_RULES_VERSION`
89−- **Version History**: Tracked in GitHub releases and repository documentation
90−- **Release Process**:
91− 1. Update CURSOR_RULES_VERSION constant in install.php
92− 2. Update version history in repository documentation
93− 3. Create GitHub release matching the version number
94− 4. Tag the release in git
105+<br/>
106+Assert that a cookie with a partial name exists
107+<br/><br/>
95108
96−### .cursor/UPDATE.md File Purpose
97−The UPDATE.md file serves as an installation receipt that:
98−- Records the version of cursor-rules that was installed
99−- Documents the installation date and time
100−- Lists the number of rule files installed
101−- Shows the installation type (core, web-stack, Python, etc.)
102−- Records any tag filters that were applied
103−- Gets created/overwritten by the installer on each run
104−- Helps users identify which version and configuration they have installed
109+```gherkin
110+Then a cookie with a name containing "session" should exist
105111
106−## Known Issues and Solutions
112+```
107113
108−### Curl Piping Issues (Fixed in v1.0.6)
109−When piping the installer through curl, several PHP-specific behaviors can cause problems:
114+</details>
110115
111−**Problem**: Script hangs when using `curl ... | php` commands
112−**Root Causes**:
113−1. `$_SERVER['PHP_SELF']` becomes "Standard input code" instead of script name when piped
114−2. PHP continues waiting for STDIN input even after script completion
115−3. Arguments may not parse correctly when using `--` separator with piped input
116+<details>
117+ <summary><code>@Then a cookie with a name containing :partial_name and the value :value should exist</code></summary>
116118
117−**Solutions Implemented**:
118−1. **Entry Point Detection**: Check for both normal execution and "Standard input code"
119− ```php
120− if (basename(__FILE__) === basename($_SERVER['PHP_SELF'] ?? '') ||
121− ($_SERVER['PHP_SELF'] ?? '') === 'Standard input code')
122− ```
119+<br/>
120+Assert that a cookie with a partial name and value exists
121+<br/><br/>
123122
124−2. **STDIN Cleanup**: Always close STDIN before exit to prevent hanging
125− ```php
126− if (defined('STDIN') && is_resource(STDIN)) {
127− fclose(STDIN);
128− }
129− ```
123+```gherkin
124+Then a cookie with a name containing "user" and the value "admin" should exist
130125
131−3. **Argument Parsing**: Handle both with and without `--` separator
132− ```php
133− if (!stream_isatty(STDIN) && $_SERVER['PHP_SELF'] === 'Standard input code') {
134− // Parse arguments from argv when piped
135− }
136− ```
126+```
137127
138−### Testing Coverage Gaps
139−**Issue**: Test suite only covered direct PHP execution, not curl piping scenarios
140−**Recommendation**: Add tests for:
141−- `curl ... | php` execution paths
142−- `cat install.php | php` scenarios
143−- Argument parsing with and without `--` separator
144−- STDIN handling in different contexts
128+</details>
145129
146−## Important Considerations
130+<details>
131+ <summary><code>@Then a cookie with a name containing :partial_name and a value containing :partial_value should exist</code></summary>
147132
148−### When Adding New Rules
149−- Follow MDC format (Markdown with custom rule syntax)
150−- Place in appropriate category under .cursor/rules/
151−- Update the rule arrays in install.php (core_rules, web_stack_rules, python_rules)
152−- Add rule to README.md documentation table
153−- Consider rule dependencies (e.g., web stack includes core rules)
133+<br/>
134+Assert that a cookie with a partial name and partial value exists
135+<br/><br/>
154136
155−### When Modifying the Installer
156−- Maintain PHP 8.3+ compatibility
157−- Preserve both interactive and non-interactive modes
158−- Update CURSOR_RULES_VERSION constant when making changes
159−- Ensure all tests pass before committing
160−- Test with both local files and GitHub downloads
137+```gherkin
138+Then a cookie with a name containing "user" and a value containing "admin" should exist
161139
162−### Testing Guidelines
163−- All tests are bash scripts in .tests/ directory
164−- Tests use temporary directories to avoid affecting the actual installation
165−- Each test should output clear success/failure messages
166−- GitHub Actions runs all tests on push/PR to main branch
140+```
167141
168−## Security Considerations
169−- Never commit sensitive information or API keys
170−- Rule files should not contain hardcoded credentials
171−- Installer validates file permissions and directory creation
172−- Downloaded files are fetched over HTTPS from GitHub
142+</details>
173143
174−## Contributing
175−- Follow conventional commits format (fix:, feat:, docs:, etc.)
176−- Update relevant documentation when adding features
177−- Ensure all tests pass before submitting PR
178−- New rules should include clear descriptions and examples
144+<details>
145+ <summary><code>@Then a cookie with the name :name should not exist</code></summary>
146+
147+<br/>
148+Assert that a cookie does not exist
149+<br/><br/>
150+
151+```gherkin
152+Then a cookie with name "old_session" should not exist
153+
154+```
155+
156+</details>
157+
158+<details>
159+ <summary><code>@Then a cookie with the name :name and the value :value should not exist</code></summary>
160+
161+<br/>
162+Assert that a cookie with a specific value does not exist
163+<br/><br/>
164+
165+```gherkin
166+Then a cookie with the name "language" and the value "fr" should not exist
167+
168+```
169+
170+</details>
171+
172+<details>
173+ <summary><code>@Then a cookie with the name :name and a value containing :partial_value should not exist</code></summary>
174+
175+<br/>
176+Assert that a cookie with a value containing a partial value does not exist
177+<br/><br/>
178+
179+```gherkin
180+Then a cookie with the name "preferences" and a value containing "lightmode" should not exist
181+
182+```
183+
184+</details>
185+
186+<details>
187+ <summary><code>@Then a cookie with a name containing :partial_name should not exist</code></summary>
188+
189+<br/>
190+Assert that a cookie with a partial name does not exist
191+<br/><br/>
192+
193+```gherkin
194+Then a cookie with a name containing "old" should not exist
195+
196+```
197+
198+</details>
199+
200+<details>
201+ <summary><code>@Then a cookie with a name containing :partial_name and the value :value should not exist</code></summary>
202+
203+<br/>
204+Assert that a cookie with a partial name and value does not exist
205+<br/><br/>
206+
207+```gherkin
208+Then a cookie with a name containing "user" and the value "guest" should not exist
209+
210+```
211+
212+</details>
213+
214+<details>
215+ <summary><code>@Then a cookie with a name containing :partial_name and a value containing :partial_value should not exist</code></summary>
216+
217+<br/>
218+Assert that a cookie with a partial name and partial value does not exist
219+<br/><br/>
220+
221+```gherkin
222+Then a cookie with a name containing "user" and a value containing "guest" should not exist
223+
224+```
225+
226+</details>
227+
228+## DateTrait
229+
230+[Source](mdc:src/DateTrait.php), [Example](mdc:tests/behat/features/date.feature)
231+
232+> Convert relative date expressions into timestamps or formatted dates.
233+> <br/><br/>
234+> Supports values and tables.
235+> <br/><br/>
236+> Possible formats:
237+> - `[relative:OFFSET]`
238+> - `[relative:OFFSET#FORMAT]`
239+>
240+> with:
241+> - `OFFSET`: any format that can be parsed by `strtotime()`.
242+> - `FORMAT`: `date()` format for additional processing.
243+>
244+> Examples:
245+> - `[relative:-1 day]` converted to `1893456000`
246+> - `[relative:-1 day#Y-m-d]` converted to `2017-11-5`
247+
248+
249+## ElementTrait
250+
251+[Source](mdc:src/ElementTrait.php), [Example](mdc:tests/behat/features/element.feature)
252+
253+> Interact with HTML elements using CSS selectors and DOM attributes.
254+> - Assert element visibility, attribute values, and viewport positioning.
255+> - Execute JavaScript-based interactions with element state verification.
256+> - Handle confirmation dialogs and scrolling operations.
257+
258+
259+<details>
260+ <summary><code>@Given I accept all confirmation dialogs</code></summary>
261+
262+<br/>
263+Accept confirmation dialogs appearing on the page
264+<br/><br/>
265+
266+```gherkin
267+Given I accept all confirmation dialogs
268+
269+```
270+
271+</details>
272+
273+<details>
274+ <summary><code>@Given I do not accept any confirmation dialogs</code></summary>
275+
276+<br/>
277+Do not accept confirmation dialogs appearing on the page
278+<br/><br/>
279+
280+```gherkin
281+Given I do not accept any confirmation dialogs
282+
283+```
284+
285+</details>
286+
287+<details>
288+ <summary><code>@When I click on the element :selector</code></summary>
289+
290+<br/>
291+Click on the element defined by the selector
292+<br/><br/>
293+
294+```gherkin
295+When I click on the element ".button"
296+
297+```
298+
299+</details>
300+
301+<details>
302+ <summary><code>@When I trigger the JS event :event on the element :selector</code></summary>
303+
304+<br/>
305+When I trigger the JS event :event on the element :selector
306+<br/><br/>
307+
308+```gherkin
309+When I trigger the JS event "click" on the element "#submit-button"
310+
311+```
312+
313+</details>
314+
315+<details>
316+ <summary><code>@When I scroll to the element :selector</code></summary>
317+
318+<br/>
319+Scroll to an element with ID
320+<br/><br/>
321+
322+```gherkin
323+When I scroll to the element "#footer"
324+
325+```
326+
327+</details>
328+
329+<details>
330+ <summary><code>@Then the element :selector with the attribute :attribute and the value :value should exist</code></summary>
331+
332+<br/>
333+Assert an element with selector and attribute with a value exists
334+<br/><br/>
335+
336+```gherkin
337+Then the element "#main-content" with the attribute "class" and the value "content-wrapper" should exist
338+
339+```
340+
341+</details>
342+
343+<details>
344+ <summary><code>@Then the element :selector with the attribute :attribute and the value containing :value should exist</code></summary>
345+
346+<br/>
347+Assert an element with selector and attribute containing a value exists
348+<br/><br/>
349+
350+```gherkin
351+Then the element "#main-content" with the attribute "class" and the value containing "content" should exist
352+
353+```
354+
355+</details>
356+
357+<details>
358+ <summary><code>@Then the element :selector with the attribute :attribute and the value :value should not exist</code></summary>
359+
360+<br/>
361+Assert an element with selector and attribute with a value exists
362+<br/><br/>
363+
364+```gherkin
365+Then the element "#main-content" with the attribute "class" and the value "hidden" should not exist
366+
367+```
368+
369+</details>
370+
371+<details>
372+ <summary><code>@Then the element :selector with the attribute :attribute and the value containing :value should not exist</code></summary>
373+
374+<br/>
375+Assert an element with selector and attribute containing a value does not exist
376+<br/><br/>
377+
378+```gherkin
379+Then the element "#main-content" with the attribute "class" and the value containing "hidden" should not exist
380+
381+```
382+
383+</details>
384+
385+<details>
386+ <summary><code>@Then the element :selector should be at the top of the viewport</code></summary>
387+
388+<br/>
389+Assert the element :selector should be at the top of the viewport
390+<br/><br/>
391+
392+```gherkin
393+Then the element "#header" should be at the top of the viewport
394+
395+```
396+
397+</details>
398+
399+<details>
400+ <summary><code>@Then the element :selector should be displayed</code></summary>
401+
402+<br/>
403+Assert that element with specified CSS is visible on page
404+<br/><br/>
405+
406+```gherkin
407+Then the element ".alert-success" should be displayed
408+
409+```
410+
411+</details>
412+
413+<details>
414+ <summary><code>@Then the element :selector should not be displayed</code></summary>
415+
416+<br/>
417+Assert that element with specified CSS is not visible on page
418+<br/><br/>
419+
420+```gherkin
421+Then the element ".error-message" should not be displayed
422+
423+```
424+
425+</details>
426+
427+<details>
428+ <summary><code>@Then the element :selector should be displayed within a viewport</code></summary>
429+
430+<br/>
431+Assert that element with specified CSS is displayed within a viewport
432+<br/><br/>
433+
434+```gherkin
435+Then the element ".hero-banner" should be displayed within a viewport
436+
437+```
438+
439+</details>
440+
441+<details>
442+ <summary><code>@Then the element :selector should be displayed within a viewport with a top offset of :number pixels</code></summary>
443+
444+<br/>
445+Assert that element with specified CSS is displayed within a viewport with a top offset
446+<br/><br/>
447+
448+```gherkin
449+Then the element ".sticky-header" should be displayed within a viewport with a top offset of 50 pixels
450+
451+```
452+
453+</details>
454+
455+<details>
456+ <summary><code>@Then the element :selector should not be displayed within a viewport with a top offset of :number pixels</code></summary>
457+
458+<br/>
459+Assert that element with specified CSS is not displayed within a viewport with a top offset
460+<br/><br/>
461+
462+```gherkin
463+Then the element ".below-fold-content" should not be displayed within a viewport with a top offset of 0 pixels
464+
465+```
466+
467+</details>
468+
469+<details>
470+ <summary><code>@Then the element :selector should not be displayed within a viewport</code></summary>
471+
472+<br/>
473+Assert that element with specified CSS is visually hidden on page
474+<br/><br/>
475+
476+```gherkin
477+Then the element ".visually-hidden" should not be displayed within a viewport
478+
479+```
480+
481+</details>
482+
483+## FileDownloadTrait
484+
485+[Source](mdc:src/FileDownloadTrait.php), [Example](mdc:tests/behat/features/file_download.feature)
486+
487+> Test file download functionality with content verification.
488+> - Download files through links and URLs with session cookie handling.
489+> - Verify file names, content, and extracted archives.
490+> - Set up download directories and handle file cleanup.
491+>
492+> Skip processing with tags: `@behat-steps-skip:fileDownloadBeforeScenario` or
493+> `@behat-steps-skip:fileDownloadAfterScenario`
494+> <br/><br/>
495+> Special tags:
496+> - `@download` - enable download handling
497+
498+
499+<details>
500+ <summary><code>@When I download the file from the URL :url</code></summary>
501+
502+<br/>
503+Download a file from the specified URL
504+<br/><br/>
505+
506+```gherkin
507+When I download the file from the URL "/sites/default/files/document.pdf"
508+When I download the file from the URL "https://example.com/files/report.xlsx"
509+
510+```
511+
512+</details>
513+
514+<details>
515+ <summary><code>@When I download the file from the link :link</code></summary>
516+
517+<br/>
518+Download the file from the specified HTML link
519+<br/><br/>
520+
521+```gherkin
522+When I download the file from the link "Download PDF"
523+When I download the file from the link "Get Report"
524+
525+```
526+
527+</details>
528+
529+<details>
530+ <summary><code>@Then the downloaded file should contain:</code></summary>
531+
532+<br/>
533+Assert the contents of the download file
534+<br/><br/>
535+
536+```gherkin
537+Then the downloaded file should contain:
538+"""
539+Financial Report 2023
540+"""
541+
542+```
543+
544+</details>
545+
546+<details>
547+ <summary><code>@Then the downloaded file name should be :name</code></summary>
548+
549+<br/>
550+Assert the file name of the downloaded file
551+<br/><br/>
552+
553+```gherkin
554+Then the downloaded file name should be "report.pdf"
555+
556+```
557+
558+</details>
559+
560+<details>
561+ <summary><code>@Then the downloaded file name should contain :name</code></summary>
562+
563+<br/>
564+Assert the downloaded file name contains a specific string
565+<br/><br/>
566+
567+```gherkin
568+Then the downloaded file name should contain "report"
569+
570+```
571+
572+</details>
573+
574+<details>
575+ <summary><code>@Then the downloaded file should be a zip archive containing the files named:</code></summary>
576+
577+<br/>
578+Assert the downloaded file should be a zip archive containing specific files
579+<br/><br/>
580+
581+```gherkin
582+Then the downloaded file should be a zip archive containing the files named:
583+| document.pdf |
584+| image.jpg |
585+| data.csv |
586+
587+```
588+
589+</details>
590+
591+<details>
592+ <summary><code>@Then the downloaded file should be a zip archive containing the files partially named:</code></summary>
593+
594+<br/>
595+Assert the downloaded file should be a zip archive containing files with partial names
596+<br/><br/>
597+
598+```gherkin
599+Then the downloaded file should be a zip archive containing the files partially named:
600+| report |
601+| data |
602+| image |
603+
604+```
605+
606+</details>
607+
608+<details>
609+ <summary><code>@Then the downloaded file should be a zip archive not containing the files partially named:</code></summary>
610+
611+<br/>
612+Assert the downloaded file is a zip archive not containing files with partial names
613+<br/><br/>
614+
615+```gherkin
616+Then the downloaded file should be a zip archive not containing the files partially named:
617+| confidential |
618+| private |
619+| draft |
620+
621+```
622+
623+</details>
624+
625+## KeyboardTrait
626+
627+[Source](mdc:src/KeyboardTrait.php), [Example](mdc:tests/behat/features/keyboard.feature)
628+
629+> Simulate keyboard interactions in Drupal browser testing.
630+> - Trigger key press events including special keys and key combinations.
631+> - Assert keyboard navigation and shortcut functionality.
632+> - Support for targeted key presses on specific page elements.
633+
634+
635+<details>
636+ <summary><code>@When I press the key :key</code></summary>
637+
638+<br/>
639+Press a single keyboard key
640+<br/><br/>
641+
642+```gherkin
643+When I press the key "a"
644+When I press the key "tab"
645+
646+```
647+
648+</details>
649+
650+<details>
651+ <summary><code>@When I press the key :key on the element :selector</code></summary>
652+
653+<br/>
654+Press a single keyboard key on the element
655+<br/><br/>
656+
657+```gherkin
658+When I press the key "a" on the element "#edit-title"
659+When I press the key "tab" on the element "#edit-title"
660+
661+```
662+
663+</details>
664+
665+<details>
666+ <summary><code>@When I press the keys :keys</code></summary>
667+
668+<br/>
669+Press multiple keyboard keys
670+<br/><br/>
671+
672+```gherkin
673+When I press the keys "abc"
674+
675+```
676+
677+</details>
678+
679+<details>
680+ <summary><code>@When I press the keys :keys on the element :selector</code></summary>
681+
682+<br/>
683+Press multiple keyboard keys on the element
684+<br/><br/>
685+
686+```gherkin
687+When I press the keys "abc" on the element "#edit-title"
688+
689+```
690+
691+</details>
692+
693+## LinkTrait
694+
695+[Source](mdc:src/LinkTrait.php), [Example](mdc:tests/behat/features/link.feature)
696+
697+> Verify link elements with attribute and content assertions.
698+> - Find links by title, URL, text content, and class attributes.
699+> - Test link existence, visibility, and destination accuracy.
700+> - Assert absolute and relative link paths.
701+
702+
703+<details>
704+ <summary><code>@When I click on the link with the title :title</code></summary>
705+
706+<br/>
707+Click on the link with a title
708+<br/><br/>
709+
710+```gherkin
711+When I click on the link with the title "Return to site content"
712+
713+```
714+
715+</details>
716+
717+<details>
718+ <summary><code>@Then the link :link with the href :href should exist</code></summary>
719+
720+<br/>
721+Assert a link with a href exists
722+<br/><br/>
723+
724+```gherkin
725+Then the link "About us" with the href "/about-us" should exist
726+Then the link "About us" with the href "/about*" should exist
727+
728+```
729+
730+</details>
731+
732+<details>
733+ <summary><code>@Then the link :link with the href :href within the element :selector should exist</code></summary>
734+
735+<br/>
736+Assert link with a href exists within an element
737+<br/><br/>
738+
739+```gherkin
740+Then the link "About us" with the href "/about-us" within the element ".main-nav" should exist
741+Then the link "About us" with the href "/about*" within the element ".main-nav" should exist
742+
743+```
744+
745+</details>
746+
747+<details>
748+ <summary><code>@Then the link :link with the href :href should not exist</code></summary>
749+
750+<br/>
751+Assert link with a href does not exist
752+<br/><br/>
753+
754+```gherkin
755+Then the link "About us" with the href "/about-us" should not exist
756+Then the link "About us" with the href "/about*" should not exist
757+
758+```
759+
760+</details>
761+
762+<details>
763+ <summary><code>@Then the link :link with the href :href within the element :selector should not exist</code></summary>
764+
765+<br/>
766+Assert link with a href does not exist within an element
767+<br/><br/>
768+
769+```gherkin
770+Then the link "About us" with the href "/about-us" within the element ".main-nav" should not exist
771+Then the link "About us" with the href "/about*" within the element ".main-nav" should not exist
772+
773+```
774+
775+</details>
776+
777+<details>
778+ <summary><code>@Then the link with the title :title should exist</code></summary>
779+
780+<br/>
781+Assert that a link with a title exists
782+<br/><br/>
783+
784+```gherkin
785+Then the link with the title "Return to site content" should exist
786+
787+```
788+
789+</details>
790+
791+<details>
792+ <summary><code>@Then the link with the title :title should not exist</code></summary>
793+
794+<br/>
795+Assert that a link with a title does not exist
796+<br/><br/>
797+
798+```gherkin
799+Then the link with the title "Some non-existing title" should not exist
800+
801+```
802+
803+</details>
804+
805+<details>
806+ <summary><code>@Then the link :link should be an absolute link</code></summary>
807+
808+<br/>
809+Assert that the link with a text is absolute
810+<br/><br/>
811+
812+```gherkin
813+Then the link "my-link-title" should be an absolute link
814+
815+```
816+
817+</details>
818+
819+<details>
820+ <summary><code>@Then the link :link should not be an absolute link</code></summary>
821+
822+<br/>
823+Assert that the link is not an absolute
824+<br/><br/>
825+
826+```gherkin
827+Then the link "Return to site content" should not be an absolute link
828+
829+```
830+
831+</details>
832+
833+## PathTrait
834+
835+[Source](mdc:src/PathTrait.php), [Example](mdc:tests/behat/features/path.feature)
836+
837+> Navigate and verify paths with URL validation.
838+> - Assert current page location with front page special handling.
839+> - Configure basic authentication for protected path access.
840+
841+
842+<details>
843+ <summary><code>@Given the basic authentication with the username :username and the password :password</code></summary>
844+
845+<br/>
846+Set basic authentication for the current session
847+<br/><br/>
848+
849+```gherkin
850+Given the basic authentication with the username "myusername" and the password "mypassword"
851+
852+```
853+
854+</details>
855+
856+<details>
857+ <summary><code>@Then the path should be :path</code></summary>
858+
859+<br/>
860+Assert that the current page is a specified path
861+<br/><br/>
862+
863+```gherkin
864+Then the path should be "/about-us"
865+Then the path should be "<front>"
866+
867+```
868+
869+</details>
870+
871+<details>
872+ <summary><code>@Then the path should not be :path</code></summary>
873+
874+<br/>
875+Assert that the current page is not a specified path
876+<br/><br/>
877+
878+```gherkin
879+Then the path should not be "/about-us"
880+Then the path should not be "<front>"
881+
882+```
883+
884+</details>
885+
886+## ResponseTrait
887+
888+[Source](mdc:src/ResponseTrait.php), [Example](mdc:tests/behat/features/response.feature)
889+
890+> Verify HTTP responses with status code and header checks.
891+> - Assert HTTP header presence and values.
892+
893+
894+<details>
895+ <summary><code>@Then the response should contain the header :header_name</code></summary>
896+
897+<br/>
898+Assert that a response contains a header with specified name
899+<br/><br/>
900+
901+```gherkin
902+Then the response should contain the header "Connection"
903+
904+```
905+
906+</details>
907+
908+<details>
909+ <summary><code>@Then the response should not contain the header :header_name</code></summary>
910+
911+<br/>
912+Assert that a response does not contain a header with a specified name
913+<br/><br/>
914+
915+```gherkin
916+Then the response should not contain the header "Connection"
917+
918+```
919+
920+</details>
921+
922+<details>
923+ <summary><code>@Then the response header :header_name should contain the value :header_value</code></summary>
924+
925+<br/>
926+Assert that a response contains a header with a specified name and value
927+<br/><br/>
928+
929+```gherkin
930+Then the response header "Connection" should contain the value "Keep-Alive"
931+
932+```
933+
934+</details>
935+
936+<details>
937+ <summary><code>@Then the response header :header_name should not contain the value :header_value</code></summary>
938+
939+<br/>
940+Assert a response does not contain a header with a specified name and value
941+<br/><br/>
942+
943+```gherkin
944+Then the response header "Connection" should not contain the value "Keep-Alive"
945+
946+```
947+
948+</details>
949+
950+## WaitTrait
951+
952+[Source](mdc:src/WaitTrait.php), [Example](mdc:tests/behat/features/wait.feature)
953+
954+> Wait for a period of time or for AJAX to finish.
955+
956+
957+<details>
958+ <summary><code>@When I wait for :seconds second(s)</code></summary>
959+
960+<br/>
961+Wait for a specified number of seconds
962+<br/><br/>
963+
964+```gherkin
965+When I wait for 5 seconds
966+When I wait for 1 second
967+
968+```
969+
970+</details>
971+
972+<details>
973+ <summary><code>@When I wait for :seconds second(s) for AJAX to finish</code></summary>
974+
975+<br/>
976+Wait for the AJAX calls to finish
977+<br/><br/>
978+
979+```gherkin
980+When I wait for 5 seconds for AJAX to finish
981+When I wait for 1 second for AJAX to finish
982+
983+```
984+
985+</details>
986+
987+
988+
989+## Drupal\BigPipeTrait
990+
991+[Source](mdc:src/Drupal/BigPipeTrait.php), [Example](mdc:tests/behat/features/drupal_big_pipe.feature)
992+
993+> Bypass Drupal BigPipe when rendering pages.
994+> <br/><br/>
995+> Activated by adding `@big_pipe` tag to the scenario.
996+> <br/><br/>
997+> Skip processing with tags: `@behat-steps-skip:bigPipeBeforeScenario` or
998+> `@behat-steps-skip:bigPipeBeforeStep`.
999+
1000+
1001+## Drupal\BlockTrait
1002+
1003+[Source](mdc:src/Drupal/BlockTrait.php), [Example](mdc:tests/behat/features/drupal_block.feature)
1004+
1005+> Manage Drupal blocks.
1006+> - Create and configure blocks with custom visibility conditions.
1007+> - Place blocks in regions and verify their rendering in the page.
1008+> - Automatically clean up created blocks after scenario completion.
1009+>
1010+> Skip processing with tag: `@behat-steps-skip:blockAfterScenario`
1011+
1012+
1013+<details>
1014+ <summary><code>@Given the instance of :admin_label block exists with the following configuration:</code></summary>
1015+
1016+<br/>
1017+Create a block instance
1018+<br/><br/>
1019+
1020+```gherkin
1021+Given the instance of "My block" block exists with the following configuration:
1022+ | label | My block |
1023+ | label_display | 1 |
1024+ | region | content |
1025+ | status | 1 |
1026+
1027+```
1028+
1029+</details>
1030+
1031+<details>
1032+ <summary><code>@Given the block :label has the following configuration:</code></summary>
1033+
1034+<br/>
1035+Configure an existing block identified by label
1036+<br/><br/>
1037+
1038+```gherkin
1039+Given the block "My block" has the following configuration:
1040+| label_display | 1 |
1041+| region | content |
1042+| status | 1 |
1043+
1044+```
1045+
1046+</details>
1047+
1048+<details>
1049+ <summary><code>@Given the block :label does not exist</code></summary>
1050+
1051+<br/>
1052+Remove a block specified by label
1053+<br/><br/>
1054+
1055+```gherkin
1056+Given the block "My block" does not exist
1057+
1058+```
1059+
1060+</details>
1061+
1062+<details>
1063+ <summary><code>@Given the block :label is enabled</code></summary>
1064+
1065+<br/>
1066+Enable a block specified by label
1067+<br/><br/>
1068+
1069+```gherkin
1070+Given the block "My block" is enabled
1071+
1072+```
1073+
1074+</details>
1075+
1076+<details>
1077+ <summary><code>@Given the block :label is disabled</code></summary>
1078+
1079+<br/>
1080+Disable a block specified by label
1081+<br/><br/>
1082+
1083+```gherkin
1084+Given the block "My block" is disabled
1085+
1086+```
1087+
1088+</details>
1089+
1090+<details>
1091+ <summary><code>@Given the block :label has the following :condition condition configuration:</code></summary>
1092+
1093+<br/>
1094+Set a visibility condition for a block
1095+<br/><br/>
1096+
1097+```gherkin
1098+Given the block "My block" has the following "request_path" condition configuration:
1099+| pages | /node/1\r\n/about |
1100+| negate | 0 |
1101+
1102+```
1103+
1104+</details>
1105+
1106+<details>
1107+ <summary><code>@Given the block :label has the :condition condition removed</code></summary>
1108+
1109+<br/>
1110+Remove a visibility condition from the specified block
1111+<br/><br/>
1112+
1113+```gherkin
1114+Given the block "My block" has the "request_path" condition removed
1115+
1116+```
1117+
1118+</details>
1119+
1120+<details>
1121+ <summary><code>@Then the block :label should exist</code></summary>
1122+
1123+<br/>
1124+Assert that a block with the specified label exists
1125+<br/><br/>
1126+
1127+```gherkin
1128+Then the block "My block" should exist
1129+
1130+```
1131+
1132+</details>
1133+
1134+<details>
1135+ <summary><code>@Then the block :label should not exist</code></summary>
1136+
1137+<br/>
1138+Assert that a block with the specified label does not exist
1139+<br/><br/>
1140+
1141+```gherkin
1142+Then the block "My block" should not exist
1143+
1144+```
1145+
1146+</details>
1147+
1148+<details>
1149+ <summary><code>@Then the block :label should exist in the :region region</code></summary>
1150+
1151+<br/>
1152+Assert that a block with the specified label exists in a region
1153+<br/><br/>
1154+
1155+```gherkin
1156+Then the block "My block" should exist in the "content" region
1157+
1158+```
1159+
1160+</details>
1161+
1162+<details>
1163+ <summary><code>@Then the block :label should not exist in the :region region</code></summary>
1164+
1165+<br/>
1166+Assert that a block with the specified label does not exist in a region
1167+<br/><br/>
1168+
1169+```gherkin
1170+Then the block "My block" should not exist in the "content" region
1171+
1172+```
1173+
1174+</details>
1175+
1176+## Drupal\ContentBlockTrait
1177+
1178+[Source](mdc:src/Drupal/ContentBlockTrait.php), [Example](mdc:tests/behat/features/drupal_content_block.feature)
1179+
1180+> Manage Drupal content blocks.
1181+> - Define reusable custom block content with structured field data.
1182+> - Create, edit, and verify block_content entities by type and description.
1183+> - Automatically clean up created entities after scenario completion.
1184+>
1185+> Skip processing with tag: `@behat-steps-skip:contentBlockAfterScenario`
1186+
1187+
1188+<details>
1189+ <summary><code>@Given the following :type content blocks do not exist:</code></summary>
1190+
1191+<br/>
1192+Remove content blocks of a specified type with the given descriptions
1193+<br/><br/>
1194+
1195+```gherkin
1196+Given the following "basic" content blocks do not exist:
1197+| [TEST] Footer Block |
1198+| [TEST] Contact Form |
1199+
1200+```
1201+
1202+</details>
1203+
1204+<details>
1205+ <summary><code>@Given the following :type content blocks exist:</code></summary>
1206+
1207+<br/>
1208+Create content blocks of the specified type with the given field values
1209+<br/><br/>
1210+
1211+```gherkin
1212+Given the following "basic" content blocks exist:
1213+| info | status | body | created |
1214+| [TEST] Footer Contact | 1 | Call us at 555-1234 | 2023-01-17 8:00am |
1215+| [TEST] Copyright | 1 | © 2023 Example Company | 2023-01-18 9:00am |
1216+
1217+```
1218+
1219+</details>
1220+
1221+<details>
1222+ <summary><code>@When I edit the :type content block with the description :description</code></summary>
1223+
1224+<br/>
1225+Navigate to the edit page for a specified content block
1226+<br/><br/>
1227+
1228+```gherkin
1229+When I edit the "basic" content block with the description "[TEST] Footer Block"
1230+
1231+```
1232+
1233+</details>
1234+
1235+<details>
1236+ <summary><code>@Then the content block type :type should exist</code></summary>
1237+
1238+<br/>
1239+Assert that a content block type exists
1240+<br/><br/>
1241+
1242+```gherkin
1243+Then the content block type "Search" should exist
1244+
1245+```
1246+
1247+</details>
1248+
1249+## Drupal\ContentTrait
1250+
1251+[Source](mdc:src/Drupal/ContentTrait.php), [Example](mdc:tests/behat/features/drupal_content.feature)
1252+
1253+> Manage Drupal content with workflow and moderation support.
1254+> - Create, find, and manipulate nodes with structured field data.
1255+> - Navigate to node pages by title and manage editorial workflows.
1256+> - Support content moderation transitions and scheduled publishing.
1257+
1258+
1259+<details>
1260+ <summary><code>@Given the content type :content_type does not exist</code></summary>
1261+
1262+<br/>
1263+Delete content type
1264+<br/><br/>
1265+
1266+```gherkin
1267+Given the content type "article" does not exist
1268+
1269+```
1270+
1271+</details>
1272+
1273+<details>
1274+ <summary><code>@Given the following :content_type content does not exist:</code></summary>
1275+
1276+<br/>
1277+Remove content defined by provided properties
1278+<br/><br/>
1279+
1280+```gherkin
1281+Given the following "article" content does not exist:
1282+ | title |
1283+ | Test article |
1284+ | Another test article |
1285+
1286+```
1287+
1288+</details>
1289+
1290+<details>
1291+ <summary><code>@When I visit the :content_type content page with the title :title</code></summary>
1292+
1293+<br/>
1294+Visit a page of a type with a specified title
1295+<br/><br/>
1296+
1297+```gherkin
1298+When I visit the "article" content page with the title "Test article"
1299+
1300+```
1301+
1302+</details>
1303+
1304+<details>
1305+ <summary><code>@When I visit the :content_type content edit page with the title :title</code></summary>
1306+
1307+<br/>
1308+Visit an edit page of a type with a specified title
1309+<br/><br/>
1310+
1311+```gherkin
1312+When I visit the "article" content edit page with the title "Test article"
1313+
1314+```
1315+
1316+</details>
1317+
1318+<details>
1319+ <summary><code>@When I visit the :content_type content delete page with the title :title</code></summary>
1320+
1321+<br/>
1322+Visit a delete page of a type with a specified title
1323+<br/><br/>
1324+
1325+```gherkin
1326+When I visit the "article" content delete page with the title "Test article"
1327+
1328+```
1329+
1330+</details>
1331+
1332+<details>
1333+ <summary><code>@When I visit the :content_type content scheduled transitions page with the title :title</code></summary>
1334+
1335+<br/>
1336+Visit a scheduled transitions page of a type with a specified title
1337+<br/><br/>
1338+
1339+```gherkin
1340+When I visit the "article" content scheduled transitions page with the title "Test article"
1341+
1342+```
1343+
1344+</details>
1345+
1346+<details>
1347+ <summary><code>@When I change the moderation state of the :content_type content with the title :title to the :new_state state</code></summary>
1348+
1349+<br/>
1350+Change moderation state of a content with the specified title
1351+<br/><br/>
1352+
1353+```gherkin
1354+When I change the moderation state of the "article" content with the title "Test article" to the "published" state
1355+
1356+```
1357+
1358+</details>
1359+
1360+## Drupal\DraggableviewsTrait
1361+
1362+[Source](mdc:src/Drupal/DraggableviewsTrait.php), [Example](mdc:tests/behat/features/drupal_draggableviews.feature)
1363+
1364+> Order items in the Drupal Draggable Views.
1365+
1366+
1367+<details>
1368+ <summary><code>@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:</code></summary>
1369+
1370+<br/>
1371+Save order of the Draggable Order items
1372+<br/><br/>
1373+
1374+```gherkin
1375+When I save the draggable views items of the view "draggableviews_demo" and the display "page_1" for the "article" content in the following order:
1376+ | First Article |
1377+ | Second Article |
1378+ | Third Article |
1379+
1380+```
1381+
1382+</details>
1383+
1384+## Drupal\EckTrait
1385+
1386+[Source](mdc:src/Drupal/EckTrait.php), [Example](mdc:tests/behat/features/drupal_eck.feature)
1387+
1388+> Manage Drupal ECK entities with custom type and bundle creation.
1389+> - Create structured ECK entities with defined field values.
1390+> - Assert entity type registration and visit entity pages.
1391+> - Automatically clean up created entities after scenario completion.
1392+>
1393+> Skip processing with tag: `@behat-steps-skip:eckAfterScenario`
1394+
1395+
1396+<details>
1397+ <summary><code>@Given the following eck :bundle :entity_type entities exist:</code></summary>
1398+
1399+<br/>
1400+Create eck entities
1401+<br/><br/>
1402+
1403+```gherkin
1404+Given the following eck "contact" "contact_type" entities exist:
1405+| title | field_marine_animal | field_fish_type | ... |
1406+| Snook | Fish | Marine fish | 10 |
1407+| ... | ... | ... | ... |
1408+
1409+```
1410+
1411+</details>
1412+
1413+<details>
1414+ <summary><code>@Given the following eck :bundle :entity_type entities do not exist:</code></summary>
1415+
1416+<br/>
1417+Remove custom entities by field
1418+<br/><br/>
1419+
1420+```gherkin
1421+Given the following eck "contact" "contact_type" entities do not exist:
1422+| field | value |
1423+| field_a | Entity label |
1424+
1425+```
1426+
1427+</details>
1428+
1429+<details>
1430+ <summary><code>@When I visit eck :bundle :entity_type entity with the title :title</code></summary>
1431+
1432+<br/>
1433+Navigate to view entity page with specified type and title
1434+<br/><br/>
1435+
1436+```gherkin
1437+When I visit eck "contact" "contact_type" entity with the title "Test contact"
1438+
1439+```
1440+
1441+</details>
1442+
1443+<details>
1444+ <summary><code>@When I edit eck :bundle :entity_type entity with the title :title</code></summary>
1445+
1446+<br/>
1447+Navigate to edit eck entity page with specified type and title
1448+<br/><br/>
1449+
1450+```gherkin
1451+When I edit eck "contact" "contact_type" entity with the title "Test contact"
1452+
1453+```
1454+
1455+</details>
1456+
1457+## Drupal\EmailTrait
1458+
1459+[Source](mdc:src/Drupal/EmailTrait.php), [Example](mdc:tests/behat/features/drupal_email.feature)
1460+
1461+> Test Drupal email functionality with content verification.
1462+> - Capture and examine outgoing emails with header and body validation.
1463+> - Follow links and test attachments within email content.
1464+> - Configure mail handler systems for proper test isolation.
1465+>
1466+> Skip processing with tags: `@behat-steps-skip:emailBeforeScenario` or
1467+> `@behat-steps-skip:emailAfterScenario`
1468+> <br/><br/>
1469+> Special tags:
1470+> - `@email` - enable email tracking using a default handler
1471+> - `@email:{type}` - enable email tracking using a `{type}` handler
1472+> - `@debug` (enable detailed logs)
1473+
1474+
1475+<details>
1476+ <summary><code>@When I clear the test email system queue</code></summary>
1477+
1478+<br/>
1479+Clear test email system queue
1480+<br/><br/>
1481+
1482+```gherkin
1483+When I clear the test email system queue
1484+
1485+```
1486+
1487+</details>
1488+
1489+<details>
1490+ <summary><code>@When I follow link number :link_number in the email with the subject :subject</code></summary>
1491+
1492+<br/>
1493+Follow a specific link number in an email with the given subject
1494+<br/><br/>
1495+
1496+```gherkin
1497+When I follow link number "1" in the email with the subject "Account Verification"
1498+
1499+```
1500+
1501+</details>
1502+
1503+<details>
1504+ <summary><code>@When I follow link number :link_number in the email with the subject containing :subject</code></summary>
1505+
1506+<br/>
1507+Follow a specific link number in an email whose subject contains the given substring
1508+<br/><br/>
1509+
1510+```gherkin
1511+When I follow link number "1" in the email with the subject containing "Verification"
1512+
1513+```
1514+
1515+</details>
1516+
1517+<details>
1518+ <summary><code>@When I enable the test email system</code></summary>
1519+
1520+<br/>
1521+Enable the test email system
1522+<br/><br/>
1523+
1524+```gherkin
1525+When I enable the test email system
1526+
1527+```
1528+
1529+</details>
1530+
1531+<details>
1532+ <summary><code>@When I disable the test email system</code></summary>
1533+
1534+<br/>
1535+Disable test email system
1536+<br/><br/>
1537+
1538+```gherkin
1539+When I disable the test email system
1540+
1541+```
1542+
1543+</details>
1544+
1545+<details>
1546+ <summary><code>@Then an email should be sent to the :address</code></summary>
1547+
1548+<br/>
1549+Assert that an email should be sent to an address
1550+<br/><br/>
1551+
1552+```gherkin
1553+Then an email should be sent to the "user@example.com"
1554+
1555+```
1556+
1557+</details>
1558+
1559+<details>
1560+ <summary><code>@Then no emails should have been sent</code></summary>
1561+
1562+<br/>
1563+Assert that no email messages should be sent
1564+<br/><br/>
1565+
1566+```gherkin
1567+Then no emails should have been sent
1568+
1569+```
1570+
1571+</details>
1572+
1573+<details>
1574+ <summary><code>@Then no emails should have been sent to the :address</code></summary>
1575+
1576+<br/>
1577+Assert that no email messages should be sent to a specified address
1578+<br/><br/>
1579+
1580+```gherkin
1581+Then no emails should have been sent to the "user@example.com"
1582+
1583+```
1584+
1585+</details>
1586+
1587+<details>
1588+ <summary><code>@Then the email header :header should contain:</code></summary>
1589+
1590+<br/>
1591+Assert that the email message header should contain specified content
1592+<br/><br/>
1593+
1594+```gherkin
1595+Then the email header "Subject" should contain:
1596+"""
1597+Account details
1598+"""
1599+
1600+```
1601+
1602+</details>
1603+
1604+<details>
1605+ <summary><code>@Then the email header :header should exactly be:</code></summary>
1606+
1607+<br/>
1608+Assert that the email message header should be the exact specified content
1609+<br/><br/>
1610+
1611+```gherkin
1612+Then the email header "Subject" should exactly be:
1613+"""
1614+Your Account Details
1615+"""
1616+
1617+```
1618+
1619+</details>
1620+
1621+<details>
1622+ <summary><code>@Then an email should be sent to the address :address with the content:</code></summary>
1623+
1624+<br/>
1625+Assert that an email should be sent to an address with the exact content in the body
1626+<br/><br/>
1627+
1628+```gherkin
1629+Then an email should be sent to the address "user@example.com" with the content:
1630+"""
1631+Welcome to our site!
1632+Click the link below to verify your account.
1633+"""
1634+
1635+```
1636+
1637+</details>
1638+
1639+<details>
1640+ <summary><code>@Then an email should be sent to the address :address with the content containing:</code></summary>
1641+
1642+<br/>
1643+Assert that an email should be sent to an address with the body containing specific content
1644+<br/><br/>
1645+
1646+```gherkin
1647+Then an email should be sent to the address "user@example.com" with the content containing:
1648+"""
1649+verification link
1650+"""
1651+
1652+```
1653+
1654+</details>
1655+
1656+<details>
1657+ <summary><code>@Then an email should be sent to the address :address with the content not containing:</code></summary>
1658+
1659+<br/>
1660+Assert that an email should be sent to an address with the body not containing specific content
1661+<br/><br/>
1662+
1663+```gherkin
1664+Then an email should be sent to the address "user@example.com" with the content not containing:
1665+"""
1666+password
1667+"""
1668+
1669+```
1670+
1671+</details>
1672+
1673+<details>
1674+ <summary><code>@Then an email should not be sent to the address :address with the content:</code></summary>
1675+
1676+<br/>
1677+Assert that an email should not be sent to an address with the exact content in the body
1678+<br/><br/>
1679+
1680+```gherkin
1681+Then an email should not be sent to the address "wrong@example.com" with the content:
1682+"""
1683+Welcome to our site!
1684+"""
1685+
1686+```
1687+
1688+</details>
1689+
1690+<details>
1691+ <summary><code>@Then an email should not be sent to the address :address with the content containing:</code></summary>
1692+
1693+<br/>
1694+Assert that an email should not be sent to an address with the body containing specific content
1695+<br/><br/>
1696+
1697+```gherkin
1698+Then an email should not be sent to the address "wrong@example.com" with the content containing:
1699+"""
1700+verification link
1701+"""
1702+
1703+```
1704+
1705+</details>
1706+
1707+<details>
1708+ <summary><code>@Then the email field :field should contain:</code></summary>
1709+
1710+<br/>
1711+Assert that the email field should contain a value
1712+<br/><br/>
1713+
1714+```gherkin
1715+Then the email field "body" should contain:
1716+"""
1717+Please verify your account
1718+"""
1719+
1720+```
1721+
1722+</details>
1723+
1724+<details>
1725+ <summary><code>@Then the email field :field should be:</code></summary>
1726+
1727+<br/>
1728+Assert that the email field should exactly match a value
1729+<br/><br/>
1730+
1731+```gherkin
1732+Then the email field "subject" should be:
1733+"""
1734+Account Verification
1735+"""
1736+
1737+```
1738+
1739+</details>
1740+
1741+<details>
1742+ <summary><code>@Then the email field :field should not contain:</code></summary>
1743+
1744+<br/>
1745+Assert that the email field should not contain a value
1746+<br/><br/>
1747+
1748+```gherkin
1749+Then the email field "body" should not contain:
1750+"""
1751+password
1752+"""
1753+
1754+```
1755+
1756+</details>
1757+
1758+<details>
1759+ <summary><code>@Then the email field :field should not be:</code></summary>
1760+
1761+<br/>
1762+Assert that the email field should not exactly match a value
1763+<br/><br/>
1764+
1765+```gherkin
1766+Then the email field "subject" should not be:
1767+"""
1768+Password Reset
1769+"""
1770+
1771+```
1772+
1773+</details>
1774+
1775+<details>
1776+ <summary><code>@Then the file :file_name should be attached to the email with the subject :subject</code></summary>
1777+
1778+<br/>
1779+Assert that a file is attached to an email message with specified subject
1780+<br/><br/>
1781+
1782+```gherkin
1783+Then the file "document.pdf" should be attached to the email with the subject "Your document"
1784+
1785+```
1786+
1787+</details>
1788+
1789+<details>
1790+ <summary><code>@Then the file :file_name should be attached to the email with the subject containing :subject</code></summary>
1791+
1792+<br/>
1793+Assert that a file is attached to an email message with a subject containing the specified substring
1794+<br/><br/>
1795+
1796+```gherkin
1797+Then the file "report.xlsx" should be attached to the email with the subject containing "Monthly Report"
1798+
1799+```
1800+
1801+</details>
1802+
1803+## Drupal\FieldTrait
1804+
1805+[Source](mdc:src/Drupal/FieldTrait.php), [Example](mdc:tests/behat/features/drupal_field.feature)
1806+
1807+> Manipulate Drupal form fields and verify widget functionality.
1808+> - Set field values for various input types including selects and WYSIWYG.
1809+> - Assert field existence, state, and selected options.
1810+> - Support for specialized widgets like color pickers and rich text editors.
1811+
1812+
1813+<details>
1814+ <summary><code>@When I fill in the color field :field with the value :value</code></summary>
1815+
1816+<br/>
1817+Fill value for color field
1818+<br/><br/>
1819+
1820+```gherkin
1821+When I fill in the color field "#edit-text-color" with the value "#3366FF"
1822+
1823+```
1824+
1825+</details>
1826+
1827+<details>
1828+ <summary><code>@When I fill in the WYSIWYG field :field with the :value</code></summary>
1829+
1830+<br/>
1831+Set value for WYSIWYG field
1832+<br/><br/>
1833+
1834+```gherkin
1835+When I fill in the WYSIWYG field "edit-body-0-value" with the "<p>This is a <strong>formatted</strong> paragraph.</p>"
1836+
1837+```
1838+
1839+</details>
1840+
1841+<details>
1842+ <summary><code>@Then the field :name should exist</code></summary>
1843+
1844+<br/>
1845+Assert that field exists on the page using id,name,label or value
1846+<br/><br/>
1847+
1848+```gherkin
1849+Then the field "Body" should exist
1850+Then the field "field_body" should exist
1851+
1852+```
1853+
1854+</details>
1855+
1856+<details>
1857+ <summary><code>@Then the field :name should not exist</code></summary>
1858+
1859+<br/>
1860+Assert that field does not exist on the page using id,name,label or value
1861+<br/><br/>
1862+
1863+```gherkin
1864+Then the field "Body" should not exist
1865+Then the field "field_body" should not exist
1866+
1867+```
1868+
1869+</details>
1870+
1871+<details>
1872+ <summary><code>@Then the field :name should be :enabled_or_disabled</code></summary>
1873+
1874+<br/>
1875+Assert whether the field has a state
1876+<br/><br/>
1877+
1878+```gherkin
1879+Then the field "Body" should be "disabled"
1880+Then the field "field_body" should be "disabled"
1881+Then the field "Tags" should be "enabled"
1882+Then the field "field_tags" should be "not enabled"
1883+
1884+```
1885+
1886+</details>
1887+
1888+<details>
1889+ <summary><code>@Then the color field :field should have the value :value</code></summary>
1890+
1891+<br/>
1892+Assert that a color field has a value
1893+<br/><br/>
1894+
1895+```gherkin
1896+Then the color field "#edit-background-color" should have the value "#FF5733"
1897+
1898+```
1899+
1900+</details>
1901+
1902+<details>
1903+ <summary><code>@Then the option :option should exist within the select element :selector</code></summary>
1904+
1905+<br/>
1906+Assert that a select has an option
1907+<br/><br/>
1908+
1909+```gherkin
1910+Then the option "Administrator" should exist within the select element "edit-roles"
1911+
1912+```
1913+
1914+</details>
1915+
1916+<details>
1917+ <summary><code>@Then the option :option should not exist within the select element :selector</code></summary>
1918+
1919+<br/>
1920+Assert that a select does not have an option
1921+<br/><br/>
1922+
1923+```gherkin
1924+Then the option "Guest" should not exist within the select element "edit-roles"
1925+
1926+```
1927+
1928+</details>
1929+
1930+<details>
1931+ <summary><code>@Then the option :option should be selected within the select element :selector</code></summary>
1932+
1933+<br/>
1934+Assert that a select option is selected
1935+<br/><br/>
1936+
1937+```gherkin
1938+Then the option "Administrator" should be selected within the select element "edit-roles"
1939+
1940+```
1941+
1942+</details>
1943+
1944+<details>
1945+ <summary><code>@Then the option :option should not be selected within the select element :selector</code></summary>
1946+
1947+<br/>
1948+Assert that a select option is not selected
1949+<br/><br/>
1950+
1951+```gherkin
1952+Then the option "Editor" should not be selected within the select element "edit-roles"
1953+
1954+```
1955+
1956+</details>
1957+
1958+## Drupal\FileTrait
1959+
1960+[Source](mdc:src/Drupal/FileTrait.php), [Example](mdc:tests/behat/features/drupal_file.feature)
1961+
1962+> Manage Drupal file entities with upload and storage operations.
1963+> - Create managed and unmanaged files with specific URIs and content.
1964+> - Verify file existence, content, and proper storage locations.
1965+> - Set up file system directories and clean up created files.
1966+>
1967+> Skip processing with tags: `@behat-steps-skip:fileBeforeScenario` or
1968+> `@behat-steps-skip:fileAfterScenario`
1969+
1970+
1971+<details>
1972+ <summary><code>@Given the following managed files:</code></summary>
1973+
1974+<br/>
1975+Create managed files with properties provided in the table
1976+<br/><br/>
1977+
1978+```gherkin
1979+Given the following managed files:
1980+| path | uri | status |
1981+| document.pdf | public://document.pdf | 1 |
1982+| image.jpg | public://images/pic.jpg| 1 |
1983+
1984+```
1985+
1986+</details>
1987+
1988+<details>
1989+ <summary><code>@Given the following managed files do not exist:</code></summary>
1990+
1991+<br/>
1992+Delete managed files defined by provided properties/fields
1993+<br/><br/>
1994+
1995+```gherkin
1996+Given no managed files:
1997+| filename |
1998+| myfile.jpg |
1999+| otherfile.jpg |
2000+ Given no managed files:
2001+ | uri |
2002+ | public://myfile.jpg |
2003+ | public://otherfile.jpg |
2004+
2005+```
2006+
2007+</details>
2008+
2009+<details>
2010+ <summary><code>@Given the unmanaged file at the URI :uri exists</code></summary>
2011+
2012+<br/>
2013+Create an unmanaged file
2014+<br/><br/>
2015+
2016+```gherkin
2017+Given the unmanaged file at the URI "public://sample.txt" exists
2018+
2019+```
2020+
2021+</details>
2022+
2023+<details>
2024+ <summary><code>@Given the unmanaged file at the URI :uri exists with :content</code></summary>
2025+
2026+<br/>
2027+Create an unmanaged file with specified content
2028+<br/><br/>
2029+
2030+```gherkin
2031+Given the unmanaged file at the URI "public://data.txt" exists with "Sample content"
2032+
2033+```
2034+
2035+</details>
2036+
2037+<details>
2038+ <summary><code>@Then an unmanaged file at the URI :uri should exist</code></summary>
2039+
2040+<br/>
2041+Assert that an unmanaged file with specified URI exists
2042+<br/><br/>
2043+
2044+```gherkin
2045+Then an unmanaged file at the URI "public://sample.txt" should exist
2046+
2047+```
2048+
2049+</details>
2050+
2051+<details>
2052+ <summary><code>@Then an unmanaged file at the URI :uri should not exist</code></summary>
2053+
2054+<br/>
2055+Assert that an unmanaged file with specified URI does not exist
2056+<br/><br/>
2057+
2058+```gherkin
2059+Then an unmanaged file at the URI "public://temp.txt" should not exist
2060+
2061+```
2062+
2063+</details>
2064+
2065+<details>
2066+ <summary><code>@Then an unmanaged file at the URI :uri should contain :content</code></summary>
2067+
2068+<br/>
2069+Assert that an unmanaged file exists and has specified content
2070+<br/><br/>
2071+
2072+```gherkin
2073+Then an unmanaged file at the URI "public://config.txt" should contain "debug=true"
2074+
2075+```
2076+
2077+</details>
2078+
2079+<details>
2080+ <summary><code>@Then an unmanaged file at the URI :uri should not contain :content</code></summary>
2081+
2082+<br/>
2083+Assert that an unmanaged file exists and does not have specified content
2084+<br/><br/>
2085+
2086+```gherkin
2087+Then an unmanaged file at the URI "public://config.txt" should not contain "debug=false"
2088+
2089+```
2090+
2091+</details>
2092+
2093+## Drupal\MediaTrait
2094+
2095+[Source](mdc:src/Drupal/MediaTrait.php), [Example](mdc:tests/behat/features/drupal_media.feature)
2096+
2097+> Manage Drupal media entities with type-specific field handling.
2098+> - Create structured media items with proper file reference handling.
2099+> - Assert media browser functionality and edit media entity fields.
2100+> - Support for multiple media types with field value expansion handling.
2101+> - Automatically clean up created entities after scenario completion.
2102+>
2103+> Skip processing with tag: `@behat-steps-skip:mediaAfterScenario`
2104+
2105+
2106+<details>
2107+ <summary><code>@Given :media_type media type does not exist</code></summary>
2108+
2109+<br/>
2110+Remove media type
2111+<br/><br/>
2112+
2113+```gherkin
2114+Given "video" media type does not exist
2115+
2116+```
2117+
2118+</details>
2119+
2120+<details>
2121+ <summary><code>@Given the following media :media_type exist:</code></summary>
2122+
2123+<br/>
2124+Create media of a given type
2125+<br/><br/>
2126+
2127+```gherkin
2128+Given "video" media:
2129+| name | field1 | field2 | field3 |
2130+| My media | file.jpg | value | value |
2131+| ... | ... | ... | ... |
2132+
2133+```
2134+
2135+</details>
2136+
2137+<details>
2138+ <summary><code>@Given the following media :media_type do not exist:</code></summary>
2139+
2140+<br/>
2141+Remove media defined by provided properties
2142+<br/><br/>
2143+
2144+```gherkin
2145+Given the following media "image" do not exist:
2146+| name |
2147+| Media item |
2148+| Another media item |
2149+
2150+```
2151+
2152+</details>
2153+
2154+<details>
2155+ <summary><code>@When I edit the media :media_type with the name :name</code></summary>
2156+
2157+<br/>
2158+Navigate to edit media with specified type and name
2159+<br/><br/>
2160+
2161+```gherkin
2162+When I edit "document" media "Test document"
2163+
2164+```
2165+
2166+</details>
2167+
2168+## Drupal\MenuTrait
2169+
2170+[Source](mdc:src/Drupal/MenuTrait.php), [Example](mdc:tests/behat/features/drupal_menu.feature)
2171+
2172+> Manage Drupal menu systems and menu link rendering.
2173+> - Assert menu items by label, path, and containment hierarchy.
2174+> - Assert menu link visibility and active states in different regions.
2175+> - Create and manage menu hierarchies with parent-child relationships.
2176+> - Automatically clean up created menu links after scenario completion.
2177+>
2178+> Skip processing with tag: `@behat-steps-skip:menuAfterScenario`
2179+
2180+
2181+<details>
2182+ <summary><code>@Given the menu :menu_name does not exist</code></summary>
2183+
2184+<br/>
2185+Remove a single menu by its label if it exists
2186+<br/><br/>
2187+
2188+```gherkin
2189+Given the menu "Test Menu" does not exist
2190+
2191+```
2192+
2193+</details>
2194+
2195+<details>
2196+ <summary><code>@Given the following menus:</code></summary>
2197+
2198+<br/>
2199+Create a menu if one does not exist
2200+<br/><br/>
2201+
2202+```gherkin
2203+Given the following menus:
2204+| label | description |
2205+| Footer Menu | Links displayed in the footer |
2206+| Secondary Menu | Secondary navigation menu |
2207+
2208+```
2209+
2210+</details>
2211+
2212+<details>
2213+ <summary><code>@Given the following menu links do not exist in the menu :menu_name:</code></summary>
2214+
2215+<br/>
2216+Remove menu links by title
2217+<br/><br/>
2218+
2219+```gherkin
2220+Given the following menu links do not exist in the menu "Main navigation":
2221+| About Us |
2222+| Contact |
2223+
2224+```
2225+
2226+</details>
2227+
2228+<details>
2229+ <summary><code>@Given the following menu links exist in the menu :menu_name :</code></summary>
2230+
2231+<br/>
2232+Create menu links
2233+<br/><br/>
2234+
2235+```gherkin
2236+Given the following menu links exist in the menu "Main navigation":
2237+| title | enabled | uri | parent |
2238+| Products | 1 | /products | |
2239+| Latest Products | 1 | /products/latest | Products |
2240+
2241+```
2242+
2243+</details>
2244+
2245+## Drupal\MetatagTrait
2246+
2247+[Source](mdc:src/Drupal/MetatagTrait.php), [Example](mdc:tests/behat/features/drupal_metatag.feature)
2248+
2249+> Assert `<meta>` tags in page markup.
2250+> - Assert presence and content of meta tags with proper attribute handling.
2251+
2252+
2253+## Drupal\OverrideTrait
2254+
2255+[Source](mdc:src/Drupal/OverrideTrait.php), [Example](mdc:tests/behat/features/drupal_override.feature)
2256+
2257+> Override Drupal Extension behaviors.
2258+> - Automated entity deletion before creation to avoid duplicates.
2259+> - Improved user authentication handling for anonymous users.
2260+>
2261+> Use with caution: depending on your version of Drupal Extension, PHP and
2262+> Composer, the step definition string (/^Given etc.../) may need to be defined
2263+> for these overrides. If you encounter errors about missing or duplicated
2264+> step definitions, do not include this trait and rather copy the contents of
2265+> this file into your feature context file and copy the step definition strings
2266+> from the Drupal Extension.
2267+
2268+
2269+## Drupal\ParagraphsTrait
2270+
2271+[Source](mdc:src/Drupal/ParagraphsTrait.php), [Example](mdc:tests/behat/features/drupal_paragraphs.feature)
2272+
2273+> Manage Drupal paragraphs entities with structured field data.
2274+> - Create paragraph items with type-specific field values.
2275+> - Test nested paragraph structures and reference field handling.
2276+> - Attach paragraphs to various entity types with parent-child relationships.
2277+> - Automatically clean up created paragraph items after scenario completion.
2278+>
2279+> Skip processing with tag: `@behat-steps-skip:paragraphsAfterScenario`
2280+
2281+
2282+<details>
2283+ <summary><code>@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:</code></summary>
2284+
2285+<br/>
2286+Create a paragraph of the given type with fields within an existing entity
2287+<br/><br/>
2288+
2289+```gherkin
2290+Given the following fields for the paragraph "text" exist in the field "field_component" within the "landing_page" "node" identified by the field "title" and the value "My landing page":
2291+| field_paragraph_title | My paragraph title |
2292+| field_paragraph_longtext:value | My paragraph message |
2293+| field_paragraph_longtext:format | full_html |
2294+| ... | ... |
2295+
2296+```
2297+
2298+</details>
2299+
2300+## Drupal\SearchApiTrait
2301+
2302+[Source](mdc:src/Drupal/SearchApiTrait.php), [Example](mdc:tests/behat/features/drupal_search_api.feature)
2303+
2304+> Assert Drupal Search API with index and query operations.
2305+> - Add content to an index
2306+> - Run indexing for a specific number of items.
2307+
2308+
2309+<details>
2310+ <summary><code>@When I add the :content_type content with the title :title to the search index</code></summary>
2311+
2312+<br/>
2313+Index a node of a specific content type with a specific title
2314+<br/><br/>
2315+
2316+```gherkin
2317+When I add the "article" content with the title "Test Article" to the search index
2318+
2319+```
2320+
2321+</details>
2322+
2323+<details>
2324+ <summary><code>@When I run search indexing for :count item(s)</code></summary>
2325+
2326+<br/>
2327+Run indexing for a specific number of items
2328+<br/><br/>
2329+
2330+```gherkin
2331+When I run search indexing for 5 items
2332+When I run search indexing for 1 item
2333+
2334+```
2335+
2336+</details>
2337+
2338+## Drupal\TaxonomyTrait
2339+
2340+[Source](mdc:src/Drupal/TaxonomyTrait.php), [Example](mdc:tests/behat/features/drupal_taxonomy.feature)
2341+
2342+> Manage Drupal taxonomy terms with vocabulary organization.
2343+> - Create term vocabulary structures using field values.
2344+> - Navigate to term pages
2345+> - Verify vocabulary configurations.
2346+
2347+
2348+<details>
2349+ <summary><code>@Given the following :vocabulary_machine_name vocabulary terms do not exist:</code></summary>
2350+
2351+<br/>
2352+Remove terms from a specified vocabulary
2353+<br/><br/>
2354+
2355+```gherkin
2356+Given the following "fruits" vocabulary terms do not exist:
2357+ | Apple |
2358+ | Pear |
2359+
2360+```
2361+
2362+</details>
2363+
2364+<details>
2365+ <summary><code>@When I visit the :vocabulary_machine_name vocabulary :term_name term page</code></summary>
2366+
2367+<br/>
2368+Visit specified vocabulary term page
2369+<br/><br/>
2370+
2371+```gherkin
2372+When I visit the "fruits" vocabulary "Apple" term page
2373+
2374+```
2375+
2376+</details>
2377+
2378+<details>
2379+ <summary><code>@When I edit the :vocabulary_machine_name vocabulary :term_name term page</code></summary>
2380+
2381+<br/>
2382+Edit specified vocabulary term page
2383+<br/><br/>
2384+
2385+```gherkin
2386+When I edit the "fruits" vocabulary "Apple" term page
2387+
2388+```
2389+
2390+</details>
2391+
2392+<details>
2393+ <summary><code>@Then the vocabulary :machine_name with the name :name should exist</code></summary>
2394+
2395+<br/>
2396+Assert that a vocabulary with a specific name exists
2397+<br/><br/>
2398+
2399+```gherkin
2400+Then the vocabulary "topics" with the name "Topics" should exist
2401+
2402+```
2403+
2404+</details>
2405+
2406+<details>
2407+ <summary><code>@Then the vocabulary :machine_name should not exist</code></summary>
2408+
2409+<br/>
2410+Assert that a vocabulary with a specific name does not exist
2411+<br/><br/>
2412+
2413+```gherkin
2414+Then the vocabulary "topics" should not exist
2415+
2416+```
2417+
2418+</details>
2419+
2420+<details>
2421+ <summary><code>@Then the taxonomy term :term_name from the vocabulary :vocabulary_machine_name should exist</code></summary>
2422+
2423+<br/>
2424+Assert that a taxonomy term exist by name
2425+<br/><br/>
2426+
2427+```gherkin
2428+Then the taxonomy term "Apple" from the vocabulary "Fruits" should exist
2429+
2430+```
2431+
2432+</details>
2433+
2434+<details>
2435+ <summary><code>@Then the taxonomy term :term_name from the vocabulary :vocabulary_machine_name should not exist</code></summary>
2436+
2437+<br/>
2438+Assert that a taxonomy term does not exist by name
2439+<br/><br/>
2440+
2441+```gherkin
2442+Then the taxonomy term "Apple" from the vocabulary "Fruits" should not exist
2443+
2444+```
2445+
2446+</details>
2447+
2448+## Drupal\TestmodeTrait
2449+
2450+[Source](mdc:src/Drupal/TestmodeTrait.php), [Example](mdc:tests/behat/features/drupal_testmode.feature)
2451+
2452+> Configure Drupal Testmode module for controlled testing scenarios.
2453+> <br/><br/>
2454+> Skip processing with tags: `@behat-steps-skip:testmodeBeforeScenario` and
2455+> `@behat-steps-skip:testmodeAfterScenario`.
2456+> <br/><br/>
2457+> Special tags:
2458+> - `@testmode` - enable for scenario
2459+
2460+
2461+## Drupal\UserTrait
2462+
2463+[Source](mdc:src/Drupal/UserTrait.php), [Example](mdc:tests/behat/features/drupal_user.feature)
2464+
2465+> Manage Drupal users with role and permission assignments.
2466+> - Create user accounts
2467+> - Create user roles
2468+> - Visit user profile pages for editing and deletion.
2469+> - Assert user roles and permissions.
2470+> - Assert user account status (active/inactive).
2471+
2472+
2473+<details>
2474+ <summary><code>@Given the following users do not exist:</code></summary>
2475+
2476+<br/>
2477+Remove users specified in a table
2478+<br/><br/>
2479+
2480+```gherkin
2481+Given the following users do not exist:
2482+ | name |
2483+ | John |
2484+ | Jane |
2485+ Given the following users do not exist:
2486+ | mail |
2487+ | john@example.com |
2488+ | jane@example.com |
2489+
2490+```
2491+
2492+</details>
2493+
2494+<details>
2495+ <summary><code>@Given the password for the user :name is :password</code></summary>
2496+
2497+<br/>
2498+Set a password for a user
2499+<br/><br/>
2500+
2501+```gherkin
2502+Given the password for the user "John" is "password"
2503+
2504+```
2505+
2506+</details>
2507+
2508+<details>
2509+ <summary><code>@Given the last access time for the user :name is :datetime</code></summary>
2510+
2511+<br/>
2512+Set last access time for a user
2513+<br/><br/>
2514+
2515+```gherkin
2516+Given the last access time for the user "John" is "Friday, 22 November 2024 13:46:14"
2517+Given the last access time for the user "John" is "1732319174"
2518+
2519+```
2520+
2521+</details>
2522+
2523+<details>
2524+ <summary><code>@Given the last login time for the user :name is :datetime</code></summary>
2525+
2526+<br/>
2527+Set last login time for a user
2528+<br/><br/>
2529+
2530+```gherkin
2531+Given the last login time for the user "John" is "Friday, 22 November 2024 13:46:14"
2532+Given the last login time for the user "John" is "1732319174"
2533+
2534+```
2535+
2536+</details>
2537+
2538+<details>
2539+ <summary><code>@Given the role :role_name with the permissions :permissions</code></summary>
2540+
2541+<br/>
2542+Create a single role with specified permissions
2543+<br/><br/>
2544+
2545+```gherkin
2546+Given the role "Content Manager" with the permissions "access content, create article content, edit any article content"
2547+
2548+```
2549+
2550+</details>
2551+
2552+<details>
2553+ <summary><code>@Given the following roles:</code></summary>
2554+
2555+<br/>
2556+Create multiple roles from the specified table
2557+<br/><br/>
2558+
2559+```gherkin
2560+Given the following roles:
2561+| name | permissions |
2562+| Content Editor | access content, create article content |
2563+| Content Approver | access content, edit any article content |
2564+
2565+```
2566+
2567+</details>
2568+
2569+<details>
2570+ <summary><code>@When I visit :name user profile page</code></summary>
2571+
2572+<br/>
2573+Visit the profile page of the specified user
2574+<br/><br/>
2575+
2576+```gherkin
2577+When I visit "John" user profile page
2578+
2579+```
2580+
2581+</details>
2582+
2583+<details>
2584+ <summary><code>@When I visit my own user profile page</code></summary>
2585+
2586+<br/>
2587+Visit the profile page of the current user
2588+<br/><br/>
2589+
2590+```gherkin
2591+When I visit my own user profile page
2592+
2593+```
2594+
2595+</details>
2596+
2597+<details>
2598+ <summary><code>@When I visit :name user profile edit page</code></summary>
2599+
2600+<br/>
2601+Visit the profile edit page of the specified user
2602+<br/><br/>
2603+
2604+```gherkin
2605+When I visit "John" user profile edit page
2606+
2607+```
2608+
2609+</details>
2610+
2611+<details>
2612+ <summary><code>@When I visit my own user profile edit page</code></summary>
2613+
2614+<br/>
2615+Visit the profile edit page of the current user
2616+<br/><br/>
2617+
2618+```gherkin
2619+When I visit my own user profile edit page
2620+
2621+```
2622+
2623+</details>
2624+
2625+<details>
2626+ <summary><code>@When I visit :name user profile delete page</code></summary>
2627+
2628+<br/>
2629+Visit the profile delete page of the specified user
2630+<br/><br/>
2631+
2632+```gherkin
2633+When I visit "John" user profile delete page
2634+
2635+```
2636+
2637+</details>
2638+
2639+<details>
2640+ <summary><code>@When I visit my own user profile delete page</code></summary>
2641+
2642+<br/>
2643+Visit the profile delete page of the current user
2644+<br/><br/>
2645+
2646+```gherkin
2647+When I visit my own user profile delete page
2648+
2649+```
2650+
2651+</details>
2652+
2653+<details>
2654+ <summary><code>@Then the user :name should have the role(s) :roles assigned</code></summary>
2655+
2656+<br/>
2657+Assert that a user has roles assigned
2658+<br/><br/>
2659+
2660+```gherkin
2661+Then the user "John" should have the roles "administrator, editor" assigned
2662+
2663+```
2664+
2665+</details>
2666+
2667+<details>
2668+ <summary><code>@Then the user :name should not have the role(s) :roles assigned</code></summary>
2669+
2670+<br/>
2671+Assert that a user does not have roles assigned
2672+<br/><br/>
2673+
2674+```gherkin
2675+Then the user "John" should not have the roles "administrator, editor" assigned
2676+
2677+```
2678+
2679+</details>
2680+
2681+<details>
2682+ <summary><code>@Then the user :name should be blocked</code></summary>
2683+
2684+<br/>
2685+Assert that a user is blocked
2686+<br/><br/>
2687+
2688+```gherkin
2689+Then the user "John" should be blocked
2690+
2691+```
2692+
2693+</details>
2694+
2695+<details>
2696+ <summary><code>@Then the user :name should not be blocked</code></summary>
2697+
2698+<br/>
2699+Assert that a user is not blocked
2700+<br/><br/>
2701+
2702+```gherkin
2703+Then the user "John" should not be blocked
2704+
2705+```
2706+
2707+</details>
2708+
2709+## Drupal\WatchdogTrait
2710+
2711+[Source](mdc:src/Drupal/WatchdogTrait.php), [Example](mdc:tests/behat/features/drupal_watchdog.feature)
2712+
2713+> Assert Drupal does not trigger PHP errors during scenarios using Watchdog.
2714+> - Check for Watchdog messages after scenario completion.
2715+> - Optionally check only for specific message types.
2716+> - Optionally skip error checking for specific scenarios.
2717+>
2718+> Skip processing with tags: `@behat-steps-skip:watchdogSetScenario` or
2719+> `@behat-steps-skip:watchdogAfterScenario`
2720+> <br/><br/>
2721+> Special tags:
2722+> - `@watchdog:{type}` - limit watchdog messages to specific types.
2723+> - `@error` - add to scenarios that are expected to trigger an error.
2724+
2725+## Steps Format Guidelines
2726+- **General Guidelines**:
2727+ - Use tuple format instead of regular expressions
2728+ - Use descriptive placeholder names
2729+ - Use `the following` for tabled content
2730+ - Use `with` for properties: `Then the link with the title :title should exist`
2731+ - Avoid optional words like `(the|a)`
2732+ - Omit unnecessary suffixes like `on the page`
2733+ - Method names should begin with the trait name: `userAssertHasRoles()`
2734+
2735+- **Given Steps**:
2736+ - Define test prerequisites
2737+ - Use words like `exists` or `have`
2738+ - Avoid using `should` or `should not`
2739+ - Avoid using `Given I`
2740+
2741+- **When Steps**:
2742+ - Describe an action with an action verb
2743+ - Use the format `When I <verb>`
2744+
2745+- **Then Steps**:
2746+ - Specify assertions and expectations
2747+ - Use `should` and `should not` for assertions
2748+ - Start with the entity being asserted
2749+ - Avoid using `Then I`
2750+ - Methods should include the `Assert` prefix
2751+
2752+## Common Behat Step Patterns
2753+- Block assertions:
2754+ - `I should see the block with label "..."`
2755+ - `I should see the block with label "..." in the region "..."`
2756+
2757+- Content block operations:
2758+ - `the content block type "..." should exist`
2759+ - `the following "..." content blocks exist:`
2760+ - `I edit the "..." content block with the description "..."`
2761+
2762+- Email testing:
2763+ - `I enable the test email system`
2764+ - `I clear the test email system queue`
2765+ - `an email should be sent to the "..."`
2766+
2767+## Skipping Before Scenario Hooks
2768+Some traits provide `beforeScenario` hook implementations that can be disabled by adding `behat-steps-skip:METHOD_NAME` tag to your test.
2769+
2770+Example: To skip `beforeScenario` hook from `ElementTrait`, add `@behat-steps-skip:ElementTrait` tag to the feature.
2771+
2772+## Code Style Conventions
2773+- Code is written using Drupal coding standards
2774+- Local variables and method arguments: `snake_case`
2775+- Method names and class properties: `camelCase`
2776+
