===============
LIBRARY RULES
===============
From library maintainers:
- Check rendered HTML with a CSS selector, never as a string or a regular expression.
- Select by tag, role, aria-*, label or text, then by a data-* marker; a class is a value to check with toHaveSelectorClass().
- A check of one node needs exactly one match; narrow to a region with within().
- Give a check its reason as the last argument; after the optional value of toHaveSelectorAttribute(), pass it by name: message: '…'.
### Install skill as Claude Code plugin
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Install the skill as a plugin in Claude Code by adding the marketplace and then installing the plugin.
```text
/plugin marketplace add sorge-it/phpunit-pest-html-assertions
/plugin install phpunit-pest-html-assertions@sorge-it
```
--------------------------------
### Install skill with npx skills
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Install the skill for other agents (Cursor, Codex, GitHub Copilot) using the `skills` CLI.
```sh
npx skills add sorge-it/phpunit-pest-html-assertions
```
--------------------------------
### Install with Composer
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Install the package as a dev dependency. When Pest is installed, Composer registers the expectations automatically, so tests/Pest.php needs no line.
```sh
composer require --dev sorge-it/phpunit-pest-html-assertions
```
--------------------------------
### Add package to boost.json
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Add the package to the `packages` array in `boost.json` so Laravel Boost installs the guideline and skill for the agent.
```json
{
"packages": ["sorge-it/phpunit-pest-html-assertions"]
}
```
--------------------------------
### toHaveSelectorClass example with class as value
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Example of using a CSS class as a value to check with toHaveSelectorClass, not as a selector. The class is the expected value, while the selector is a data-* marker.
```text
toHaveSelectorClass('[data-status]', 'bg-red-500')
```
--------------------------------
### Failure message for a check that fails
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Example failure message when a check fails. Shows the path of regions, what was asked, what was found, and the region itself as indented HTML, cut at 40 lines.
```text
Failed asserting that (page) > [data-cart] has one node matching "[data-name="Pear"]" with the text "Pear, ripe".
Its text is "Pear".
In (page) > [data-cart]:
-
Apple
-
Pear
```
--------------------------------
### NotOneNode failure message for one-node check
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Example failure message when a check of one node finds none or two matches. States the requirement for exactly one match and shows the selector and the number of nodes found.
```text
NotOneNode: (page) > [data-cart]: a check of one node needs exactly one match. The selector "[data-name]" finds 2 nodes.
```
--------------------------------
### Escape dot in attribute name: [wire\:poll\.10s]
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Example of escaping a dot in an attribute name for a selector.
```text
[wire\:poll\.10s]
```
--------------------------------
### Escape colon in attribute name: [wire\:model="name"]
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Example of escaping a colon in an attribute name for a selector.
```text
[wire\:model="name"]
```
--------------------------------
### PHPUnit: AssertsHtml trait with assertHtmlSelectorCount and assertHtmlAnySelectorTextSame
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
PHPUnit test using the AssertsHtml trait. Every method of the trait starts with 'assertHtml', so it also works in a Symfony WebTestCase, which has its own assertSelectorExists() and similar methods.
```php
use SorgeIt\PhpunitPestHtmlAssertions\PHPUnit\AssertsHtml;
final class CartTest extends TestCase
{
use AssertsHtml;
public function test_it_lists_the_items_of_the_cart(): void
{
$response = $this->get('/cart');
self::assertHtmlSelectorCount($response, '[data-cart] li', 3);
self::assertHtmlAnySelectorTextSame($response, '[data-cart] li', 'Apple');
}
}
```
--------------------------------
### Record demo with make -C demo all
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/CONTRIBUTING.md
Record the demo again when a message or the output of a check changes. Requires Docker.
```sh
make -C demo all
```
--------------------------------
### Run composer test and composer lint
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/CONTRIBUTING.md
Run the test suite and linters before opening a pull request. composer test runs Pint and Rector as a dry run, PHPStan at max, type coverage at 100%, and the test suites. composer lint runs Rector, then Pint.
```sh
composer test # Pint and Rector as a dry run, PHPStan at max, type coverage 100 %, the test suites
composer lint # Rector, then Pint
```
--------------------------------
### Run pest with HTML_ASSERTIONS_SHOW_FRAMES=1
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/CONTRIBUTING.md
Set the HTML_ASSERTIONS_SHOW_FRAMES environment variable to 1 to see frames from inside the package when a failure hides them. Run this in the shell before the command; setting it in phpunit.xml comes too late.
```sh
HTML_ASSERTIONS_SHOW_FRAMES=1 vendor/bin/pest
```
--------------------------------
### Html::of($value)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Creates an `Html` instance from a value in plain PHP.
```APIDOC
## [PHP] Html::of($value)
### Description
Creates an `Html` instance from a value in plain PHP.
### Method
Static factory method
### Endpoint
`Html::of($value)`
### Parameters
- **$value** (mixed) - Required - The page or HTML content.
### Usage Example
```php
$html = Html::of($page);
```
### Response
Returns an `Html` instance.
```
--------------------------------
### eachMatch($selector, $callback)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Applies the same assertions to every element matching a selector.
```APIDOC
## [PEST] eachMatch($selector, $callback)
### Description
Applies the same assertions to every element matching the selector. If no match is found, the test stops with `NoMatch`.
### Method
Pest expectation method
### Endpoint
`eachMatch($selector, $callback)`
### Parameters
- **$selector** (string) - Required - CSS selector for elements.
- **$callback** (callable) - Required - A function receiving an `Html` object for each match.
### Usage Example
```php
expect($page)->eachMatch('[data-avatar]', fn ($avatar) => $avatar->toHaveSelectorClass(':scope', 'rounded-full'));
```
### Response
Returns the expectation object for chaining.
```
--------------------------------
### Html::matches($selector)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Returns the matching elements for a selector.
```APIDOC
## [PHP] Html::matches($selector)
### Description
Returns the matching elements for a selector.
### Method
Instance method
### Endpoint
`Html::matches($selector)`
### Parameters
- **$selector** (string) - Required - CSS selector.
### Usage Example
```php
$matches = $html->matches('[data-item]');
```
### Response
Returns an array of matching elements.
```
--------------------------------
### Run checks on every match with eachMatch()
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/resources/boost/skills/phpunit-pest-html-assertions/SKILL.md
Run the same checks on every match with `eachMatch()`. No match stops the test with `NoMatch`. Never write `->not->eachMatch()`, `->not->within()`, or `->not->frame()`; turn the checks inside or after them around. A region reads like `querySelectorAll`: it finds nodes below its element, not the element itself; `:scope` alone names the element of the region, while `:scope > li` and `:scope.x` are refused.
```php
expect($response)->eachMatch('[data-avatar]', fn ($avatar) => $avatar->toHaveSelectorClass(':scope', 'rounded-full'));
```
--------------------------------
### HTML Assertions
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
A collection of Pest and PHPUnit assertions for HTML content, each with its parameters and failure message.
```APIDOC
## [Pest] toHaveSelector('[data-cart]')
### Description
Asserts that the page has a node matching the given CSS selector.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
### Response
Fails with: "Failed asserting that (page) has a node matching \"[data-cart]\""
```
```APIDOC
## [PHPUnit] assertHtmlSelectorNotExists('[data-cart]')
### Description
Asserts that the page does not have a node matching the given CSS selector.
### Method
PHPUnit trait method
### Parameters
- **selector** (string) - Required - CSS selector to match
### Response
Fails with: "Failed asserting that (page) does not have a node matching \"[data-cart]\""
```
```APIDOC
## [Pest] toHaveSelectorCount('li', 3)
### Description
Asserts that the page has exactly the given number of nodes matching the selector.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **count** (int) - Required - Expected number of matching nodes
### Response
Fails with: "Failed asserting that (page) has 3 nodes matching \"li\""
```
```APIDOC
## [Pest] toHaveSelectorCountAtLeast('li', 2)
### Description
Asserts that the page has at least the given number of nodes matching the selector.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **count** (int) - Required - Minimum number of matching nodes
### Response
Fails with: "Failed asserting that (page) has at least 2 nodes matching \"li\""
```
```APIDOC
## [Pest] toHaveSelectorText('h1', 'Orders')
### Description
Asserts that the page has exactly one node matching the selector with the given text.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **text** (string) - Required - Expected text content
### Response
Fails with: "Failed asserting that (page) has one node matching \"h1\" with the text \"Orders\""
```
```APIDOC
## [Pest] toHaveSelectorTextContaining('h1', 'Ord')
### Description
Asserts that the page has exactly one node matching the selector whose text contains the given substring.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **text** (string) - Required - Substring to search for
### Response
Fails with: "Failed asserting that (page) has one node matching \"h1\" whose text contains \"Ord\""
```
```APIDOC
## [Pest] toHaveAnySelectorText('li', 'Apple')
### Description
Asserts that the page has at least one node matching the selector with the given text.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **text** (string) - Required - Expected text content
### Response
Fails with: "Failed asserting that (page) has a node matching \"li\" with the text \"Apple\""
```
```APIDOC
## [Pest] toHaveAnySelectorTextContaining('li', 'App')
### Description
Asserts that the page has at least one node matching the selector whose text contains the given substring.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **text** (string) - Required - Substring to search for
### Response
Fails with: "Failed asserting that (page) has a node matching \"li\" whose text contains \"App\""
```
```APIDOC
## [Pest] toHaveSelectorAttribute('a', 'href', '/next')
### Description
Asserts that the page has exactly one node matching the selector with the given attribute value.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **attribute** (string) - Required - Attribute name
- **value** (string) - Required - Expected attribute value
### Response
Fails with: "Failed asserting that (page) has one node matching \"a\" whose attribute \"href\" is \"/next\""
```
```APIDOC
## [Pest] toHaveSelectorAttribute('button', 'disabled')
### Description
Asserts that the page has exactly one node matching the selector with the given attribute present.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **attribute** (string) - Required - Attribute name
### Response
Fails with: "Failed asserting that (page) has one node matching \"button\" with the attribute \"disabled\""
```
```APIDOC
## [Pest] toHaveSelectorAttributeContaining('a', 'href', 'page=2')
### Description
Asserts that the page has exactly one node matching the selector whose attribute value contains the given substring.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **attribute** (string) - Required - Attribute name
- **value** (string) - Required - Substring to search for in attribute value
### Response
Fails with: "Failed asserting that (page) has one node matching \"a\" whose attribute \"href\" contains \"page=2\""
```
```APIDOC
## [Pest] toHaveSelectorAttributeNamed('main', 'wire:poll')
### Description
Asserts that the page has exactly one node matching the selector with an attribute whose name starts with the given prefix.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **attribute** (string) - Required - Attribute name prefix
### Response
Fails with: "Failed asserting that (page) has one node matching \"main\" with an attribute whose name starts with \"wire:poll\""
```
```APIDOC
## [Pest] toHaveSelectorClass('[data-status]', 'bg-red-500')
### Description
Asserts that the page has exactly one node matching the selector with the given class.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **class** (string) - Required - Expected class name
### Response
Fails with: "Failed asserting that (page) has one node matching \"[data-status]\" with the class \"bg-red-500\""
```
```APIDOC
## [Pest] toHaveText('Apple Pear')
### Description
Asserts that the page has the given text.
### Method
Pest expectation
### Parameters
- **text** (string) - Required - Expected text content
### Response
Fails with: "Failed asserting that (page) has the text \"Apple Pear\""
```
```APIDOC
## [Pest] toHaveTextContaining('Apple')
### Description
Asserts that the page has text containing the given substring.
### Method
Pest expectation
### Parameters
- **text** (string) - Required - Substring to search for
### Response
Fails with: "Failed asserting that (page) has a text that contains \"Apple\""
```
```APIDOC
## [Pest] toHaveTextCount('Apple', 2)
### Description
Asserts that the page has the given text exactly the given number of times.
### Method
Pest expectation
### Parameters
- **text** (string) - Required - Text to count
- **count** (int) - Required - Expected number of occurrences
### Response
Fails with: "Failed asserting that (page) has the text \"Apple\" 2 times"
```
```APIDOC
## [Pest] toAppearBefore('[data-head]', '[data-body]')
### Description
Asserts that the node matching the first selector appears before the node matching the second selector in the document.
### Method
Pest expectation
### Parameters
- **selector1** (string) - Required - CSS selector for the first node
- **selector2** (string) - Required - CSS selector for the second node
### Response
Fails with: "Failed asserting that (page) has the node matching \"[data-head]\" before the node matching \"[data-body]\""
```
```APIDOC
## [Pest] toHaveTitle('Orders')
### Description
Asserts that the page has the given title.
### Method
Pest expectation
### Parameters
- **title** (string) - Required - Expected page title
### Response
Fails with: "Failed asserting that (page) has the title \"Orders\""
```
```APIDOC
## [Pest] toHaveInputValue('email', 'anna@example.com')
### Description
Asserts that the page has a field with the given name and value.
### Method
Pest expectation
### Parameters
- **name** (string) - Required - Field name
- **value** (string) - Required - Expected field value
### Response
Fails with: "Failed asserting that (page) has one field named \"email\" with the value \"anna@example.com\""
```
```APIDOC
## [Pest] toBeChecked('[data-agree]')
### Description
Asserts that the page has a checked checkbox matching the selector.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
### Response
Fails with: "Failed asserting that (page) has one checked box matching \"[data-agree]\""
```
```APIDOC
## [Pest] toHaveSelectedOption('[data-country]', 'de')
### Description
Asserts that the page has a select matching the selector with the given option chosen.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
- **option** (string) - Required - Expected selected option value
### Response
Fails with: "Failed asserting that (page) has one select matching \"[data-country]\" with the option \"de\" chosen"
```
```APIDOC
## [Pest] toBeDisabled('[data-send]')
### Description
Asserts that the page has a disabled node matching the selector.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
### Response
Fails with: "Failed asserting that (page) has one disabled node matching \"[data-send]\""
```
```APIDOC
## [Pest] toHaveLink('Next', '/page/2')
### Description
Asserts that the page has a link with the given text and href.
### Method
Pest expectation
### Parameters
- **text** (string) - Required - Link text
- **href** (string) - Required - Link destination
### Response
Fails with: "Failed asserting that (page) has a link \"Next\" to \"/page/2\""
```
```APIDOC
## [Pest] toBeEmptyNode('[data-errors]')
### Description
Asserts that the page has an empty node matching the selector.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to match
### Response
Fails with: "Failed asserting that (page) has one empty node matching \"[data-errors]\""
```
--------------------------------
### Html::count()
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Returns the number of matching elements.
```APIDOC
## [PHP] Html::count()
### Description
Returns the number of matching elements.
### Method
Instance method
### Endpoint
`Html::count()`
### Usage Example
```php
$count = $html->count();
```
### Response
Returns an integer count.
```
--------------------------------
### texts($selector)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Retrieves the text content of matching elements in page order.
```APIDOC
## [PEST] texts($selector)
### Description
Returns the text content of all elements matching the selector, in the order they appear in the page.
### Method
Pest expectation method
### Endpoint
`texts($selector)`
### Parameters
- **$selector** (string) - Required - CSS selector for elements.
### Usage Example
```php
expect(html($page))->texts('[data-cart] [data-name]')->toBe(['Apple', 'Pear']);
```
### Response
Returns an array of text strings.
```
--------------------------------
### Use html() with within(), frame(), texts(), rawTexts(), attributes(), attributeValues()
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/resources/boost/skills/phpunit-pest-html-assertions/SKILL.md
Use `html($value)` to turn a page into an `Html` and chain methods like expectations. `within()` requires the region to appear exactly once or the test stops with `NotOneNode`; `frame()` treats an iframe's srcdoc as its own page; `texts()`, `rawTexts()`, and `attributes()` return values in page order; `attributeValues()` returns every attribute value of the region.
```php
use function SorgeIt\PhpunitPestHtmlAssertions\Pest\html;
// A region: the page holds it exactly once, or the test stops with NotOneNode. Every check after it looks inside it.
expect(html($response))->within('[data-cart]')
->toHaveSelectorCount('li', 3)
->not->toHaveSelector('[data-errors]');
// The srcdoc of an iframe, as a page of its own.
expect(html($response))->frame('iframe[data-preview]')->toHaveSelectorText('p', 'Hello');
// Values, in the order of the page.
expect(html($response))->texts('[data-cart] [data-name]')->toBe(['Apple', 'Pear']);
expect(html($response))->rawTexts('[data-note]')->toBe(["Line one\nLine two"]);
expect(html($response))->attributes('[data-item]', 'data-id')->toBe(['1', '2']);
// Every attribute value of the region.
expect(html($response)->attributeValues())->each->not->toContain('javascript:');
```
--------------------------------
### Html::rawTexts($selector)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Returns the raw text content of matching elements.
```APIDOC
## [PHP] Html::rawTexts($selector)
### Description
Returns the raw text content of matching elements.
### Method
Instance method
### Endpoint
`Html::rawTexts($selector)`
### Parameters
- **$selector** (string) - Required - CSS selector.
### Usage Example
```php
$rawTexts = $html->rawTexts('[data-note]');
```
### Response
Returns an array of raw text strings.
```
--------------------------------
### html($value)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
The `html()` function wraps a page into an `Html` object, enabling chainable assertions.
```APIDOC
## [PEST] html($value)
### Description
Turns a page into an `Html` object, enabling chainable assertions on the page's content.
### Method
Pest expectation helper
### Endpoint
`html($value)`
### Parameters
- **$value** (mixed) - Required - The page or HTML content to be wrapped.
### Usage Example
```php
use function SorgeIt\PhpunitPestHtmlAssertions\Pest\html;
expect(html($page))->within('[data-cart]')
->toHaveSelectorCount('li', 3)
->not->toHaveSelector('[data-errors]');
```
### Response
Returns an `Html` object that supports chainable assertion methods.
```
--------------------------------
### Html::text()
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Returns the text content of the region.
```APIDOC
## [PHP] Html::text()
### Description
Returns the text content of the region.
### Method
Instance method
### Endpoint
`Html::text()`
### Usage Example
```php
$text = $html->text();
```
### Response
Returns a string.
```
--------------------------------
### within($selector)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Defines a region within the page, scoping subsequent assertions to that region.
```APIDOC
## [PEST] within($selector)
### Description
Defines a region within the page. The region must exist exactly once, otherwise the test stops with `NotOneNode`. All subsequent checks are scoped to this region.
### Method
Pest expectation method
### Endpoint
`within($selector)`
### Parameters
- **$selector** (string) - Required - CSS selector identifying the region.
### Usage Example
```php
expect(html($page))->within('[data-cart]')
->toHaveSelectorCount('li', 3)
->not->toHaveSelector('[data-errors]');
```
### Response
Returns the `Html` object for further chaining.
```
--------------------------------
### rawTexts($selector)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Retrieves the raw text content of matching elements, preserving whitespace.
```APIDOC
## [PEST] rawTexts($selector)
### Description
Returns the raw text content (including whitespace and line breaks) of all matching elements.
### Method
Pest expectation method
### Endpoint
`rawTexts($selector)`
### Parameters
- **$selector** (string) - Required - CSS selector for elements.
### Usage Example
```php
expect(html($page))->rawTexts('[data-note]')->toBe(["Line one\nLine two"]);
```
### Response
Returns an array of raw text strings.
```
--------------------------------
### Html::attributes($selector, $attribute)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Returns attribute values for matching elements.
```APIDOC
## [PHP] Html::attributes($selector, $attribute)
### Description
Returns attribute values for matching elements.
### Method
Instance method
### Endpoint
`Html::attributes($selector, $attribute)`
### Parameters
- **$selector** (string) - Required - CSS selector.
- **$attribute** (string) - Required - Attribute name.
### Usage Example
```php
$attributes = $html->attributes('[data-item]', 'data-id');
```
### Response
Returns an array of attribute values.
```
--------------------------------
### Html::texts($selector)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Returns the text content of matching elements.
```APIDOC
## [PHP] Html::texts($selector)
### Description
Returns the text content of matching elements.
### Method
Instance method
### Endpoint
`Html::texts($selector)`
### Parameters
- **$selector** (string) - Required - CSS selector.
### Usage Example
```php
$texts = $html->texts('[data-name]');
```
### Response
Returns an array of text strings.
```
--------------------------------
### Pest HTML assertions: toHaveSelector, toHaveText, toBeChecked, etc.
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/resources/boost/skills/phpunit-pest-html-assertions/SKILL.md
Pest expectations for HTML assertions. Use `toBeEmptyNode`, not `toBeEmpty`, because Pest has its own `toBeEmpty`. The expectations are registered by Composer; `tests/Pest.php` needs no line.
```php
expect($response)->toHaveSelector('[data-cart]');
expect($response)->toHaveSelectorCount('[data-cart] li', 3);
expect($response)->toHaveSelectorCountAtLeast('li', 1);
expect($response)->toHaveSelectorText('h1', 'Orders');
expect($response)->toHaveSelectorTextContaining('h1', 'Ord');
expect($response)->toHaveAnySelectorText('li', 'Anna');
expect($response)->toHaveAnySelectorTextContaining('li', 'Ann');
expect($response)->toHaveSelectorAttribute('a[data-next]', 'href', '/page/2');
expect($response)->toHaveSelectorAttribute('button[data-send]', 'disabled');
expect($response)->toHaveSelectorAttributeContaining('a[data-next]', 'href', 'page=2');
expect($response)->toHaveSelectorAttributeNamed('main', 'wire:poll');
expect($response)->toHaveSelectorClass('[data-status]', 'bg-red-500');
expect($response)->toHaveText('Anna Ben');
expect($response)->toHaveTextContaining('Anna');
expect($response)->toHaveTextCount('Anna', 1);
expect($response)->toAppearBefore('[data-head]', '[data-body]');
expect($response)->toHaveTitle('Orders');
expect($response)->toHaveInputValue('email', 'anna@example.com');
expect($response)->toBeChecked('[data-agree]');
expect($response)->toHaveSelectedOption('[data-country]', 'de');
expect($response)->toBeDisabled('[data-send]');
expect($response)->toHaveLink('Next', '/page/2');
expect($response)->toBeEmptyNode('[data-errors]');
```
--------------------------------
### Html::frame($selector)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Accesses the content of an iframe as a separate page.
```APIDOC
## [PHP] Html::frame($selector)
### Description
Accesses the content of an iframe as a separate page.
### Method
Instance method
### Endpoint
`Html::frame($selector)`
### Parameters
- **$selector** (string) - Required - CSS selector for the iframe.
### Usage Example
```php
$html->frame('iframe[data-preview]');
```
### Response
Returns an `Html` instance for the iframe content.
```
--------------------------------
### Use Pest html() helper for region, frame, and value assertions
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Shows the Pest `html()` helper and its chainable methods for asserting on HTML pages. `within()` restricts checks to a region that must exist exactly once or the test stops with `NotOneNode`; `frame()` treats an iframe's srcdoc as a separate page; `texts()`, `rawTexts()`, and `attributes()` return arrays in page order; `eachMatch()` runs a closure on every match and stops with `NoMatch` if none; `attributeValues()` collects all attribute values. A negated check on a missing region always passes, but `within()` prevents that by failing on a missing region even under `->not`.
```php
use function SorgeIt\PhpunitPestHtmlAssertions\Pest\html;
// A region: the page holds it exactly once, or the test stops with NotOneNode. Every check after it looks inside it.
expect(html($page))->within('[data-cart]')
->toHaveSelectorCount('li', 3)
->not->toHaveSelector('[data-errors]');
// The srcdoc of an iframe, as a page of its own.
expect(html($page))->frame('iframe[data-preview]')->toHaveSelectorText('p', 'Hello');
// Values, in the order of the page.
expect(html($page))->texts('[data-cart] [data-name]')->toBe(['Apple', 'Pear']);
expect(html($page))->rawTexts('[data-note]')->toBe(["Line one\nLine two"]);
expect(html($page))->attributes('[data-item]', 'data-id')->toBe(['1', '2']);
// The same checks on every match. No match stops the test with NoMatch: a loop over nothing would check nothing.
// `:scope` is the match itself.
expect($page)->eachMatch('[data-avatar]', fn ($avatar) => $avatar->toHaveSelectorClass(':scope', 'rounded-full'));
// Every attribute value of the region, whatever the name of the attribute.
expect(html($page)->attributeValues())->each->not->toContain('javascript:');
```
--------------------------------
### Pass a custom message to toHaveSelectorCount and assertHtmlSelectorCount
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Shows how to pass a custom message to the count checks and the resulting failure output. The message appears first, followed by the package's failure text. Use this when you need to provide a reason for the assertion.
```php
expect($response)->toHaveSelectorCount('[data-cart] li', 3, 'The cart keeps the items of the last visit.');
self::assertHtmlSelectorCount($response, '[data-cart] li', 3, 'The cart keeps the items of the last visit.');
```
```text
The cart keeps the items of the last visit.
Failed asserting that (page) has 3 nodes matching "[data-cart] li".
The selector "[data-cart] li" finds 2 nodes.
…
```
--------------------------------
### Check a string holds a class with html.classAsString
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Shows three equivalent checks that the html.classAsString rule reports: a Pest expectation, a PHP function, and a selector-based assertion. The rule reports a check when it searches a string and passes when the class is found anywhere, including in comments or scripts.
```php
expect($html)->toContain('lg:grid-cols-4'); // reported
expect(str_contains($html, 'lg:grid-cols-4'))->toBeTrue(); // reported
expect($html)->toHaveSelectorClass('[data-highlights]', 'lg:grid-cols-4'); // the element has the class
```
--------------------------------
### Count zero nodes with toHaveSelectorCount()
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/resources/boost/skills/phpunit-pest-html-assertions/SKILL.md
To give a reason and a region when asserting absence, count zero nodes with `toHaveSelectorCount()`. Under `->not`, Pest lists the message among the arguments without the region.
```php
expect($response)->toHaveSelectorCount('[data-errors]', 0, 'A valid form shows no error.');
```
--------------------------------
### frame($selector)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Accesses the content of an iframe as a separate page for assertions.
```APIDOC
## [PEST] frame($selector)
### Description
Treats the `srcdoc` of an iframe as a page of its own, allowing assertions within the iframe content.
### Method
Pest expectation method
### Endpoint
`frame($selector)`
### Parameters
- **$selector** (string) - Required - CSS selector for the iframe element.
### Usage Example
```php
expect(html($page))->frame('iframe[data-preview]')->toHaveSelectorText('p', 'Hello');
```
### Response
Returns an `Html` object representing the iframe's content.
```
--------------------------------
### attributes($selector, $attribute)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Retrieves attribute values from matching elements.
```APIDOC
## [PEST] attributes($selector, $attribute)
### Description
Returns the values of a specified attribute for all matching elements, in page order.
### Method
Pest expectation method
### Endpoint
`attributes($selector, $attribute)`
### Parameters
- **$selector** (string) - Required - CSS selector for elements.
- **$attribute** (string) - Required - The attribute name to retrieve.
### Usage Example
```php
expect(html($page))->attributes('[data-item]', 'data-id')->toBe(['1', '2']);
```
### Response
Returns an array of attribute values.
```
--------------------------------
### Html::within($selector)
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Defines a region within the page for scoped operations.
```APIDOC
## [PHP] Html::within($selector)
### Description
Defines a region within the page, scoping subsequent operations to that region.
### Method
Instance method
### Endpoint
`Html::within($selector)`
### Parameters
- **$selector** (string) - Required - CSS selector for the region.
### Usage Example
```php
$html->within('[data-cart]');
```
### Response
Returns the `Html` instance for chaining.
```
--------------------------------
### Html::attributeValues()
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Returns all attribute values in the region.
```APIDOC
## [PHP] Html::attributeValues()
### Description
Returns all attribute values in the region.
### Method
Instance method
### Endpoint
`Html::attributeValues()`
### Usage Example
```php
$values = $html->attributeValues();
```
### Response
Returns an array of all attribute values.
```
--------------------------------
### Pest HTML Assertions
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/resources/boost/skills/phpunit-pest-html-assertions/SKILL.md
Pest expectations for HTML assertions on HTTP responses. Each expectation is a method call on the response object.
```APIDOC
## expect($response)->toHaveSelector('[data-cart]')
### Description
Asserts that the response HTML contains at least one element matching the given CSS selector.
### Method
Pest expectation
### Parameters
- **selector** (string) - Required - CSS selector to search for.
### Example
```php
expect($response)->toHaveSelector('[data-cart]');
```
## expect($response)->toHaveSelectorCount('[data-cart] li', 3)
### Description
Asserts that the response HTML contains exactly the given number of elements matching the selector.
### Parameters
- **selector** (string) - Required - CSS selector.
- **count** (int) - Required - Expected number of matching elements.
### Example
```php
expect($response)->toHaveSelectorCount('[data-cart] li', 3);
```
## expect($response)->toHaveSelectorCountAtLeast('li', 1)
### Description
Asserts that the response HTML contains at least the given number of elements matching the selector.
### Parameters
- **selector** (string) - Required - CSS selector.
- **count** (int) - Required - Minimum expected number of matching elements.
### Example
```php
expect($response)->toHaveSelectorCountAtLeast('li', 1);
```
## expect($response)->toHaveSelectorText('h1', 'Orders')
### Description
Asserts that the first element matching the selector has exactly the given text content.
### Parameters
- **selector** (string) - Required - CSS selector.
- **text** (string) - Required - Expected exact text.
### Example
```php
expect($response)->toHaveSelectorText('h1', 'Orders');
```
## expect($response)->toHaveSelectorTextContaining('h1', 'Ord')
### Description
Asserts that the first element matching the selector contains the given text.
### Parameters
- **selector** (string) - Required - CSS selector.
- **text** (string) - Required - Expected substring.
### Example
```php
expect($response)->toHaveSelectorTextContaining('h1', 'Ord');
```
## expect($response)->toHaveAnySelectorText('li', 'Anna')
### Description
Asserts that at least one element matching the selector has exactly the given text.
### Parameters
- **selector** (string) - Required - CSS selector.
- **text** (string) - Required - Expected exact text.
### Example
```php
expect($response)->toHaveAnySelectorText('li', 'Anna');
```
## expect($response)->toHaveAnySelectorTextContaining('li', 'Ann')
### Description
Asserts that at least one element matching the selector contains the given text.
### Parameters
- **selector** (string) - Required - CSS selector.
- **text** (string) - Required - Expected substring.
### Example
```php
expect($response)->toHaveAnySelectorTextContaining('li', 'Ann');
```
## expect($response)->toHaveSelectorAttribute('a[data-next]', 'href', '/page/2')
### Description
Asserts that the first element matching the selector has the given attribute with the exact value.
### Parameters
- **selector** (string) - Required - CSS selector.
- **attribute** (string) - Required - Attribute name.
- **value** (string) - Optional - Expected attribute value. If omitted, only presence is checked.
### Example
```php
expect($response)->toHaveSelectorAttribute('a[data-next]', 'href', '/page/2');
```
## expect($response)->toHaveSelectorAttribute('button[data-send]', 'disabled')
### Description
Asserts that the first element matching the selector has the given attribute (presence only).
### Parameters
- **selector** (string) - Required - CSS selector.
- **attribute** (string) - Required - Attribute name.
### Example
```php
expect($response)->toHaveSelectorAttribute('button[data-send]', 'disabled');
```
## expect($response)->toHaveSelectorAttributeContaining('a[data-next]', 'href', 'page=2')
### Description
Asserts that the first element matching the selector has the given attribute containing the given substring.
### Parameters
- **selector** (string) - Required - CSS selector.
- **attribute** (string) - Required - Attribute name.
- **value** (string) - Required - Expected substring.
### Example
```php
expect($response)->toHaveSelectorAttributeContaining('a[data-next]', 'href', 'page=2');
```
## expect($response)->toHaveSelectorAttributeNamed('main', 'wire:poll')
### Description
Asserts that the first element matching the selector has an attribute with the given name.
### Parameters
- **selector** (string) - Required - CSS selector.
- **attribute** (string) - Required - Attribute name.
### Example
```php
expect($response)->toHaveSelectorAttributeNamed('main', 'wire:poll');
```
## expect($response)->toHaveSelectorClass('[data-status]', 'bg-red-500')
### Description
Asserts that the first element matching the selector has the given CSS class.
### Parameters
- **selector** (string) - Required - CSS selector.
- **class** (string) - Required - Expected CSS class.
### Example
```php
expect($response)->toHaveSelectorClass('[data-status]', 'bg-red-500');
```
## expect($response)->toHaveText('Anna Ben')
### Description
Asserts that the response HTML contains the given exact text.
### Parameters
- **text** (string) - Required - Expected exact text.
### Example
```php
expect($response)->toHaveText('Anna Ben');
```
## expect($response)->toHaveTextContaining('Anna')
### Description
Asserts that the response HTML contains the given substring.
### Parameters
- **text** (string) - Required - Expected substring.
### Example
```php
expect($response)->toHaveTextContaining('Anna');
```
## expect($response)->toHaveTextCount('Anna', 1)
### Description
Asserts that the response HTML contains the given text exactly the given number of times.
### Parameters
- **text** (string) - Required - Text to count.
- **count** (int) - Required - Expected number of occurrences.
### Example
```php
expect($response)->toHaveTextCount('Anna', 1);
```
## expect($response)->toAppearBefore('[data-head]', '[data-body]')
### Description
Asserts that the first element matching the first selector appears before the first element matching the second selector in the HTML.
### Parameters
- **firstSelector** (string) - Required - CSS selector for the first element.
- **secondSelector** (string) - Required - CSS selector for the second element.
### Example
```php
expect($response)->toAppearBefore('[data-head]', '[data-body]');
```
## expect($response)->toHaveTitle('Orders')
### Description
Asserts that the response HTML has a `` element with the given exact text.
### Parameters
- **title** (string) - Required - Expected title text.
### Example
```php
expect($response)->toHaveTitle('Orders');
```
## expect($response)->toHaveInputValue('email', 'anna@example.com')
### Description
Asserts that the input element with the given name has the given value.
### Parameters
- **name** (string) - Required - Input name attribute.
- **value** (string) - Required - Expected input value.
### Example
```php
expect($response)->toHaveInputValue('email', 'anna@example.com');
```
## expect($response)->toBeChecked('[data-agree]')
### Description
Asserts that the element matching the selector is checked (checkbox or radio).
### Parameters
- **selector** (string) - Required - CSS selector.
### Example
```php
expect($response)->toBeChecked('[data-agree]');
```
## expect($response)->toHaveSelectedOption('[data-country]', 'de')
### Description
Asserts that the select element matching the selector has the given option selected.
### Parameters
- **selector** (string) - Required - CSS selector.
- **value** (string) - Required - Expected selected option value.
### Example
```php
expect($response)->toHaveSelectedOption('[data-country]', 'de');
```
## expect($response)->toBeDisabled('[data-send]')
### Description
Asserts that the element matching the selector is disabled.
### Parameters
- **selector** (string) - Required - CSS selector.
### Example
```php
expect($response)->toBeDisabled('[data-send]');
```
## expect($response)->toHaveLink('Next', '/page/2')
### Description
Asserts that the response HTML contains a link with the given text and href.
### Parameters
- **text** (string) - Required - Link text.
- **href** (string) - Required - Expected href attribute.
### Example
```php
expect($response)->toHaveLink('Next', '/page/2');
```
## expect($response)->toBeEmptyNode('[data-errors]')
### Description
Asserts that the element matching the selector is empty (no child nodes or text).
### Parameters
- **selector** (string) - Required - CSS selector.
### Example
```php
expect($response)->toBeEmptyNode('[data-errors]');
```
```
--------------------------------
### Pest: toHaveSelectorCount and toHaveAnySelectorText
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Pest expectation that asserts the response has exactly 3 elements matching '[data-cart] li' and that at least one of those elements contains the text 'Apple'. Use inside a Pest test.
```php
it('lists the items of the cart', function () {
expect($this->get('/cart'))
->toHaveSelectorCount('[data-cart] li', 3)
->toHaveAnySelectorText('[data-cart] li', 'Apple');
});
```
--------------------------------
### PHPUnit Trait AssertsHtml
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/resources/boost/skills/phpunit-pest-html-assertions/SKILL.md
PHPUnit trait with equivalent assertion methods for HTML checks.
```APIDOC
## PHPUnit Trait Methods
### Description
The trait `SorgeIt\PhpunitPestHtmlAssertions\PHPUnit\AssertsHtml` provides the same checks as methods, for example `assertHtmlSelectorExists`, `assertHtmlSelectorTextSame` and `assertHtmlSelectorAttribute`.
### Methods
- **assertHtmlSelectorExists** - Asserts that a selector exists.
- **assertHtmlSelectorTextSame** - Asserts that the selector text is the same.
- **assertHtmlSelectorAttribute** - Asserts that the selector has an attribute.
### Usage
Use the trait in your PHPUnit test class to access these methods.
```
--------------------------------
### Pass reason as message parameter to PHPUnit/Pest HTML assertions
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/resources/boost/skills/phpunit-pest-html-assertions/SKILL.md
Pass the reason for a check as the last parameter `$message` (or by name after the optional `$value` for `toHaveSelectorAttribute()`). A failure shows the message first. `within()` and `frame()` take no message.
```php
expect($response)->toHaveSelectorCount('[data-cart] li', 3, 'The cart keeps the items of the last visit.');
expect($response)->toHaveSelectorAttribute('button[data-send]', 'disabled', message: 'The form waits for the consent.');
```
--------------------------------
### Enable camelCaseClasses in PHPStan configuration
Source: https://github.com/sorge-it/phpunit-pest-html-assertions/blob/main/README.md
Configuration for PHPStan to enable camelCase class detection in the html.classAsString rule. Use this when your project writes classes in camelCase, otherwise camelCase in tests is usually a JavaScript or PHP name.
```neon
parameters:
htmlAssertions:
camelCaseClasses: true
```