diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index f7f897c8..85b0d49d 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -1,18 +1,16 @@
name: CI
-
on: [push, pull_request]
jobs:
tests:
runs-on: ubuntu-latest
-
strategy:
matrix:
php: [8.1, 8.2, 8.3, 8.4]
- symfony: ["5.4.*", "6.4.*", "7.1.*"]
+ symfony: ["5.4.*", "6.4.*", "7.2.*"]
exclude:
- php: 8.1
- symfony: "7.1.*"
+ symfony: "7.2.*"
steps:
- name: Checkout code
@@ -26,40 +24,28 @@ jobs:
extensions: ctype, iconv, intl, json, mbstring, pdo, pdo_sqlite
coverage: none
- - name: Checkout Symfony 5.4 Sample
- if: "matrix.symfony == '5.4.*'"
- uses: actions/checkout@v4
- with:
- repository: Codeception/symfony-module-tests
- path: framework-tests
- ref: "5.4"
-
- - name: Checkout Symfony 6.4 Sample
- if: "matrix.symfony == '6.4.*'"
- uses: actions/checkout@v4
- with:
- repository: Codeception/symfony-module-tests
- path: framework-tests
- ref: "6.4"
+ - name: Set Symfony version reference
+ run: echo "SF_REF=${MATRIX_SYMFONY%.*}" >> $GITHUB_ENV
+ env:
+ MATRIX_SYMFONY: ${{ matrix.symfony }}
- - name: Checkout Symfony 7.1 Sample
- if: "matrix.symfony == '7.1.*'"
+ - name: Checkout Symfony ${{ env.SF_REF }} Sample
uses: actions/checkout@v4
with:
repository: Codeception/symfony-module-tests
path: framework-tests
- ref: "7.1"
+ ref: ${{ env.SF_REF }}
- name: Get composer cache directory
id: composer-cache
- run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+ run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- - name: Cache composer dependencies
+ - name: Cache Composer dependencies
uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
- key: ${{ runner.os }}-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
- restore-keys: ${{ runner.os }}-${{ matrix.php }}-composer-
+ key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json', 'composer.lock') }}
+ restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer-
- name: Install PHPUnit 10
run: composer require --dev --no-update "phpunit/phpunit=^10.0"
@@ -78,27 +64,27 @@ jobs:
composer require codeception/module-doctrine="3.*" --no-update
composer update --prefer-dist --no-progress --no-dev
- - name: Validate composer.json and composer.lock
- run: composer validate
+ - name: Validate Composer files
+ run: composer validate --strict
working-directory: framework-tests
- - name: Install PHPUnit 10 in framework-tests
+ - name: Install PHPUnit in framework-tests
run: composer require --dev --no-update "phpunit/phpunit=^10.0"
working-directory: framework-tests
- - name: Install Symfony Sample
+ - name: Prepare Symfony sample
run: |
composer remove codeception/codeception codeception/module-asserts codeception/module-doctrine codeception/lib-innerbrowser codeception/module-symfony --dev --no-update
composer update --no-progress
working-directory: framework-tests
- - name: Prepare the test environment
+ - name: Setup Database
run: |
php bin/console doctrine:schema:update --force
php bin/console doctrine:fixtures:load --quiet
working-directory: framework-tests
- - name: Run test suite
+ - name: Run tests
run: |
php vendor/bin/codecept build -c framework-tests
php vendor/bin/codecept run Functional -c framework-tests
diff --git a/composer.json b/composer.json
index 65238b1d..747a5941 100644
--- a/composer.json
+++ b/composer.json
@@ -28,33 +28,34 @@
"codeception/module-asserts": "^3.0",
"codeception/module-doctrine": "^3.1",
"doctrine/orm": "^2.10",
- "symfony/browser-kit": "^5.4 | ^6.4 | ^7.0",
- "symfony/cache": "^5.4 | ^6.4 | ^7.0",
- "symfony/config": "^5.4 | ^6.4 | ^7.0",
- "symfony/dependency-injection": "^5.4 | ^6.4 | ^7.0",
- "symfony/dom-crawler": "^5.4 | ^6.4 | ^7.0",
- "symfony/dotenv": "^5.4 | ^6.4 | ^7.0",
- "symfony/error-handler": "^5.4 | ^6.4 | ^7.0",
- "symfony/filesystem": "^5.4 | ^6.4 | ^7.0",
- "symfony/form": "^5.4 | ^6.4 | ^7.0",
- "symfony/framework-bundle": "^5.4 | ^6.4 | ^7.0",
- "symfony/http-client": "^5.4 | ^6.4 | ^7.0",
- "symfony/http-foundation": "^5.4 | ^6.4 | ^7.0",
- "symfony/http-kernel": "^5.4 | ^6.4 | ^7.0",
- "symfony/mailer": "^5.4 | ^6.4 | ^7.0",
- "symfony/mime": "^5.4 | ^6.4 | ^7.0",
- "symfony/notifier": "^5.4 | ^6.4 | ^7.0",
- "symfony/options-resolver": "^5.4 | ^6.4 | ^7.0",
- "symfony/property-access": "^5.4 | ^6.4 | ^7.0",
- "symfony/property-info": "^5.4 | ^6.4 | ^7.0",
- "symfony/routing": "^5.4 | ^6.4 | ^7.0",
- "symfony/security-bundle": "^5.4 | ^6.4 | ^7.0",
- "symfony/security-core": "^5.4 | ^6.4 | ^7.0",
- "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",
+ "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",
+ "symfony/dependency-injection": "^5.4 | ^6.4 | ^7.2",
+ "symfony/dom-crawler": "^5.4 | ^6.4 | ^7.2",
+ "symfony/dotenv": "^5.4 | ^6.4 | ^7.2",
+ "symfony/error-handler": "^5.4 | ^6.4 | ^7.2",
+ "symfony/filesystem": "^5.4 | ^6.4 | ^7.2",
+ "symfony/form": "^5.4 | ^6.4 | ^7.2",
+ "symfony/framework-bundle": "^5.4 | ^6.4 | ^7.2",
+ "symfony/http-client": "^5.4 | ^6.4 | ^7.2",
+ "symfony/http-foundation": "^5.4 | ^6.4 | ^7.2",
+ "symfony/http-kernel": "^5.4 | ^6.4 | ^7.2",
+ "symfony/mailer": "^5.4 | ^6.4 | ^7.2",
+ "symfony/mime": "^5.4 | ^6.4 | ^7.2",
+ "symfony/notifier": "^5.4 | ^6.4 | ^7.2",
+ "symfony/options-resolver": "^5.4 | ^6.4 | ^7.2",
+ "symfony/property-access": "^5.4 | ^6.4 | ^7.2",
+ "symfony/property-info": "^5.4 | ^6.4 | ^7.2",
+ "symfony/routing": "^5.4 | ^6.4 | ^7.2",
+ "symfony/security-bundle": "^5.4 | ^6.4 | ^7.2",
+ "symfony/security-core": "^5.4 | ^6.4 | ^7.2",
+ "symfony/security-csrf": "^5.4 | ^6.4 | ^7.2",
+ "symfony/security-http": "^5.4 | ^6.4 | ^7.2",
+ "symfony/translation": "^5.4 | ^6.4 | ^7.2",
+ "symfony/twig-bundle": "^5.4 | ^6.4 | ^7.2",
+ "symfony/validator": "^5.4 | ^6.4 | ^7.2",
+ "symfony/var-exporter": "^5.4 | ^6.4 | ^7.2",
"vlucas/phpdotenv": "^4.2 | ^5.4"
},
"suggest": {
diff --git a/readme.md b/readme.md
index ccedd850..c5bbcb98 100644
--- a/readme.md
+++ b/readme.md
@@ -9,7 +9,7 @@ A Codeception module for Symfony framework.
## Requirements
-* `Symfony` `5.4.x`, `6.4.x`, `7.1.x` or higher, as per the [Symfony supported versions](https://symfony.com/releases).
+* `Symfony` `5.4.x`, `6.4.x`, `7.2.x` or higher, as per the [Symfony supported versions](https://symfony.com/releases).
* `PHP 8.1` or higher.
## Installation
diff --git a/src/Codeception/Module/Symfony.php b/src/Codeception/Module/Symfony.php
index 3f7917bb..3ac2bc79 100644
--- a/src/Codeception/Module/Symfony.php
+++ b/src/Codeception/Module/Symfony.php
@@ -17,6 +17,7 @@
use Codeception\Module\Symfony\EventsAssertionsTrait;
use Codeception\Module\Symfony\FormAssertionsTrait;
use Codeception\Module\Symfony\HttpClientAssertionsTrait;
+use Codeception\Module\Symfony\LoggerAssertionsTrait;
use Codeception\Module\Symfony\MailerAssertionsTrait;
use Codeception\Module\Symfony\MimeAssertionsTrait;
use Codeception\Module\Symfony\ParameterAssertionsTrait;
@@ -25,6 +26,7 @@
use Codeception\Module\Symfony\ServicesAssertionsTrait;
use Codeception\Module\Symfony\SessionAssertionsTrait;
use Codeception\Module\Symfony\TimeAssertionsTrait;
+use Codeception\Module\Symfony\TranslationAssertionsTrait;
use Codeception\Module\Symfony\TwigAssertionsTrait;
use Codeception\Module\Symfony\ValidatorAssertionsTrait;
use Codeception\TestInterface;
@@ -141,6 +143,7 @@ class Symfony extends Framework implements DoctrineProvider, PartedModule
use EventsAssertionsTrait;
use FormAssertionsTrait;
use HttpClientAssertionsTrait;
+ use LoggerAssertionsTrait;
use MailerAssertionsTrait;
use MimeAssertionsTrait;
use ParameterAssertionsTrait;
@@ -148,6 +151,7 @@ class Symfony extends Framework implements DoctrineProvider, PartedModule
use SecurityAssertionsTrait;
use ServicesAssertionsTrait;
use SessionAssertionsTrait;
+ use TranslationAssertionsTrait;
use TimeAssertionsTrait;
use TwigAssertionsTrait;
use ValidatorAssertionsTrait;
@@ -317,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.'
);
}
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
+ * assertPageTitleContains('Welcome');
+ * ```
*/
public function assertPageTitleContains(string $expectedTitle, string $message = ''): void
{
@@ -64,6 +89,11 @@ public function assertPageTitleContains(string $expectedTitle, string $message =
/**
* Asserts that the `` element equals the given title.
+ *
+ * ```php
+ * 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
+ * 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
+ * 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
+ * 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
+ * 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
+ * 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
+ * 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
+ * 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
* 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
+ * 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
+ * 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
+ * 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/LoggerAssertionsTrait.php b/src/Codeception/Module/Symfony/LoggerAssertionsTrait.php
new file mode 100644
index 00000000..4cd0266a
--- /dev/null
+++ b/src/Codeception/Module/Symfony/LoggerAssertionsTrait.php
@@ -0,0 +1,60 @@
+amOnPage('/home');
+ * $I->dontSeeDeprecations();
+ * ```
+ *
+ * @param string $message Optional custom failure message.
+ */
+ public function dontSeeDeprecations(string $message = ''): void
+ {
+ $loggerCollector = $this->grabLoggerCollector(__FUNCTION__);
+ $logs = $loggerCollector->getProcessedLogs();
+
+ $foundDeprecations = [];
+
+ foreach ($logs as $log) {
+ if (isset($log['type']) && $log['type'] === 'deprecation') {
+ $msg = $log['message'];
+ if ($msg instanceof Data) {
+ $msg = $msg->getValue(true);
+ }
+ if (!is_string($msg)) {
+ $msg = (string)$msg;
+ }
+ $foundDeprecations[] = $msg;
+ }
+ }
+
+ $errorMessage = $message ?: sprintf(
+ "Found %d deprecation message%s in the log:\n%s",
+ count($foundDeprecations),
+ count($foundDeprecations) > 1 ? 's' : '',
+ implode("\n", array_map(static function ($msg) {
+ return " - " . $msg;
+ }, $foundDeprecations))
+ );
+
+ $this->assertEmpty($foundDeprecations, $errorMessage);
+ }
+
+ protected function grabLoggerCollector(string $function): LoggerDataCollector
+ {
+ return $this->grabCollector('logger', $function);
+ }
+}
diff --git a/src/Codeception/Module/Symfony/MailerAssertionsTrait.php b/src/Codeception/Module/Symfony/MailerAssertionsTrait.php
index df2fd0f1..5a31e6d8 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
+ * 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
+ * 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
+ * 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
+ * assertQueuedEmailCount(1, 'smtp');
+ * ```
*/
public function assertQueuedEmailCount(int $count, ?string $transport = null, string $message = ''): void
{
@@ -50,7 +72,12 @@ 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
+ * dontSeeEmailIsSent();
+ * ```
*/
public function dontSeeEmailIsSent(): void
{
@@ -60,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
@@ -82,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
@@ -100,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
* assertThat($this->getMessageMailerEvents(), new MailerConstraint\EmailCount($expectedCount));
}
+ /**
+ * Returns the mailer event at the specified index.
+ *
+ * ```php
+ * 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.");
}
}
diff --git a/src/Codeception/Module/Symfony/TranslationAssertionsTrait.php b/src/Codeception/Module/Symfony/TranslationAssertionsTrait.php
new file mode 100644
index 00000000..7c4c385a
--- /dev/null
+++ b/src/Codeception/Module/Symfony/TranslationAssertionsTrait.php
@@ -0,0 +1,178 @@
+dontSeeFallbackTranslations();
+ * ```
+ */
+ public function dontSeeFallbackTranslations(): void
+ {
+ $translationCollector = $this->grabTranslationCollector(__FUNCTION__);
+ $fallbacks = $translationCollector->getCountFallbacks();
+
+ $this->assertSame(
+ $fallbacks,
+ 0,
+ "Expected no fallback translations, but found {$fallbacks}."
+ );
+ }
+
+ /**
+ * Asserts that no missing translations were found.
+ *
+ * ```php
+ * dontSeeMissingTranslations();
+ * ```
+ */
+ public function dontSeeMissingTranslations(): void
+ {
+ $translationCollector = $this->grabTranslationCollector(__FUNCTION__);
+ $missings = $translationCollector->getCountMissings();
+
+ $this->assertSame(
+ $missings,
+ 0,
+ "Expected no missing translations, but found {$missings}."
+ );
+ }
+
+ /**
+ * Grabs the count of defined translations.
+ *
+ * ```php
+ * grabDefinedTranslations();
+ * ```
+ *
+ * @return int The count of defined translations.
+ */
+ public function grabDefinedTranslationsCount(): int
+ {
+ $translationCollector = $this->grabTranslationCollector(__FUNCTION__);
+ return $translationCollector->getCountDefines();
+ }
+
+ /**
+ * Asserts that there are no missing translations and no fallback translations.
+ *
+ * ```php
+ * seeAllTranslationsDefined();
+ * ```
+ */
+ public function seeAllTranslationsDefined(): void
+ {
+ $this->dontSeeMissingTranslations();
+ $this->dontSeeFallbackTranslations();
+ }
+
+ /**
+ * Asserts that the default locale is the expected one.
+ *
+ * ```php
+ * seeDefaultLocaleIs('en');
+ * ```
+ *
+ * @param string $expectedLocale The expected default locale
+ */
+ public function seeDefaultLocaleIs(string $expectedLocale): void
+ {
+ $translationCollector = $this->grabTranslationCollector(__FUNCTION__);
+ $locale = $translationCollector->getLocale();
+
+ $this->assertSame(
+ $expectedLocale,
+ $locale,
+ "Expected default locale '{$expectedLocale}', but found '{$locale}'."
+ );
+ }
+
+ /**
+ * Asserts that the fallback locales match the expected ones.
+ *
+ * ```php
+ * seeFallbackLocalesAre(['es', 'fr']);
+ * ```
+ *
+ * @param array $expectedLocales The expected fallback locales
+ */
+ public function seeFallbackLocalesAre(array $expectedLocales): void
+ {
+ $translationCollector = $this->grabTranslationCollector(__FUNCTION__);
+ $fallbackLocales = $translationCollector->getFallbackLocales();
+
+ if ($fallbackLocales instanceof Data) {
+ $fallbackLocales = $fallbackLocales->getValue(true);
+ }
+
+ $this->assertSame(
+ $expectedLocales,
+ $fallbackLocales,
+ "Fallback locales do not match expected."
+ );
+ }
+
+ /**
+ * Asserts that the count of fallback translations is less than the given limit.
+ *
+ * ```php
+ * seeFallbackTranslationsCountLessThan(10);
+ * ```
+ *
+ * @param int $limit Maximum count of fallback translations
+ */
+ public function seeFallbackTranslationsCountLessThan(int $limit): void
+ {
+ $translationCollector = $this->grabTranslationCollector(__FUNCTION__);
+ $fallbacks = $translationCollector->getCountFallbacks();
+
+ $this->assertLessThan(
+ $limit,
+ $fallbacks,
+ "Expected fewer than {$limit} fallback translations, but found {$fallbacks}."
+ );
+ }
+
+ /**
+ * Asserts that the count of missing translations is less than the given limit.
+ *
+ * ```php
+ * seeMissingTranslationsCountLessThan(5);
+ * ```
+ *
+ * @param int $limit Maximum count of missing translations
+ */
+ public function seeMissingTranslationsCountLessThan(int $limit): void
+ {
+ $translationCollector = $this->grabTranslationCollector(__FUNCTION__);
+ $missings = $translationCollector->getCountMissings();
+
+ $this->assertLessThan(
+ $limit,
+ $missings,
+ "Expected fewer than {$limit} missing translations, but found {$missings}."
+ );
+ }
+
+ protected function grabTranslationCollector(string $function): TranslationDataCollector
+ {
+ return $this->grabCollector('translation', $function);
+ }
+}