diff --git a/.github/workflows/sylius.yaml b/.github/workflows/sylius.yaml index 48fb290..8081a9e 100644 --- a/.github/workflows/sylius.yaml +++ b/.github/workflows/sylius.yaml @@ -19,13 +19,12 @@ jobs: - 8.2 - 8.3 sylius: - - 1.12.0 - - 1.13.0 - - 1.14.0 + - 2.0 symfony: - 6.4 + - 7.2 node: - - 14.x + - 20.x env: APP_ENV: test package-name: synolia/sylius-admin-oauth-plugin diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 09039a7..15abde5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ in `install/Application/.env.local` and/or `install/Application/.env.test.local` $ make install -e SYLIUS_VERSION=XX SYMFONY_VERSION=YY PHP_VERSION=ZZ ``` -Default values : XX=1.12.0 and YY=6.3 and ZZ=8.2 +Default values : XX=2.0.0 and YY=7.2 and ZZ=8.2 :information_source: To reset (drop database and delete files) test environment: ```bash diff --git a/Makefile b/Makefile index ec3186a..f5df7c3 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ CONSOLE=cd ${TEST_DIRECTORY} && php bin/console -e test COMPOSER=cd ${TEST_DIRECTORY} && composer YARN=cd ${TEST_DIRECTORY} && yarn -SYLIUS_VERSION=1.14 -SYMFONY_VERSION=6.4 +SYLIUS_VERSION=2.0 +SYMFONY_VERSION=7.2 PHP_VERSION=8.2 PLUGIN_NAME=synolia/sylius-admin-oauth-plugin @@ -16,7 +16,7 @@ PLUGIN_NAME=synolia/sylius-admin-oauth-plugin ### DEVELOPMENT ### ¯¯¯¯¯¯¯¯¯¯¯ -install: sylius ## Install Plugin on Sylius [SYLIUS_VERSION=1.12.0] [SYMFONY_VERSION=6.1] [PHP_VERSION=8.1] +install: sylius ## Install Plugin on Sylius [SYLIUS_VERSION=2.0.0] [SYMFONY_VERSION=7.2] [PHP_VERSION=8.2] .PHONY: install reset: ## Remove dependencies diff --git a/README.md b/README.md index 7cabfd2..2727f76 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,10 @@ ## Requirements -| | Version | -|:-------|:--------| -| PHP | ^8.2 | -| Sylius | ^1.12 | +| | Version | +|:-------|:--------------| +| PHP | ^8.2 | +| Sylius | ^1.12 or ^2.0 | ## Installation @@ -45,7 +45,6 @@ 3. In your security.yaml, add the OAuth authenticator in your admin firewall and put access_control paths you need depending on wich provider you use. **They must be on top of the others** : ```yaml security: - enable_authenticator_manager: true firewalls: admin: custom_authenticators: @@ -62,13 +61,14 @@ 4. Create a config/routes/synolia_oauth.yaml to configure plugin's routes and to prefix them with 'admin': ```yaml synolia_oauth: - resource: '@SynoliaSyliusAdminOauthPlugin/config/routes.yaml' + resource: '@SynoliaSyliusAdminOauthPlugin/config/routes[-legacy].yaml' prefix: '/%sylius_admin.path_name%' ``` -5. Create a config/packages/synolia_oauth_config.yaml to import all required configs : +5. Create a config/packages/synolia_oauth_config.yaml to import all required configs + depending on which sylius version you use: ```yaml imports: - - { resource: "@SynoliaSyliusAdminOauthPlugin/config/app.yaml" } + - { resource: "@SynoliaSyliusAdminOauthPlugin/config/app[-legacy].yaml" } ``` 6. Add this trait to your App\Entity\User\AdminUser.php diff --git a/composer.json b/composer.json index 4d11f62..75bf45d 100644 --- a/composer.json +++ b/composer.json @@ -11,32 +11,32 @@ "php": "^8.2", "knpuniversity/oauth2-client-bundle": "^2.18", "league/oauth2-google": "^4.0", - "sylius/sylius": "^1.12", + "sylius/sylius": "^2.0", "thenetworg/oauth2-azure": "^2.2", "webmozart/assert": "^1.11" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.66", - "friendsoftwig/twigcs": "^6.5", - "j13k/yaml-lint": "^1.1", - "php-parallel-lint/php-parallel-lint": "^1.4", - "phpmd/phpmd": "^2.15", - "phpro/grumphp": "^2.9", - "phpstan/extension-installer": "^1.3", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-doctrine": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpstan/phpstan-webmozart-assert": "^2.0", - "phpunit/phpunit": "^9.5", - "povils/phpmnd": "^3.5", - "rector/rector": "^2.0", - "seld/jsonlint": "^1.11", - "squizlabs/php_codesniffer": "^3.11", - "sylius-labs/coding-standard": "^4.3", - "symfony/browser-kit": "^6.4", - "symfony/debug-bundle": "^6.4", - "symfony/dotenv": "^6.4" + "friendsofphp/php-cs-fixer": "3.66.0", + "friendsoftwig/twigcs": "6.5.0", + "j13k/yaml-lint": "1.1.6", + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpmd/phpmd": "2.15.0", + "phpro/grumphp": "2.10.0", + "phpstan/extension-installer": "1.4.3", + "phpstan/phpstan": "2.0.4", + "phpstan/phpstan-doctrine": "2.0.1", + "phpstan/phpstan-phpunit": "2.0.3", + "phpstan/phpstan-strict-rules": "2.0.1", + "phpstan/phpstan-webmozart-assert": "2.0.0", + "phpunit/phpunit": "9.6.22", + "povils/phpmnd": "3.5.0", + "rector/rector": "2.0.4", + "seld/jsonlint": "1.11.0", + "squizlabs/php_codesniffer": "3.11.2", + "sylius-labs/coding-standard": "4.4.0", + "symfony/browser-kit": "6.4.13", + "symfony/debug-bundle": "6.4.13", + "symfony/dotenv": "6.4.16" }, "config": { "sort-packages": true, diff --git a/config/app-legacy.yaml b/config/app-legacy.yaml new file mode 100644 index 0000000..2105d87 --- /dev/null +++ b/config/app-legacy.yaml @@ -0,0 +1,3 @@ +imports: + - { resource: "legacy/*.yaml" } + - { resource: "ui/*.yaml" } diff --git a/config/app.yaml b/config/app.yaml index 1888eff..a7ca420 100644 --- a/config/app.yaml +++ b/config/app.yaml @@ -1,95 +1,5 @@ -sylius_ui: - events: - sylius.admin.login.form.content: - blocks: - alerts: '@SynoliaSyliusAdminOauthPlugin/alerts.html.twig' - google_oauth_button: '@SynoliaSyliusAdminOauthPlugin/google_auth_button.html.twig' - microsoft_oauth_button: '@SynoliaSyliusAdminOauthPlugin/microsoft_auth_button.html.twig' - sylius.admin.layout.stylesheets: - blocks: - stylesoauth: - template: "@SynoliaSyliusAdminOauthPlugin/_styles.html.twig" - enabled: true - -twig: - globals: - google_client_id: '%env(default::SYNOLIA_ADMIN_OAUTH_GOOGLE_CLIENT_ID)%' - microsoft_client_id: '%env(default::SYNOLIA_ADMIN_OAUTH_MICROSOFT_CLIENT_ID)%' - -knpu_oauth2_client: - clients: - google_admin: - type: google - client_id: '%env(default::SYNOLIA_ADMIN_OAUTH_GOOGLE_CLIENT_ID)%' - client_secret: '%env(default::SYNOLIA_ADMIN_OAUTH_GOOGLE_CLIENT_SECRET)%' - redirect_route: 'connect_admin_google_check' - redirect_params: {} - azure_admin: - type: azure - client_id: '%env(default::SYNOLIA_ADMIN_OAUTH_MICROSOFT_CLIENT_ID)%' - client_secret: '%env(default::SYNOLIA_ADMIN_OAUTH_MICROSOFT_CLIENT_SECRET)%' - redirect_route: 'connect_admin_microsoft_check' - redirect_params: {} - -winzou_state_machine: - synolia_admin_oauth_authorized_domain: - class: "%synolia_admin_oauth.model.authorized_domain.class%" - property_path: isEnabled - graph: synolia_admin_oauth_authorized_domain - state_machine_class: "%sylius.state_machine.class%" - states: - new: ~ - enabled: ~ - transitions: - enable: - from: [new] - to: enabled -sylius_grid: - grids: - synolia_admin_oauth_authorized_domain: - driver: - options: - class: "%synolia_admin_oauth.model.authorized_domain.class%" - sorting: - name: asc - isEnabled: asc - fields: - name: - type: string - label: sylius.ui.name - sortable: ~ - isEnabled: - type: twig - label: sylius.ui.is_enabled - options: - template: "@SynoliaSyliusAdminOauthPlugin/state.html.twig" - vars: - labels: "AuthorizedDomain/Label/Status" - sortable: ~ - actions: - main: - create: - type: create - item: - update: - type: update - delete: - type: delete - enable: - type: apply_transition - label: sylius.ui.enable - icon: star - options: - link: - route: app_admin_authorized_domain_trust - parameters: - id: resource.id - transition: enable - graph: app_authorized_domain - class: yellow - bulk: - delete: - type: delete - filters: - name: - type: string +imports: + - { resource: "legacy/knpu-oauth2-client.yaml" } + - { resource: "legacy/twig.yaml" } + - { resource: "grid/authorized-domain.yaml" } + - { resource: "twig_hooks/*.yaml" } diff --git a/config/grid/authorized-domain.yaml b/config/grid/authorized-domain.yaml new file mode 100644 index 0000000..c82974e --- /dev/null +++ b/config/grid/authorized-domain.yaml @@ -0,0 +1,35 @@ +sylius_grid: + grids: + synolia_admin_oauth_authorized_domain: + driver: + options: + class: "%synolia_admin_oauth.model.authorized_domain.class%" + sorting: + name: asc + isEnabled: asc + fields: + name: + type: string + label: sylius.ui.name + sortable: ~ + isEnabled: + type: twig + label: sylius.ui.is_enabled + options: + template: "@SynoliaSyliusAdminOauthPlugin/admin/grid/authorized_domain/is_enabled.html.twig" + sortable: ~ + actions: + main: + create: + type: create + item: + update: + type: update + delete: + type: delete + bulk: + delete: + type: delete + filters: + name: + type: string diff --git a/config/legacy/grid.yaml b/config/legacy/grid.yaml new file mode 100644 index 0000000..c751502 --- /dev/null +++ b/config/legacy/grid.yaml @@ -0,0 +1,37 @@ +sylius_grid: + grids: + synolia_admin_oauth_authorized_domain: + driver: + options: + class: "%synolia_admin_oauth.model.authorized_domain.class%" + sorting: + name: asc + isEnabled: asc + fields: + name: + type: string + label: sylius.ui.name + sortable: ~ + isEnabled: + type: twig + label: sylius.ui.is_enabled + options: + template: "@SynoliaSyliusAdminOauthPlugin/state.html.twig" + vars: + labels: "AuthorizedDomain/Label/Status" + sortable: ~ + actions: + main: + create: + type: create + item: + update: + type: update + delete: + type: delete + bulk: + delete: + type: delete + filters: + name: + type: string diff --git a/config/legacy/knpu-oauth2-client.yaml b/config/legacy/knpu-oauth2-client.yaml new file mode 100644 index 0000000..d480032 --- /dev/null +++ b/config/legacy/knpu-oauth2-client.yaml @@ -0,0 +1,14 @@ +knpu_oauth2_client: + clients: + google_admin: + type: google + client_id: '%env(default::SYNOLIA_ADMIN_OAUTH_GOOGLE_CLIENT_ID)%' + client_secret: '%env(default::SYNOLIA_ADMIN_OAUTH_GOOGLE_CLIENT_SECRET)%' + redirect_route: 'connect_admin_google_check' + redirect_params: {} + azure_admin: + type: azure + client_id: '%env(default::SYNOLIA_ADMIN_OAUTH_MICROSOFT_CLIENT_ID)%' + client_secret: '%env(default::SYNOLIA_ADMIN_OAUTH_MICROSOFT_CLIENT_SECRET)%' + redirect_route: 'connect_admin_microsoft_check' + redirect_params: {} \ No newline at end of file diff --git a/config/legacy/twig.yaml b/config/legacy/twig.yaml new file mode 100644 index 0000000..d651919 --- /dev/null +++ b/config/legacy/twig.yaml @@ -0,0 +1,4 @@ +twig: + globals: + google_client_id: '%env(default::SYNOLIA_ADMIN_OAUTH_GOOGLE_CLIENT_ID)%' + microsoft_client_id: '%env(default::SYNOLIA_ADMIN_OAUTH_MICROSOFT_CLIENT_ID)%' diff --git a/config/routes-legacy.yaml b/config/routes-legacy.yaml new file mode 100644 index 0000000..b0bde93 --- /dev/null +++ b/config/routes-legacy.yaml @@ -0,0 +1,21 @@ +controllers: + resource: + path: ../src/Controller/ + namespace: Synolia\SyliusAdminOauthPlugin\Controller + type: attribute + +synolia_admin_oauth_authorized_domain: + resource: | + alias: synolia_admin_oauth.authorized_domain + section: admin + templates: "@SyliusAdmin\\Crud" + redirect: index + grid: synolia_admin_oauth_authorized_domain + vars: + all: + header: synolia.sylius_admin_oauth.ui.authorized_domains.title + subheader: synolia.sylius_admin_oauth.ui.authorized_domains.subheader + breadcrumb: synolia.sylius_admin_oauth.ui.authorized_domains.menu_label + index: + icon: 'file image outline' + type: sylius.resource diff --git a/config/routes.yaml b/config/routes.yaml index b0bde93..d145fbf 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -8,14 +8,7 @@ synolia_admin_oauth_authorized_domain: resource: | alias: synolia_admin_oauth.authorized_domain section: admin - templates: "@SyliusAdmin\\Crud" + templates: "@SyliusAdmin\\shared\\crud" redirect: index grid: synolia_admin_oauth_authorized_domain - vars: - all: - header: synolia.sylius_admin_oauth.ui.authorized_domains.title - subheader: synolia.sylius_admin_oauth.ui.authorized_domains.subheader - breadcrumb: synolia.sylius_admin_oauth.ui.authorized_domains.menu_label - index: - icon: 'file image outline' type: sylius.resource diff --git a/config/twig_hooks/admin_login.yaml b/config/twig_hooks/admin_login.yaml new file mode 100644 index 0000000..cb1a7ac --- /dev/null +++ b/config/twig_hooks/admin_login.yaml @@ -0,0 +1,28 @@ +sylius_twig_hooks: + hooks: + 'sylius_admin.base#stylesheets': + stylesoauth: + template: '@SynoliaSyliusAdminOauthPlugin/_styles.html.twig' + priority: 0 + 'sylius_admin.security.login.page.content.form': + alerts: + template: '@SynoliaSyliusAdminOauthPlugin/alerts.html.twig' + priority: 600 + google_oauth_button: + template: '@SynoliaSyliusAdminOauthPlugin/google_auth_button.html.twig' + priority: -100 + microsoft_oauth_button: + template: '@SynoliaSyliusAdminOauthPlugin/microsoft_auth_button.html.twig' + priority: -100 + 'sylius_admin.authorized_domain.index.content.header': + breadcrumbs: + template: '@SyliusAdmin/shared/crud/index/content/header/breadcrumbs.html.twig' + context: + title: synolia.sylius_admin_oauth.ui.authorized_domains.menu_label + 'sylius_admin.authorized_domain.index.content.header.title_block': + title: + template: '@SyliusAdmin/shared/crud/common/content/header/title_block/title.html.twig' + configuration: + title: synolia.sylius_admin_oauth.ui.authorized_domains.title + subheader: synolia.sylius_admin_oauth.ui.authorized_domains.subheader + icon: tabler:stack \ No newline at end of file diff --git a/config/ui/admin_login.yaml b/config/ui/admin_login.yaml new file mode 100644 index 0000000..7a28086 --- /dev/null +++ b/config/ui/admin_login.yaml @@ -0,0 +1,12 @@ +sylius_ui: + events: + sylius.admin.login.form.content: + blocks: + alerts: '@SynoliaSyliusAdminOauthPlugin/alerts.html.twig' + google_oauth_button: '@SynoliaSyliusAdminOauthPlugin/google_auth_button.html.twig' + microsoft_oauth_button: '@SynoliaSyliusAdminOauthPlugin/microsoft_auth_button.html.twig' + sylius.admin.layout.stylesheets: + blocks: + stylesoauth: + template: "@SynoliaSyliusAdminOauthPlugin/_styles.html.twig" + enabled: true \ No newline at end of file diff --git a/install/Application/config/packages/security.yaml b/install/Application/config/packages/security.yaml index 3934065..7e25bda 100644 --- a/install/Application/config/packages/security.yaml +++ b/install/Application/config/packages/security.yaml @@ -1,7 +1,4 @@ security: - # edit for SyliusAdminOauthPlugin - enable_authenticator_manager: true - # end of SyliusAdminOauthPlugin providers: sylius_admin_user_provider: id: sylius.admin_user_provider.email_or_name_based @@ -11,18 +8,20 @@ security: id: sylius.shop_user_provider.email_or_name_based sylius_api_shop_user_provider: id: sylius.shop_user_provider.email_or_name_based + password_hashers: Sylius\Component\User\Model\UserInterface: argon2i firewalls: admin: - # add for SyliusAdminOauthPlugin + ###> synolia/sylius-admin-oauth-plugin ### custom_authenticators: - Synolia\SyliusAdminOauthPlugin\Security\Authenticator\OauthAuthenticator - # end of SyliusAdminOauthPlugin + ###< synolia/sylius-admin-oauth-plugin ### switch_user: true context: admin pattern: "%sylius.security.admin_regex%" provider: sylius_admin_user_provider + user_checker: security.user_checker.chain.admin form_login: provider: sylius_admin_user_provider login_path: sylius_admin_login @@ -44,26 +43,28 @@ security: path: sylius_admin_logout target: sylius_admin_login - new_api_admin_user: - pattern: "%sylius.security.new_api_admin_regex%/.*" + api_admin: + pattern: "%sylius.security.api_admin_regex%/.*" provider: sylius_api_admin_user_provider + user_checker: security.user_checker.chain.api_admin stateless: true entry_point: jwt json_login: - check_path: "%sylius.security.new_api_admin_route%/authentication-token" + check_path: "%sylius.security.api_admin_route%/administrators/token" username_path: email password_path: password success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure jwt: true - new_api_shop_user: - pattern: "%sylius.security.new_api_shop_regex%/.*" + api_shop: + pattern: "%sylius.security.api_shop_regex%/.*" provider: sylius_api_shop_user_provider + user_checker: security.user_checker.chain.api_shop stateless: true entry_point: jwt json_login: - check_path: "%sylius.security.new_api_shop_route%/authentication-token" + check_path: "%sylius.security.api_shop_route%/customers/token" username_path: email password_path: password success_handler: lexik_jwt_authentication.handler.authentication_success @@ -75,6 +76,7 @@ security: context: shop pattern: "%sylius.security.shop_regex%" provider: sylius_shop_user_provider + user_checker: security.user_checker.chain.shop form_login: success_handler: sylius.authentication.success_handler failure_handler: sylius.authentication.failure_handler @@ -88,6 +90,12 @@ security: enable_csrf: true csrf_parameter: _csrf_shop_security_token csrf_token_id: shop_authenticate + json_login: + check_path: sylius_shop_json_login_check + username_path: _username + password_path: _password + success_handler: sylius.authentication.success_handler + failure_handler: sylius.authentication.failure_handler remember_me: secret: "%env(APP_SECRET)%" name: APP_SHOP_REMEMBER_ME @@ -98,18 +106,22 @@ security: target: sylius_shop_homepage invalidate_session: false + image_resolver: + pattern: ^/media/cache/resolve + security: false + dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false access_control: - # add for SyliusAdminOauthPlugin - - { path: "%sylius.security.admin_regex%/connect/google", role: PUBLIC_ACCESS, requires_channel: https } + ###> synolia/sylius-admin-oauth-plugin ### + - { path: "%sylius.security.admin_regex%/connect/google", role: PUBLIC_ACCESS, requires_channel: https } - { path: "%sylius.security.admin_regex%/connect/google/check", role: PUBLIC_ACCESS, requires_channel: https } - - { path: "%sylius.security.admin_regex%/connect/microsoft", role: PUBLIC_ACCESS, requires_channel: https } + - { path: "%sylius.security.admin_regex%/connect/microsoft", role: PUBLIC_ACCESS, requires_channel: https } - { path: "%sylius.security.admin_regex%/connect/microsoft/check", role: PUBLIC_ACCESS, requires_channel: https } - # end of SyliusAdminOauthPlugin - + ###< synolia/sylius-admin-oauth-plugin ### + - { path: "%sylius.security.admin_regex%/_partial", role: PUBLIC_ACCESS, ips: [127.0.0.1, ::1] } - { path: "%sylius.security.admin_regex%/_partial", role: ROLE_NO_ACCESS } - { path: "%sylius.security.shop_regex%/_partial", role: PUBLIC_ACCESS, ips: [127.0.0.1, ::1] } @@ -126,9 +138,16 @@ security: - { path: "%sylius.security.admin_regex%", role: ROLE_ADMINISTRATION_ACCESS } - { path: "%sylius.security.shop_regex%/account", role: ROLE_USER } - - { path: "%sylius.security.new_api_admin_route%/reset-password-requests", role: PUBLIC_ACCESS } - - { path: "%sylius.security.new_api_admin_regex%/.*", role: ROLE_API_ACCESS } - - { path: "%sylius.security.new_api_admin_route%/authentication-token", role: PUBLIC_ACCESS } - - { path: "%sylius.security.new_api_user_account_regex%/.*", role: ROLE_USER } - - { path: "%sylius.security.new_api_shop_route%/authentication-token", role: PUBLIC_ACCESS } - - { path: "%sylius.security.new_api_shop_regex%/.*", role: PUBLIC_ACCESS } + - { path: "%sylius.security.api_admin_route%/administrators/reset-password", role: PUBLIC_ACCESS } + - { path: "%sylius.security.api_admin_regex%/.*", role: ROLE_API_ACCESS } + - { path: "%sylius.security.api_admin_route%/administrators/token", role: PUBLIC_ACCESS } + - { path: "%sylius.security.api_shop_account_regex%/.*", role: ROLE_USER } + - { path: "%sylius.security.api_shop_route%/customers/token", role: PUBLIC_ACCESS } + - { path: "%sylius.security.api_shop_regex%/.*", role: PUBLIC_ACCESS } + +when@test: &security_test + security: + password_hashers: + Sylius\Component\User\Model\UserInterface: plaintext + +when@test_cached: *security_test \ No newline at end of file diff --git a/templates/admin/grid/authorized_domain/is_enabled.html.twig b/templates/admin/grid/authorized_domain/is_enabled.html.twig new file mode 100644 index 0000000..4c71bfc --- /dev/null +++ b/templates/admin/grid/authorized_domain/is_enabled.html.twig @@ -0,0 +1,7 @@ +{% set value = 'synolia.sylius_admin_oauth.ui.' ~ (data is same as true ? 'yes' : 'no') %} + +{% if options.vars.labels is defined %} + {% include [(options.vars.labels ~ '/' ~ data ~ '.html.twig'), '@SyliusUi/label/default.html.twig'] with {'value': value} %} +{% else %} + {% include '@SyliusUi/label/default.html.twig' with {'value': value} %} +{% endif %} diff --git a/tests/PHPUnit/AccessToAdminAreaTest.php b/tests/PHPUnit/AccessToAdminAreaTest.php index 2bd130b..13e77e0 100644 --- a/tests/PHPUnit/AccessToAdminAreaTest.php +++ b/tests/PHPUnit/AccessToAdminAreaTest.php @@ -34,7 +34,7 @@ public function testAccessToAdminArea(): void $this->client->request('GET', '/admin/'); self::assertResponseIsSuccessful(); - self::assertPageTitleContains('Dashboard | Sylius'); + self::assertPageTitleContains('Dashboard Sylius'); } public function testAccessOAuthConfigPageInAdmin(): void