Skip to content

Remove PHP 8.1 Support #211

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

Merged
merged 1 commit into from
May 28, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php: [8.1, 8.2, 8.3, 8.4]
php: [8.2, 8.3, 8.4]
symfony: ["5.4.*", "6.4.*", "7.2.*"]
exclude:
- php: 8.1
Expand Down
19 changes: 11 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
{
"name": "codeception/module-symfony",
"description": "Codeception module for Symfony framework",
"license": "MIT",
"type": "library",
"license": "MIT",
"keywords": [
"codeception",
"functional testing",
"symfony"
],
"homepage": "https://codeception.com/",
"support": {
"docs": "https://codeception.com/docs/modules/Symfony"
},
"authors": [
{
"name": "Michael Bodnarchuk"
Expand All @@ -17,17 +21,16 @@
"homepage": "https://medium.com/@ganieves"
}
],
"homepage": "https://codeception.com/",
"require": {
"php": "^8.1",
"php": "^8.2",
"ext-json": "*",
"codeception/codeception": "^5.0.8",
"codeception/lib-innerbrowser": "^3.1.1 | ^4.0"
"codeception/codeception": "^5.3",
"codeception/lib-innerbrowser": "^3.1 | ^4.0"
},
"require-dev": {
"codeception/module-asserts": "^3.0",
"codeception/module-doctrine": "^3.1",
"doctrine/orm": "^2.10",
"doctrine/orm": "^2.20",
"symfony/browser-kit": "^5.4 | ^6.4 | ^7.2",
"symfony/cache": "^5.4 | ^6.4 | ^7.2",
"symfony/config": "^5.4 | ^6.4 | ^7.2",
Expand Down Expand Up @@ -62,12 +65,12 @@
"codeception/module-asserts": "Include traditional PHPUnit assertions in your tests",
"symfony/web-profiler-bundle": "Tool that gives information about the execution of requests"
},
"minimum-stability": "RC",
"autoload": {
"classmap": ["src/"]
},
"config": {
"classmap-authoritative": true,
"sort-packages": true
}
},
"minimum-stability": "RC"
}
9 changes: 6 additions & 3 deletions src/Codeception/Module/Symfony/BrowserAssertionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,16 @@ public function assertResponseStatusCodeSame(int $expectedCode, string $message
* <?php
* $I->assertRouteSame('profile', ['id' => 123]);
* ```
*
* @param array<string, bool|float|int|null|string> $parameters
*/
public function assertRouteSame(string $expectedRoute, array $parameters = [], string $message = ''): void {
public function assertRouteSame(string $expectedRoute, array $parameters = [], string $message = ''): void
{
$request = $this->getClient()->getRequest();
$this->assertThat($request, new RequestAttributeValueSame('_route', $expectedRoute));

foreach ($parameters as $key => $value) {
$this->assertThat($request, new RequestAttributeValueSame($key, $value), $message);
$this->assertThat($request, new RequestAttributeValueSame($key, (string)$value), $message);
}
}

Expand Down Expand Up @@ -349,7 +352,7 @@ public function seePageRedirectsTo(string $page, string $redirectsTo): void
* ]);
* ```
*
* @param string $name The `name` attribute of the `<form>`. You cannot use an array as a selector here.
* @param string $name The `name` attribute of the `<form>`. You cannot use an array as a selector here.
* @param array<string, mixed> $fields The form fields to submit.
*/
public function submitSymfonyForm(string $name, array $fields): void
Expand Down
74 changes: 38 additions & 36 deletions src/Codeception/Module/Symfony/ConsoleAssertionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\HttpKernel\KernelInterface;

use function in_array;
use function sprintf;

trait ConsoleAssertionsTrait
{
/**
Expand All @@ -20,40 +23,42 @@ trait ConsoleAssertionsTrait
* $result = $I->runSymfonyConsoleCommand('hello:world', ['arg' => 'argValue', 'opt1' => 'optValue'], ['input']);
* ```
*
* @param string $command The console command to execute
* @param array $parameters Parameters (arguments and options) to pass to the command
* @param array $consoleInputs Console inputs (e.g. used for interactive questions)
* @param int $expectedExitCode The expected exit code of the command
* @return string Returns the console output of the command
* @param string $command The console command to execute.
* @param array<string, int|string> $parameters Arguments and options passed to the command
* @param list<string> $consoleInputs Inputs for interactive questions.
* @param int $expectedExitCode Expected exit code.
* @return string Console output (stdout).
*/
public function runSymfonyConsoleCommand(string $command, array $parameters = [], array $consoleInputs = [], int $expectedExitCode = 0): string
{
$kernel = $this->grabKernelService();
$application = new Application($kernel);
$consoleCommand = $application->find($command);
$commandTester = new CommandTester($consoleCommand);
public function runSymfonyConsoleCommand(
string $command,
array $parameters = [],
array $consoleInputs = [],
int $expectedExitCode = 0
): string {
$kernel = $this->grabKernelService();
$application = new Application($kernel);
$consoleCommand = $application->find($command);
$commandTester = new CommandTester($consoleCommand);
$commandTester->setInputs($consoleInputs);

$input = ['command' => $command] + $parameters;
$options = $this->configureOptions($parameters);

$input = ['command' => $command] + $parameters;
$options = $this->configureOptions($parameters);
$exitCode = $commandTester->execute($input, $options);
$output = $commandTester->getDisplay();
$output = $commandTester->getDisplay();

$this->assertSame(
$expectedExitCode,
$exitCode,
sprintf(
'Command did not exit with code %d but with %d: %s',
$expectedExitCode,
$exitCode,
$output
)
sprintf('Command exited with %d instead of expected %d. Output: %s', $exitCode, $expectedExitCode, $output)
);

return $output;
}

/**
* @param array<string, int|string|bool> $parameters
* @return array<string, mixed> Options array supported by CommandTester.
*/
private function configureOptions(array $parameters): array
{
$options = [];
Expand All @@ -69,27 +74,24 @@ private function configureOptions(array $parameters): array
}

if (in_array('--quiet', $parameters, true) || in_array('-q', $parameters, true)) {
$options['verbosity'] = OutputInterface::VERBOSITY_QUIET;
$options['verbosity'] = OutputInterface::VERBOSITY_QUIET;
$options['interactive'] = false;
}

if (
in_array('-vvv', $parameters, true) ||
in_array('--verbose=3', $parameters, true) ||
(isset($parameters["--verbose"]) && $parameters["--verbose"] === 3)
if (in_array('-vvv', $parameters, true)
|| in_array('--verbose=3', $parameters, true)
|| (isset($parameters['--verbose']) && $parameters['--verbose'] === 3)
) {
$options['verbosity'] = OutputInterface::VERBOSITY_DEBUG;
} elseif (
in_array('-vv', $parameters, true) ||
in_array('--verbose=2', $parameters, true) ||
(isset($parameters["--verbose"]) && $parameters["--verbose"] === 2)
} elseif (in_array('-vv', $parameters, true)
|| in_array('--verbose=2', $parameters, true)
|| (isset($parameters['--verbose']) && $parameters['--verbose'] === 2)
) {
$options['verbosity'] = OutputInterface::VERBOSITY_VERY_VERBOSE;
} elseif (
in_array('-v', $parameters, true) ||
in_array('--verbose=1', $parameters, true) ||
in_array('--verbose', $parameters, true) ||
(isset($parameters["--verbose"]) && $parameters["--verbose"] === 1)
} elseif (in_array('-v', $parameters, true)
|| in_array('--verbose=1', $parameters, true)
|| in_array('--verbose', $parameters, true)
|| (isset($parameters['--verbose']) && $parameters['--verbose'] === 1)
) {
$options['verbosity'] = OutputInterface::VERBOSITY_VERBOSE;
}
Expand All @@ -101,4 +103,4 @@ protected function grabKernelService(): KernelInterface
{
return $this->grabService('kernel');
}
}
}
16 changes: 10 additions & 6 deletions src/Codeception/Module/Symfony/DomCrawlerAssertionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ public function assertCheckboxChecked(string $fieldName, string $message = ''):
*/
public function assertCheckboxNotChecked(string $fieldName, string $message = ''): void
{
$this->assertThatCrawler(new LogicalNot(
new CrawlerSelectorExists("input[name=\"$fieldName\"]:checked")
), $message);
$this->assertThatCrawler(
new LogicalNot(
new CrawlerSelectorExists("input[name=\"$fieldName\"]:checked")
), $message
);
}

/**
Expand All @@ -52,9 +54,11 @@ public function assertCheckboxNotChecked(string $fieldName, string $message = ''
public function assertInputValueNotSame(string $fieldName, string $expectedValue, string $message = ''): void
{
$this->assertThatCrawler(new CrawlerSelectorExists("input[name=\"$fieldName\"]"), $message);
$this->assertThatCrawler(new LogicalNot(
new CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue)
), $message);
$this->assertThatCrawler(
new LogicalNot(
new CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue)
), $message
);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/Codeception/Module/Symfony/MimeAssertionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace Codeception\Module\Symfony;

use PHPUnit\Framework\Assert;
use PHPUnit\Framework\Constraint\LogicalNot;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\RawMessage;
use Symfony\Component\Mime\Test\Constraint as MimeConstraint;

trait MimeAssertionsTrait
Expand Down Expand Up @@ -171,8 +171,8 @@ private function verifyEmailObject(?Email $email, string $function): Email
{
$email = $email ?: $this->grabLastSentEmail();
$errorMsgTemplate = "There is no email to verify. An Email object was not specified when invoking '%s' and the application has not sent one.";
return $email ?: $this->fail(
return $email ?? Assert::fail(
sprintf($errorMsgTemplate, $function)
);
}
}
}
7 changes: 5 additions & 2 deletions src/Codeception/Module/Symfony/ServicesAssertionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Codeception\Module\Symfony;

use Codeception\Lib\Connector\Symfony as SymfonyConnector;
use PHPUnit\Framework\Assert;

trait ServicesAssertionsTrait
{
Expand All @@ -24,8 +25,10 @@ trait ServicesAssertionsTrait
public function grabService(string $serviceId): object
{
if (!$service = $this->getService($serviceId)) {
$this->fail("Service `{$serviceId}` is required by Codeception, but not loaded by Symfony since you're not using it anywhere in your app.\n
Recommended solution: Set it to `public` in your `config/services_test.php`/`.yaml`, see https://symfony.com/doc/current/service_container/alias_private.html#marking-services-as-public-private");
Assert::fail(
"Service `{$serviceId}` is required by Codeception, but not loaded by Symfony since you're not using it anywhere in your app.\n
Recommended solution: Set it to `public` in your `config/services_test.php`/`.yaml`, see https://symfony.com/doc/current/service_container/alias_private.html#marking-services-as-public-private"
);
}

return $service;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public function seeDefaultLocaleIs(string $expectedLocale): void
* $I->seeFallbackLocalesAre(['es', 'fr']);
* ```
*
* @param array $expectedLocales The expected fallback locales
* @param string[] $expectedLocales The expected fallback locales
*/
public function seeFallbackLocalesAre(array $expectedLocales): void
{
Expand Down
2 changes: 1 addition & 1 deletion src/Codeception/Module/Symfony/TwigAssertionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ protected function grabTwigCollector(string $function): TwigDataCollector
{
return $this->grabCollector('twig', $function);
}
}
}
16 changes: 8 additions & 8 deletions src/Codeception/Module/Symfony/ValidatorAssertionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ trait ValidatorAssertionsTrait
* $I->dontSeeViolatedConstraint($subject, 'propertyName', 'Symfony\Validator\ConstraintClass');
* ```
*/
public function dontSeeViolatedConstraint(mixed $subject, ?string $propertyPath = null, ?string $constraint = null): void
public function dontSeeViolatedConstraint(object $subject, ?string $propertyPath = null, ?string $constraint = null): void
{
$violations = $this->getViolationsForSubject($subject, $propertyPath, $constraint);
$this->assertCount(0, $violations, 'Constraint violations found.');
Expand All @@ -37,7 +37,7 @@ public function dontSeeViolatedConstraint(mixed $subject, ?string $propertyPath
* $I->seeViolatedConstraint($subject, 'propertyName', 'Symfony\Validator\ConstraintClass');
* ```
*/
public function seeViolatedConstraint(mixed $subject, ?string $propertyPath = null, ?string $constraint = null): void
public function seeViolatedConstraint(object $subject, ?string $propertyPath = null, ?string $constraint = null): void
{
$violations = $this->getViolationsForSubject($subject, $propertyPath, $constraint);
$this->assertNotCount(0, $violations, 'No constraint violations found.');
Expand All @@ -52,7 +52,7 @@ public function seeViolatedConstraint(mixed $subject, ?string $propertyPath = nu
* $I->seeViolatedConstraintsCount(2, $subject, 'propertyName');
* ```
*/
public function seeViolatedConstraintsCount(int $expected, mixed $subject, ?string $propertyPath = null, ?string $constraint = null): void
public function seeViolatedConstraintsCount(int $expected, object $subject, ?string $propertyPath = null, ?string $constraint = null): void
{
$violations = $this->getViolationsForSubject($subject, $propertyPath, $constraint);
$this->assertCount($expected, $violations);
Expand All @@ -66,12 +66,12 @@ public function seeViolatedConstraintsCount(int $expected, mixed $subject, ?stri
* $I->seeViolatedConstraintMessage('too short', $user, 'address');
* ```
*/
public function seeViolatedConstraintMessage(string $expected, mixed $subject, string $propertyPath): void
public function seeViolatedConstraintMessage(string $expected, object $subject, string $propertyPath): void
{
$violations = $this->getViolationsForSubject($subject, $propertyPath);
$containsExpected = false;
foreach ($violations as $violation) {
if ($violation->getPropertyPath() === $propertyPath && str_contains($violation->getMessage(), $expected)) {
if ($violation->getPropertyPath() === $propertyPath && str_contains((string)$violation->getMessage(), $expected)) {
$containsExpected = true;
break;
}
Expand All @@ -81,17 +81,17 @@ public function seeViolatedConstraintMessage(string $expected, mixed $subject, s
}

/** @return ConstraintViolationInterface[] */
protected function getViolationsForSubject(mixed $subject, ?string $propertyPath = null, ?string $constraint = null): array
protected function getViolationsForSubject(object $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(
return (array)array_filter(
$violations,
static fn($violation): bool => $violation->getConstraint()::class === $constraint &&
static fn(ConstraintViolationInterface $violation): bool => get_class((object)$violation->getConstraint()) === $constraint &&
($propertyPath === null || $violation->getPropertyPath() === $propertyPath)
);
}
Expand Down