From e11bf68e2e720bccfc1d449bf86e4bc7155c0b2a Mon Sep 17 00:00:00 2001 From: Aaron Gustavo Nieves <64917965+TavoNiievez@users.noreply.github.com> Date: Tue, 25 Mar 2025 16:17:07 -0500 Subject: [PATCH 1/6] Document new Symfony assertions (#208) --- .../Module/Symfony/BrowserAssertionsTrait.php | 87 ++++++++++++++++++- .../Symfony/DomCrawlerAssertionsTrait.php | 55 ++++++++++++ .../Module/Symfony/FormAssertionsTrait.php | 17 +++- .../Symfony/HttpClientAssertionsTrait.php | 23 ++++- .../Module/Symfony/MailerAssertionsTrait.php | 59 +++++++++++-- 5 files changed, 226 insertions(+), 15 deletions(-) diff --git a/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php b/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php index 488e1976..fbd8a075 100644 --- a/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php @@ -25,6 +25,11 @@ trait BrowserAssertionsTrait { /** * Asserts that the given cookie in the test client is set to the expected value. + * + * ```php + * assertBrowserCookieValueSame('cookie_name', 'expected_value'); + * ``` */ public function assertBrowserCookieValueSame(string $name, string $expectedValue, bool $raw = false, string $path = '/', ?string $domain = null, string $message = ''): void { @@ -35,6 +40,11 @@ public function assertBrowserCookieValueSame(string $name, string $expectedValue /** * Asserts that the test client has the specified cookie set. * This indicates that the cookie was set by any response during the test. + * + * ``` + * assertBrowserHasCookie('cookie_name'); + * ``` */ public function assertBrowserHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void { @@ -44,6 +54,11 @@ public function assertBrowserHasCookie(string $name, string $path = '/', ?string /** * Asserts that the test client does not have the specified cookie set. * This indicates that the cookie was not set by any response during the test. + * + * ```php + * assertBrowserNotHasCookie('cookie_name'); + * ``` */ public function assertBrowserNotHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void { @@ -52,6 +67,11 @@ public function assertBrowserNotHasCookie(string $name, string $path = '/', ?str /** * Asserts that the specified request attribute matches the expected value. + * + * ```php + * assertRequestAttributeValueSame('attribute_name', 'expected_value'); + * ``` */ public function assertRequestAttributeValueSame(string $name, string $expectedValue, string $message = ''): void { @@ -60,6 +80,11 @@ public function assertRequestAttributeValueSame(string $name, string $expectedVa /** * Asserts that the specified response cookie is present and matches the expected value. + * + * ```php + * assertResponseCookieValueSame('cookie_name', 'expected_value'); + * ``` */ public function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', ?string $domain = null, string $message = ''): void { @@ -69,6 +94,11 @@ public function assertResponseCookieValueSame(string $name, string $expectedValu /** * Asserts that the response format matches the expected format. This checks the format returned by the `Response::getFormat()` method. + * + * ```php + * assertResponseFormatSame('json'); + * ``` */ public function assertResponseFormatSame(?string $expectedFormat, string $message = ''): void { @@ -77,6 +107,11 @@ public function assertResponseFormatSame(?string $expectedFormat, string $messag /** * Asserts that the specified cookie is present in the response. Optionally, it can check for a specific cookie path or domain. + * + * ```php + * assertResponseHasCookie('cookie_name'); + * ``` */ public function assertResponseHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void { @@ -86,6 +121,11 @@ public function assertResponseHasCookie(string $name, string $path = '/', ?strin /** * Asserts that the specified header is available in the response. * For example, use `assertResponseHasHeader('content-type');`. + * + * ```php + * assertResponseHasHeader('content-type'); + * ``` */ public function assertResponseHasHeader(string $headerName, string $message = ''): void { @@ -95,6 +135,11 @@ public function assertResponseHasHeader(string $headerName, string $message = '' /** * Asserts that the specified header does not contain the expected value in the response. * For example, use `assertResponseHeaderNotSame('content-type', 'application/octet-stream');`. + * + * ```php + * assertResponseHeaderNotSame('content-type', 'application/json'); + * ``` */ public function assertResponseHeaderNotSame(string $headerName, string $expectedValue, string $message = ''): void { @@ -104,6 +149,11 @@ public function assertResponseHeaderNotSame(string $headerName, string $expected /** * Asserts that the specified header contains the expected value in the response. * For example, use `assertResponseHeaderSame('content-type', 'application/octet-stream');`. + * + * ```php + * assertResponseHeaderSame('content-type', 'application/json'); + * ``` */ public function assertResponseHeaderSame(string $headerName, string $expectedValue, string $message = ''): void { @@ -112,6 +162,11 @@ public function assertResponseHeaderSame(string $headerName, string $expectedVal /** * Asserts that the response was successful (HTTP status code is in the 2xx range). + * + * ```php + * assertResponseIsSuccessful(); + * ``` */ public function assertResponseIsSuccessful(string $message = '', bool $verbose = true): void { @@ -120,6 +175,11 @@ public function assertResponseIsSuccessful(string $message = '', bool $verbose = /** * Asserts that the response is unprocessable (HTTP status code is 422). + * + * ```php + * assertResponseIsUnprocessable(); + * ``` */ public function assertResponseIsUnprocessable(string $message = '', bool $verbose = true): void { @@ -128,6 +188,11 @@ public function assertResponseIsUnprocessable(string $message = '', bool $verbos /** * Asserts that the specified cookie is not present in the response. Optionally, it can check for a specific cookie path or domain. + * + * ```php + * assertResponseNotHasCookie('cookie_name'); + * ``` */ public function assertResponseNotHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void { @@ -136,7 +201,11 @@ public function assertResponseNotHasCookie(string $name, string $path = '/', ?st /** * Asserts that the specified header is not available in the response. - * For example, use `assertResponseNotHasHeader('content-type');`. + * + * ```php + * assertResponseNotHasHeader('content-type'); + * ``` */ public function assertResponseNotHasHeader(string $headerName, string $message = ''): void { @@ -146,6 +215,12 @@ public function assertResponseNotHasHeader(string $headerName, string $message = /** * Asserts that the response is a redirect. Optionally, you can check the target location and status code. * The expected location can be either an absolute or a relative path. + * + * ```php + * assertResponseRedirects('/login', 302); + * ``` */ public function assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = '', bool $verbose = true): void { @@ -165,6 +240,11 @@ public function assertResponseRedirects(?string $expectedLocation = null, ?int $ /** * Asserts that the response status code matches the expected code. + * + * ```php + * assertResponseStatusCodeSame(200); + * ``` */ public function assertResponseStatusCodeSame(int $expectedCode, string $message = '', bool $verbose = true): void { @@ -173,6 +253,11 @@ public function assertResponseStatusCodeSame(int $expectedCode, string $message /** * Asserts the request matches the given route and optionally route parameters. + * + * ```php + * assertRouteSame('profile', ['id' => 123]); + * ``` */ public function assertRouteSame(string $expectedRoute, array $parameters = [], string $message = ''): void { $request = $this->getClient()->getRequest(); diff --git a/src/Codeception/Module/Symfony/DomCrawlerAssertionsTrait.php b/src/Codeception/Module/Symfony/DomCrawlerAssertionsTrait.php index 643e3fd1..8786be4c 100644 --- a/src/Codeception/Module/Symfony/DomCrawlerAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/DomCrawlerAssertionsTrait.php @@ -15,6 +15,11 @@ trait DomCrawlerAssertionsTrait { /** * Asserts that the checkbox with the given name is checked. + * + * ```php + * assertCheckboxChecked('agree_terms'); + * ``` */ public function assertCheckboxChecked(string $fieldName, string $message = ''): void { @@ -23,6 +28,11 @@ public function assertCheckboxChecked(string $fieldName, string $message = ''): /** * Asserts that the checkbox with the given name is not checked. + * + * ```php + * assertCheckboxNotChecked('subscribe'); + * ``` */ public function assertCheckboxNotChecked(string $fieldName, string $message = ''): void { @@ -33,6 +43,11 @@ public function assertCheckboxNotChecked(string $fieldName, string $message = '' /** * Asserts that the value of the form input with the given name does not equal the expected value. + * + * ```php + * assertInputValueNotSame('username', 'admin'); + * ``` */ public function assertInputValueNotSame(string $fieldName, string $expectedValue, string $message = ''): void { @@ -44,6 +59,11 @@ public function assertInputValueNotSame(string $fieldName, string $expectedValue /** * Asserts that the value of the form input with the given name equals the expected value. + * + * ```php + * assertInputValueSame('username', 'johndoe'); + * ``` */ public function assertInputValueSame(string $fieldName, string $expectedValue, string $message = ''): void { @@ -56,6 +76,11 @@ public function assertInputValueSame(string $fieldName, string $expectedValue, s /** * Asserts that the `` element contains the given title. + * + * ```php + * <?php + * $I->assertPageTitleContains('Welcome'); + * ``` */ public function assertPageTitleContains(string $expectedTitle, string $message = ''): void { @@ -64,6 +89,11 @@ public function assertPageTitleContains(string $expectedTitle, string $message = /** * Asserts that the `<title>` element equals the given title. + * + * ```php + * <?php + * $I->assertPageTitleSame('Home Page'); + * ``` */ public function assertPageTitleSame(string $expectedTitle, string $message = ''): void { @@ -72,6 +102,11 @@ public function assertPageTitleSame(string $expectedTitle, string $message = '') /** * Asserts that the given selector matches at least one element in the response. + * + * ```php + * <?php + * $I->assertSelectorExists('.main-content'); + * ``` */ public function assertSelectorExists(string $selector, string $message = ''): void { @@ -80,6 +115,11 @@ public function assertSelectorExists(string $selector, string $message = ''): vo /** * Asserts that the given selector does not match at least one element in the response. + * + * ```php + * <?php + * $I->assertSelectorNotExists('.error'); + * ``` */ public function assertSelectorNotExists(string $selector, string $message = ''): void { @@ -88,6 +128,11 @@ public function assertSelectorNotExists(string $selector, string $message = ''): /** * Asserts that the first element matching the given selector contains the expected text. + * + * ```php + * <?php + * $I->assertSelectorTextContains('h1', 'Dashboard'); + * ``` */ public function assertSelectorTextContains(string $selector, string $text, string $message = ''): void { @@ -97,6 +142,11 @@ public function assertSelectorTextContains(string $selector, string $text, strin /** * Asserts that the first element matching the given selector does not contain the expected text. + * + * ```php + * <?php + * $I->assertSelectorTextNotContains('p', 'error'); + * ``` */ public function assertSelectorTextNotContains(string $selector, string $text, string $message = ''): void { @@ -106,6 +156,11 @@ public function assertSelectorTextNotContains(string $selector, string $text, st /** * Asserts that the text of the first element matching the given selector equals the expected text. + * + * ```php + * <?php + * $I->assertSelectorTextSame('h1', 'Dashboard'); + * ``` */ public function assertSelectorTextSame(string $selector, string $text, string $message = ''): void { diff --git a/src/Codeception/Module/Symfony/FormAssertionsTrait.php b/src/Codeception/Module/Symfony/FormAssertionsTrait.php index cdebbb64..f77403bd 100644 --- a/src/Codeception/Module/Symfony/FormAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/FormAssertionsTrait.php @@ -14,6 +14,11 @@ trait FormAssertionsTrait { /** * Asserts that value of the field of the first form matching the given selector does equal the expected value. + * + * ```php + * <?php + * $I->assertFormValue('#loginForm', 'username', 'john_doe'); + * ``` */ public function assertFormValue(string $formSelector, string $fieldName, string $value, string $message = ''): void { @@ -25,7 +30,12 @@ public function assertFormValue(string $formSelector, string $fieldName, string } /** - * Asserts that value of the field of the first form matching the given selector does equal the expected value. + * Asserts that the field of the first form matching the given selector does not have a value. + * + * ```php + * <?php + * $I->assertNoFormValue('#registrationForm', 'middle_name'); + * ``` */ public function assertNoFormValue(string $formSelector, string $fieldName, string $message = ''): void { @@ -128,7 +138,6 @@ public function seeFormErrorMessage(string $field, ?string $message = null): voi * If you want to specify the error messages, you can do so * by sending an associative array instead, with the key being * the name of the field and the error message the value. - * * This method will validate that the expected error message * is contained in the actual error message, that is, * you can specify either the entire error message or just a part of it: @@ -136,7 +145,7 @@ public function seeFormErrorMessage(string $field, ?string $message = null): voi * ```php * <?php * $I->seeFormErrorMessages([ - * 'address' => 'The address is too long' + * 'address' => 'The address is too long', * 'telephone' => 'too short', // the full error message is 'The telephone is too short' * ]); * ``` @@ -191,4 +200,4 @@ protected function grabFormCollector(string $function): FormDataCollector { return $this->grabCollector('form', $function); } -} \ No newline at end of file +} diff --git a/src/Codeception/Module/Symfony/HttpClientAssertionsTrait.php b/src/Codeception/Module/Symfony/HttpClientAssertionsTrait.php index 9ac3a6e4..f6f322eb 100644 --- a/src/Codeception/Module/Symfony/HttpClientAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/HttpClientAssertionsTrait.php @@ -12,7 +12,18 @@ trait HttpClientAssertionsTrait { /** * Asserts that the given URL has been called using, if specified, the given method body and headers. - * By default, it will check on the HttpClient, but you can also pass a specific HttpClient ID. (It will succeed if the request has been called multiple times.) + * By default, it will check on the HttpClient, but you can also pass a specific HttpClient ID. + * (It will succeed if the request has been called multiple times.) + * + * ```php + * <?php + * $I->assertHttpClientRequest( + * 'https://example.com/api', + * 'POST', + * '{"data": "value"}', + * ['Authorization' => 'Bearer token'] + * ); + * ``` */ public function assertHttpClientRequest(string $expectedUrl, string $expectedMethod = 'GET', string|array|null $expectedBody = null, array $expectedHeaders = [], string $httpClientId = 'http_client'): void { @@ -77,6 +88,11 @@ public function assertHttpClientRequest(string $expectedUrl, string $expectedMet /** * Asserts that the given number of requests has been made on the HttpClient. * By default, it will check on the HttpClient, but you can also pass a specific HttpClient ID. + * + * ```php + * <?php + * $I->assertHttpClientRequestCount(3); + * ``` */ public function assertHttpClientRequestCount(int $count, string $httpClientId = 'http_client'): void { @@ -88,6 +104,11 @@ public function assertHttpClientRequestCount(int $count, string $httpClientId = /** * Asserts that the given URL has not been called using GET or the specified method. * By default, it will check on the HttpClient, but a HttpClient id can be specified. + * + * ```php + * <?php + * $I->assertNotHttpClientRequest('https://example.com/unexpected', 'GET'); + * ``` */ public function assertNotHttpClientRequest(string $unexpectedUrl, string $expectedMethod = 'GET', string $httpClientId = 'http_client'): void { diff --git a/src/Codeception/Module/Symfony/MailerAssertionsTrait.php b/src/Codeception/Module/Symfony/MailerAssertionsTrait.php index df2fd0f1..007e02af 100644 --- a/src/Codeception/Module/Symfony/MailerAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/MailerAssertionsTrait.php @@ -15,6 +15,11 @@ trait MailerAssertionsTrait { /** * Asserts that the expected number of emails was sent. + * + * ```php + * <?php + * $I->assertEmailCount(2, 'smtp'); + * ``` */ public function assertEmailCount(int $count, ?string $transport = null, string $message = ''): void { @@ -24,6 +29,12 @@ public function assertEmailCount(int $count, ?string $transport = null, string $ /** * Asserts that the given mailer event is not queued. * Use `getMailerEvent(int $index = 0, ?string $transport = null)` to retrieve a mailer event by index. + * + * ```php + * <?php + * $event = $I->getMailerEvent(); + * $I->assertEmailIsNotQueued($event); + * ``` */ public function assertEmailIsNotQueued(MessageEvent $event, string $message = ''): void { @@ -33,6 +44,12 @@ public function assertEmailIsNotQueued(MessageEvent $event, string $message = '' /** * Asserts that the given mailer event is queued. * Use `getMailerEvent(int $index = 0, ?string $transport = null)` to retrieve a mailer event by index. + * + * ```php + * <?php + * $event = $I->getMailerEvent(); + * $I->assertEmailIsQueued($event); + * ``` */ public function assertEmailIsQueued(MessageEvent $event, string $message = ''): void { @@ -41,6 +58,11 @@ public function assertEmailIsQueued(MessageEvent $event, string $message = ''): /** * Asserts that the expected number of emails was queued (e.g. using the Messenger component). + * + * ```php + * <?php + * $I->assertQueuedEmailCount(1, 'smtp'); + * ``` */ public function assertQueuedEmailCount(int $count, ?string $transport = null, string $message = ''): void { @@ -50,7 +72,13 @@ public function assertQueuedEmailCount(int $count, ?string $transport = null, st /** * Checks that no email was sent. * The check is based on `\Symfony\Component\Mailer\EventListener\MessageLoggerListener`, which means: - * If your app performs an HTTP redirect, you need to suppress it using [stopFollowingRedirects()](https://codeception.com/docs/modules/Symfony#stopFollowingRedirects) first; otherwise this check will *always* pass. + * If your app performs an HTTP redirect, you need to suppress it using [stopFollowingRedirects()](https://codeception.com/docs/modules/Symfony#stopFollowingRedirects) first; + * otherwise this check will *always* pass. + * + * ```php + * <?php + * $I->dontSeeEmailIsSent(); + * ``` */ public function dontSeeEmailIsSent(): void { @@ -114,18 +142,31 @@ public function seeEmailIsSent(int $expectedCount = 1): void $this->assertThat($this->getMessageMailerEvents(), new MailerConstraint\EmailCount($expectedCount)); } + /** + * Returns the mailer event at the specified index. + * + * ```php + * <?php + * $event = $I->getMailerEvent(); + * ``` + */ + public function getMailerEvent(int $index = 0, ?string $transport = null): ?MessageEvent + { + $mailerEvents = $this->getMessageMailerEvents(); + $events = $mailerEvents->getEvents($transport); + return $events[$index] ?? null; + } + protected function getMessageMailerEvents(): MessageEvents { - if ($messageLogger = $this->getService('mailer.message_logger_listener')) { - /** @var MessageLoggerListener $messageLogger */ - return $messageLogger->getEvents(); + if ($mailer = $this->getService('mailer.message_logger_listener')) { + /** @var MessageLoggerListener $mailer */ + return $mailer->getEvents(); } - - if ($messageLogger = $this->getService('mailer.logger_message_listener')) { - /** @var MessageLoggerListener $messageLogger */ - return $messageLogger->getEvents(); + if ($mailer = $this->getService('mailer.logger_message_listener')) { + /** @var MessageLoggerListener $mailer */ + return $mailer->getEvents(); } - $this->fail("Emails can't be tested without Symfony Mailer service."); } } From 15fd14260b5041ec245bb9ffc146f4887f379e43 Mon Sep 17 00:00:00 2001 From: prophetz <kpuzuc@gmail.com> Date: Wed, 9 Apr 2025 23:48:38 +0300 Subject: [PATCH 2/6] Fix parameter name in exception for case when Kernel has custom namespace (#199) --- src/Codeception/Module/Symfony.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Codeception/Module/Symfony.php b/src/Codeception/Module/Symfony.php index 0e41e787..3ac2bc79 100644 --- a/src/Codeception/Module/Symfony.php +++ b/src/Codeception/Module/Symfony.php @@ -321,7 +321,7 @@ protected function getKernelClass(): string throw new ModuleRequireException( self::class, "Kernel class was not found.\n" - . 'Specify directory where file with Kernel class for your application is located with `app_path` parameter.' + . 'Specify directory where file with Kernel class for your application is located with `kernel_class` parameter.' ); } From d9084f562015e5749a66647b977be0710cdc65d4 Mon Sep 17 00:00:00 2001 From: Thomas Landauer <thomas@landauer.at> Date: Thu, 10 Apr 2025 00:03:00 +0200 Subject: [PATCH 3/6] Update MailerAssertionsTrait.php: Adding Mailpit (#204) --- .../Module/Symfony/MailerAssertionsTrait.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Codeception/Module/Symfony/MailerAssertionsTrait.php b/src/Codeception/Module/Symfony/MailerAssertionsTrait.php index 007e02af..5a31e6d8 100644 --- a/src/Codeception/Module/Symfony/MailerAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/MailerAssertionsTrait.php @@ -72,8 +72,7 @@ public function assertQueuedEmailCount(int $count, ?string $transport = null, st /** * Checks that no email was sent. * The check is based on `\Symfony\Component\Mailer\EventListener\MessageLoggerListener`, which means: - * If your app performs an HTTP redirect, you need to suppress it using [stopFollowingRedirects()](https://codeception.com/docs/modules/Symfony#stopFollowingRedirects) first; - * otherwise this check will *always* pass. + * If your app performs an HTTP redirect, you need to suppress it using [stopFollowingRedirects()](#stopFollowingRedirects) first; otherwise this check will *always* pass. * * ```php * <?php @@ -88,7 +87,7 @@ public function dontSeeEmailIsSent(): void /** * Returns the last sent email. * The function is based on `\Symfony\Component\Mailer\EventListener\MessageLoggerListener`, which means: - * If your app performs an HTTP redirect after sending the email, you need to suppress it using [stopFollowingRedirects()](https://codeception.com/docs/modules/Symfony#stopFollowingRedirects) first. + * If your app performs an HTTP redirect after sending the email, you need to suppress it using [stopFollowingRedirects()](#stopFollowingRedirects) first. * See also: [grabSentEmails()](https://codeception.com/docs/modules/Symfony#grabSentEmails) * * ```php @@ -110,7 +109,7 @@ public function grabLastSentEmail(): ?Email /** * Returns an array of all sent emails. * The function is based on `\Symfony\Component\Mailer\EventListener\MessageLoggerListener`, which means: - * If your app performs an HTTP redirect after sending the email, you need to suppress it using [stopFollowingRedirects()](https://codeception.com/docs/modules/Symfony#stopFollowingRedirects) first. + * If your app performs an HTTP redirect after sending the email, you need to suppress it using [stopFollowingRedirects()](#stopFollowingRedirects) first. * See also: [grabLastSentEmail()](https://codeception.com/docs/modules/Symfony#grabLastSentEmail) * * ```php @@ -128,7 +127,12 @@ public function grabSentEmails(): array /** * Checks if the given number of emails was sent (default `$expectedCount`: 1). * The check is based on `\Symfony\Component\Mailer\EventListener\MessageLoggerListener`, which means: - * If your app performs an HTTP redirect after sending the email, you need to suppress it using [stopFollowingRedirects()](https://codeception.com/docs/modules/Symfony#stopFollowingRedirects) first. + * If your app performs an HTTP redirect after sending the email, you need to suppress it using [stopFollowingRedirects()](#stopFollowingRedirects) first. + * + * Limitation: + * If your mail is sent in a Symfony console command and you start that command in your test with [$I->runShellCommand()](https://codeception.com/docs/modules/Cli#runShellCommand), + * Codeception will not notice it. + * As a more professional alternative, we recommend Mailpit (see [Addons](https://codeception.com/addons)), which also lets you test the content of the mail. * * ```php * <?php From c3a1c42f8dfe15e049bfc6763a962371a93e376b Mon Sep 17 00:00:00 2001 From: Aaron Gustavo Nieves <64917965+TavoNiievez@users.noreply.github.com> Date: Wed, 28 May 2025 13:25:49 -0500 Subject: [PATCH 4/6] Remove PHP 8.1 Support (#211) --- .github/workflows/main.yml | 2 +- composer.json | 19 +++-- .../Module/Symfony/BrowserAssertionsTrait.php | 9 ++- .../Module/Symfony/ConsoleAssertionsTrait.php | 74 ++++++++++--------- .../Symfony/DomCrawlerAssertionsTrait.php | 16 ++-- .../Module/Symfony/MimeAssertionsTrait.php | 6 +- .../Symfony/ServicesAssertionsTrait.php | 7 +- .../Symfony/TranslationAssertionsTrait.php | 2 +- .../Module/Symfony/TwigAssertionsTrait.php | 2 +- .../Symfony/ValidatorAssertionsTrait.php | 16 ++-- 10 files changed, 84 insertions(+), 69 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 85b0d49d..43762ad0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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 diff --git a/composer.json b/composer.json index 747a5941..f8023eb7 100644 --- a/composer.json +++ b/composer.json @@ -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" @@ -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", @@ -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" } diff --git a/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php b/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php index fbd8a075..760f6cc7 100644 --- a/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php @@ -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); } } @@ -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 diff --git a/src/Codeception/Module/Symfony/ConsoleAssertionsTrait.php b/src/Codeception/Module/Symfony/ConsoleAssertionsTrait.php index 18e20173..763f977e 100644 --- a/src/Codeception/Module/Symfony/ConsoleAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/ConsoleAssertionsTrait.php @@ -9,6 +9,9 @@ use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\HttpKernel\KernelInterface; +use function in_array; +use function sprintf; + trait ConsoleAssertionsTrait { /** @@ -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 = []; @@ -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; } @@ -101,4 +103,4 @@ protected function grabKernelService(): KernelInterface { return $this->grabService('kernel'); } -} \ No newline at end of file +} diff --git a/src/Codeception/Module/Symfony/DomCrawlerAssertionsTrait.php b/src/Codeception/Module/Symfony/DomCrawlerAssertionsTrait.php index 8786be4c..f25f9bf3 100644 --- a/src/Codeception/Module/Symfony/DomCrawlerAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/DomCrawlerAssertionsTrait.php @@ -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 + ); } /** @@ -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 + ); } /** diff --git a/src/Codeception/Module/Symfony/MimeAssertionsTrait.php b/src/Codeception/Module/Symfony/MimeAssertionsTrait.php index ba2ee9ac..d48df3d4 100644 --- a/src/Codeception/Module/Symfony/MimeAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/MimeAssertionsTrait.php @@ -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 @@ -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) ); } -} \ No newline at end of file +} diff --git a/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php b/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php index bd9140c0..b4c1a5dd 100644 --- a/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php @@ -5,6 +5,7 @@ namespace Codeception\Module\Symfony; use Codeception\Lib\Connector\Symfony as SymfonyConnector; +use PHPUnit\Framework\Assert; trait ServicesAssertionsTrait { @@ -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; diff --git a/src/Codeception/Module/Symfony/TranslationAssertionsTrait.php b/src/Codeception/Module/Symfony/TranslationAssertionsTrait.php index 7c4c385a..5fa91725 100644 --- a/src/Codeception/Module/Symfony/TranslationAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/TranslationAssertionsTrait.php @@ -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 { diff --git a/src/Codeception/Module/Symfony/TwigAssertionsTrait.php b/src/Codeception/Module/Symfony/TwigAssertionsTrait.php index 1bfba3ec..e664932c 100644 --- a/src/Codeception/Module/Symfony/TwigAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/TwigAssertionsTrait.php @@ -79,4 +79,4 @@ protected function grabTwigCollector(string $function): TwigDataCollector { return $this->grabCollector('twig', $function); } -} \ No newline at end of file +} diff --git a/src/Codeception/Module/Symfony/ValidatorAssertionsTrait.php b/src/Codeception/Module/Symfony/ValidatorAssertionsTrait.php index ca82e196..508cfa5e 100644 --- a/src/Codeception/Module/Symfony/ValidatorAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/ValidatorAssertionsTrait.php @@ -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.'); @@ -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.'); @@ -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); @@ -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; } @@ -81,7 +81,7 @@ 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); @@ -89,9 +89,9 @@ protected function getViolationsForSubject(mixed $subject, ?string $propertyPath $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) ); } From d8a8943d06b303fa9a2feb9064eeeabb5bb36386 Mon Sep 17 00:00:00 2001 From: Thomas Landauer <thomas@landauer.at> Date: Wed, 28 May 2025 20:28:12 +0200 Subject: [PATCH 5/6] Update ServicesAssertionsTrait.php: Adding another hint about private services (#210) --- .../Module/Symfony/ServicesAssertionsTrait.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php b/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php index b4c1a5dd..1286e252 100644 --- a/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php @@ -11,9 +11,9 @@ trait ServicesAssertionsTrait { /** * Grabs a service from the Symfony dependency injection container (DIC). - * In "test" environment, Symfony uses a special `test.service_container`. + * In the "test" environment, Symfony uses a special `test.service_container`. * See the "[Public Versus Private Services](https://symfony.com/doc/current/service_container/alias_private.html#marking-services-as-public-private)" documentation. - * Services that aren't injected somewhere into your app, need to be defined as `public` to be accessible by Codeception. + * Services that aren't injected anywhere in your app, need to be defined as `public` to be accessible by Codeception. * * ```php * <?php @@ -25,10 +25,10 @@ trait ServicesAssertionsTrait public function grabService(string $serviceId): object { if (!$service = $this->getService($serviceId)) { - 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" - ); + Assert::fail("Service `{$serviceId}` is required by Codeception, but not loaded by Symfony. Possible solutions:\n + In your `config/packages/framework.php`/`.yaml`, set `test` to `true` (when in test environment), see https://symfony.com/doc/current/reference/configuration/framework.html#test\n + If you're still getting this message, you're not using that service in your app, so Symfony isn't loading it at all.\n + Solution: Set it to `public` in your `config/services.php`/`.yaml`, see https://symfony.com/doc/current/service_container/alias_private.html#marking-services-as-public-private\n"); } return $service; From c2adb5cdcff816a4190c4bfd5be6acc1a5a9c4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20M=C3=BCller?= <9016208+Seros@users.noreply.github.com> Date: Fri, 30 May 2025 10:07:26 +0200 Subject: [PATCH 6/6] Replace kernel reboot with actual boot to reset services (#209) * Replace kernel reboot with actual boot to reset services * Ensure congruence with the flow in the Symfony KernelTestCase * Add 6.4wApi branch to CI --------- Co-authored-by: TavoNiievez <ganieves@outlook.com> --- .github/workflows/main.yml | 50 +++++++++++++++++------ src/Codeception/Lib/Connector/Symfony.php | 11 ++++- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 43762ad0..c95a2224 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,10 +7,7 @@ jobs: strategy: matrix: php: [8.2, 8.3, 8.4] - symfony: ["5.4.*", "6.4.*", "7.2.*"] - exclude: - - php: 8.1 - symfony: "7.2.*" + symfony: ["5.4.*", "6.4.*", "6.4wApi", "7.2.*"] steps: - name: Checkout code @@ -25,11 +22,26 @@ jobs: coverage: none - name: Set Symfony version reference - run: echo "SF_REF=${MATRIX_SYMFONY%.*}" >> $GITHUB_ENV env: MATRIX_SYMFONY: ${{ matrix.symfony }} + run: | + if [[ "$MATRIX_SYMFONY" == *'*' ]]; then + echo "SF_REF=${MATRIX_SYMFONY%.*}" >> "$GITHUB_ENV" + else + echo "SF_REF=$MATRIX_SYMFONY" >> "$GITHUB_ENV" + fi + + - name: Set Composer Symfony constraint + env: + MATRIX_SYMFONY: ${{ matrix.symfony }} + run: | + if [[ "$MATRIX_SYMFONY" == "6.4wApi" ]]; then + echo "COMP_SYMFONY=6.4.*" >> "$GITHUB_ENV" + else + echo "COMP_SYMFONY=$MATRIX_SYMFONY" >> "$GITHUB_ENV" + fi - - name: Checkout Symfony ${{ env.SF_REF }} Sample + - name: Checkout Symfony ${{ env.SF_REF }} sample uses: actions/checkout@v4 with: repository: Codeception/symfony-module-tests @@ -51,17 +63,24 @@ jobs: run: composer require --dev --no-update "phpunit/phpunit=^10.0" - name: Install dependencies + env: + MATRIX_SYMFONY: ${{ matrix.symfony }} run: | - composer require symfony/finder=${{ matrix.symfony }} --no-update - composer require symfony/yaml=${{ matrix.symfony }} --no-update - composer require symfony/console=${{ matrix.symfony }} --no-update - composer require symfony/event-dispatcher=${{ matrix.symfony }} --no-update - composer require symfony/css-selector=${{ matrix.symfony }} --no-update - composer require symfony/dom-crawler=${{ matrix.symfony }} --no-update - composer require symfony/browser-kit=${{ matrix.symfony }} --no-update + composer require symfony/finder=${{ env.COMP_SYMFONY }} --no-update + composer require symfony/yaml=${{ env.COMP_SYMFONY }} --no-update + composer require symfony/console=${{ env.COMP_SYMFONY }} --no-update + composer require symfony/event-dispatcher=${{ env.COMP_SYMFONY }} --no-update + composer require symfony/css-selector=${{ env.COMP_SYMFONY }} --no-update + composer require symfony/dom-crawler=${{ env.COMP_SYMFONY }} --no-update + composer require symfony/browser-kit=${{ env.COMP_SYMFONY }} --no-update composer require vlucas/phpdotenv --no-update composer require codeception/module-asserts="3.*" --no-update composer require codeception/module-doctrine="3.*" --no-update + + if [[ "$MATRIX_SYMFONY" == "6.4wApi" ]]; then + composer require codeception/module-rest="3.*" --no-update + fi + composer update --prefer-dist --no-progress --no-dev - name: Validate Composer files @@ -84,6 +103,11 @@ jobs: php bin/console doctrine:fixtures:load --quiet working-directory: framework-tests + - name: Generate JWT keypair + if: ${{ matrix.symfony == '6.4wApi' }} + run: php bin/console lexik:jwt:generate-keypair --skip-if-exists + working-directory: framework-tests + - name: Run tests run: | php vendor/bin/codecept build -c framework-tests diff --git a/src/Codeception/Lib/Connector/Symfony.php b/src/Codeception/Lib/Connector/Symfony.php index 44d7595a..019317af 100644 --- a/src/Codeception/Lib/Connector/Symfony.php +++ b/src/Codeception/Lib/Connector/Symfony.php @@ -49,7 +49,7 @@ protected function doRequest(object $request): Response } /** - * Reboot kernel + * Reboots the kernel. * * Services from the list of persistent services * are updated from service container before kernel shutdown @@ -66,7 +66,8 @@ public function rebootKernel(): void } $this->persistDoctrineConnections(); - $this->kernel->reboot(null); + $this->ensureKernelShutdown(); + $this->kernel->boot(); $this->container = $this->getContainer(); foreach ($this->persistentServices as $serviceName => $service) { @@ -82,6 +83,12 @@ public function rebootKernel(): void } } + protected function ensureKernelShutdown(): void + { + $this->kernel->boot(); + $this->kernel->shutdown(); + } + private function getContainer(): ?ContainerInterface { /** @var ContainerInterface $container */ <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'> <html xmlns='http://www.w3.org/1999/xhtml'> <head> <title>pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy