Skip to content

Commit

Permalink
Added Symfony validator assertions (#189)
Browse files Browse the repository at this point in the history
  • Loading branch information
TavoNiievez committed Apr 5, 2024
1 parent 3bbf45c commit 36e08c9
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
1 change: 1 addition & 0 deletions composer.json
Expand Up @@ -49,6 +49,7 @@
"symfony/security-csrf": "^5.4 | ^6.4 | ^7.0",
"symfony/security-http": "^5.4 | ^6.4 | ^7.0",
"symfony/twig-bundle": "^5.4 | ^6.4 | ^7.0",
"symfony/validator": "^5.4 | ^6.4 | ^7.0",
"symfony/var-exporter": "^5.4 | ^6.4 | ^7.0",
"vlucas/phpdotenv": "^4.2 | ^5.4"
},
Expand Down
2 changes: 2 additions & 0 deletions src/Codeception/Module/Symfony.php
Expand Up @@ -24,6 +24,7 @@
use Codeception\Module\Symfony\SessionAssertionsTrait;
use Codeception\Module\Symfony\TimeAssertionsTrait;
use Codeception\Module\Symfony\TwigAssertionsTrait;
use Codeception\Module\Symfony\ValidatorAssertionsTrait;
use Codeception\TestInterface;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
Expand Down Expand Up @@ -145,6 +146,7 @@ class Symfony extends Framework implements DoctrineProvider, PartedModule
use SessionAssertionsTrait;
use TimeAssertionsTrait;
use TwigAssertionsTrait;
use ValidatorAssertionsTrait;

public Kernel $kernel;

Expand Down
106 changes: 106 additions & 0 deletions src/Codeception/Module/Symfony/ValidatorAssertionsTrait.php
@@ -0,0 +1,106 @@
<?php

declare(strict_types=1);

namespace Codeception\Module\Symfony;

use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;

trait ValidatorAssertionsTrait
{
/**
* Asserts that the given subject fails validation.
* This assertion does not concern the exact number of violations.
*
* ```php
* <?php
* $I->dontSeeViolatedConstraint($subject);
* $I->dontSeeViolatedConstraint($subject, 'propertyName');
* $I->dontSeeViolatedConstraint($subject, 'propertyName', 'Symfony\Validator\ConstraintClass');
* ```
*/
public function dontSeeViolatedConstraint(mixed $subject, ?string $propertyPath = null, ?string $constraint = null): void
{
$violations = $this->getViolationsForSubject($subject, $propertyPath, $constraint);
$this->assertCount(0, $violations, 'Constraint violations found.');
}

/**
* Asserts that the given subject passes validation.
* This assertion does not concern the exact number of violations.
*
* ```php
* <?php
* $I->seeViolatedConstraint($subject);
* $I->seeViolatedConstraint($subject, 'propertyName');
* $I->seeViolatedConstraint($subject, 'propertyName', 'Symfony\Validator\ConstraintClass');
* ```
*/
public function seeViolatedConstraint(mixed $subject, ?string $propertyPath = null, ?string $constraint = null): void
{
$violations = $this->getViolationsForSubject($subject, $propertyPath, $constraint);
$this->assertNotCount(0, $violations, 'No constraint violations found.');
}

/**
* Asserts the exact number of violations for the given subject.
*
* ```php
* <?php
* $I->seeViolatedConstraintsCount(3, $subject);
* $I->seeViolatedConstraintsCount(2, $subject, 'propertyName');
* ```
*/
public function seeViolatedConstraintsCount(int $expected, mixed $subject, ?string $propertyPath = null, ?string $constraint = null): void
{
$violations = $this->getViolationsForSubject($subject, $propertyPath, $constraint);
$this->assertCount($expected, $violations);
}

/**
* Asserts that a constraint violation message or a part of it is present in the subject's violations.
*
* ```php
* <?php
* $I->seeViolatedConstraintMessage('too short', $user, 'address');
* ```
*/
public function seeViolatedConstraintMessage(string $expected, mixed $subject, string $propertyPath): void
{
$violations = $this->getViolationsForSubject($subject, $propertyPath);
$containsExpected = false;
foreach ($violations as $violation) {
if ($violation->getPropertyPath() === $propertyPath && str_contains($violation->getMessage(), $expected)) {
$containsExpected = true;
break;
}
}

$this->assertTrue($containsExpected, 'The violation messages do not contain: ' . $expected);
}

/** @return ConstraintViolationInterface[] */
protected function getViolationsForSubject(mixed $subject, ?string $propertyPath = null, ?string $constraint = null): array
{
$validator = $this->getValidatorService();
$violations = $propertyPath ? $validator->validateProperty($subject, $propertyPath) : $validator->validate($subject);

$violations = iterator_to_array($violations);

if ($constraint !== null) {
return array_filter(
$violations,
static fn($violation): bool => $violation->getConstraint()::class === $constraint &&
($propertyPath === null || $violation->getPropertyPath() === $propertyPath)
);
}

return $violations;
}

protected function getValidatorService(): ValidatorInterface
{
return $this->grabService(ValidatorInterface::class);
}
}

0 comments on commit 36e08c9

Please sign in to comment.