Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[develop] Adds PHPUnit 11 support #175

Merged
merged 3 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ jobs:
strategy:
fail-fast: true
matrix:
php: [8.1, 8.2, 8.3]
php: [8.2, 8.3]
phpunit: [10, 11]
laravel: [10, 11]
exclude:
- php: 8.1
laravel: 11
- phpunit: 11
laravel: 10

name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }}
name: PHP ${{ matrix.php }} - PHPUnit ${{ matrix.phpunit }} - Laravel ${{ matrix.laravel }}

steps:
- name: Checkout code
Expand All @@ -40,6 +41,7 @@ jobs:

- name: Install dependencies
run: |
composer require phpunit/phpunit:^${{ matrix.phpunit }} --no-update
composer require "laravel/framework=^${{ matrix.laravel }}" --no-update
composer update --prefer-dist --no-interaction --no-progress

Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@
}
],
"require": {
"php": "^8.1",
"php": "^8.2",
"ext-dom": "*",
"illuminate/contracts": "^10.0|^11.0",
"illuminate/database": "^10.0|^11.0",
"illuminate/http": "^10.0|^11.0",
"illuminate/support": "^10.0|^11.0",
"illuminate/testing": "^10.0|^11.0",
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^10.0.7",
"phpunit/phpunit": "^10.4|^11.0",
"symfony/console": "^6.2|^7.0",
"symfony/css-selector": "^6.2|^7.0",
"symfony/dom-crawler": "^6.2|^7.0",
Expand Down
82 changes: 82 additions & 0 deletions src/Constraints/Concerns/FormFieldConstraint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace Laravel\BrowserKitTesting\Constraints\Concerns;

use Symfony\Component\DomCrawler\Crawler;

trait FormFieldConstraint
{
/**
* The name or ID of the element.
*
* @var string
*/
protected readonly string $selector;

/**
* The expected value.
*
* @var string
*/
protected readonly string $value;

/**
* Create a new constraint instance.
*
* @param string $selector
* @param mixed $value
* @return void
*/
public function __construct($selector, $value)
{
$this->selector = $selector;
$this->value = (string) $value;
}

/**
* Get the valid elements.
*
* Multiple elements should be separated by commas without spaces.
*
* @return string
*/
abstract protected function validElements();

/**
* Get the form field.
*
* @param \Symfony\Component\DomCrawler\Crawler $crawler
* @return \Symfony\Component\DomCrawler\Crawler
*
* @throws \PHPUnit\Framework\ExpectationFailedException
*/
protected function field(Crawler $crawler)
{
$field = $crawler->filter(implode(', ', $this->getElements()));

if ($field->count() > 0) {
return $field;
}

$this->fail($crawler, sprintf(
'There is no %s with the name or ID [%s]',
$this->validElements(), $this->selector
));
}

/**
* Get the elements relevant to the selector.
*
* @return array
*/
protected function getElements()
{
$name = str_replace('#', '', $this->selector);

$id = str_replace(['[', ']'], ['\\[', '\\]'], $name);

return collect(explode(',', $this->validElements()))->map(function ($element) use ($name, $id) {
return "{$element}#{$id}, {$element}[name='{$name}']";
})->all();
}
}
99 changes: 99 additions & 0 deletions src/Constraints/Concerns/HasElement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

namespace Laravel\BrowserKitTesting\Constraints\Concerns;

use Symfony\Component\DomCrawler\Crawler;

trait HasElement
{
/**
* The name or ID of the element.
*
* @var string
*/
protected readonly string $selector;

/**
* The attributes the element should have.
*
* @var array
*/
protected readonly array $attributes;

/**
* Create a new constraint instance.
*
* @param string $selector
* @param array $attributes
* @return void
*/
public function __construct($selector, array $attributes = [])
{
$this->selector = $selector;
$this->attributes = $attributes;
}

/**
* Check if the element is found in the given crawler.
*
* @param \Symfony\Component\DomCrawler\Crawler|string $crawler
* @return bool
*/
public function matches($crawler): bool
{
$elements = $this->crawler($crawler)->filter($this->selector);

if ($elements->count() == 0) {
return false;
}

if (empty($this->attributes)) {
return true;
}

$elements = $elements->reduce(function ($element) {
return $this->hasAttributes($element);
});

return $elements->count() > 0;
}

/**
* Determines if the given element has the attributes.
*
* @param \Symfony\Component\DomCrawler\Crawler $element
* @return bool
*/
protected function hasAttributes(Crawler $element)
{
foreach ($this->attributes as $name => $value) {
if (is_numeric($name)) {
if (is_null($element->attr($value))) {
return false;
}
} else {
if ($element->attr($name) != $value) {
return false;
}
}
}

return true;
}

/**
* Returns a string representation of the object.
*
* @return string
*/
public function toString(): string
{
$message = "the element [{$this->selector}]";

if (! empty($this->attributes)) {
$message .= ' with the attributes '.json_encode($this->attributes);
}

return $message;
}
}
78 changes: 78 additions & 0 deletions src/Constraints/Concerns/HasInElement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace Laravel\BrowserKitTesting\Constraints\Concerns;

use Symfony\Component\DomCrawler\Crawler;

trait HasInElement
{
/**
* The name or ID of the element.
*
* @var string
*/
protected readonly string $element;

/**
* The text expected to be found.
*
* @var string
*/
protected readonly string $text;

/**
* Create a new constraint instance.
*
* @param string $element
* @param string $text
* @return void
*/
public function __construct($element, $text)
{
$this->text = $text;
$this->element = $element;
}

/**
* Check if the source or text is found within the element in the given crawler.
*
* @param \Symfony\Component\DomCrawler\Crawler|string $crawler
* @return bool
*/
public function matches($crawler): bool
{
$elements = $this->crawler($crawler)->filter($this->element);

$pattern = $this->getEscapedPattern($this->text);

foreach ($elements as $element) {
$element = new Crawler($element);

if (preg_match("/$pattern/i", $element->html())) {
return true;
}
}

return false;
}

/**
* Returns the description of the failure.
*
* @return string
*/
protected function getFailureDescription()
{
return sprintf('[%s] contains %s', $this->element, $this->text);
}

/**
* Returns the reversed description of the failure.
*
* @return string
*/
protected function getReverseFailureDescription()
{
return sprintf('[%s] does not contain %s', $this->element, $this->text);
}
}
Loading