Compare commits

2 Commits

Author SHA1 Message Date
Veyra Hermes Agent
5e8edeac9f Add Behat 4 compatible test configuration
Some checks failed
Build / PHP 8.3 + Symfony 7.4.* (pull_request) Has been cancelled
Build / PHP 8.4 + Symfony 7.4.* (pull_request) Has been cancelled
Build / PHP 8.5 + Symfony 7.4.* (pull_request) Has been cancelled
Build / Symfony 8 + PHP 8.5 consumer install (pull_request) Has been cancelled
Build / Run Psalm (pull_request) Has been cancelled
Build / Validate composer.json (pull_request) Has been cancelled
Build / Validate Coding Standards (pull_request) Has been cancelled
2026-06-15 15:52:05 +02:00
Veyra Hermes Agent
c1e8294f77 Add Symfony 8 and PHP 8.5 compatibility
Some checks failed
Build / PHP 8.3 + Symfony 7.4.* (pull_request) Has been cancelled
Build / PHP 8.4 + Symfony 7.4.* (pull_request) Has been cancelled
Build / PHP 8.5 + Symfony 7.4.* (pull_request) Has been cancelled
Build / Symfony 8 + PHP 8.5 consumer install (pull_request) Has been cancelled
Build / Run Psalm (pull_request) Has been cancelled
Build / Validate composer.json (pull_request) Has been cancelled
Build / Validate Coding Standards (pull_request) Has been cancelled
Build / PHP 8.3 + Symfony 7.4.* (push) Has been cancelled
Build / PHP 8.4 + Symfony 7.4.* (push) Has been cancelled
Build / PHP 8.5 + Symfony 7.4.* (push) Has been cancelled
Build / Symfony 8 + PHP 8.5 consumer install (push) Has been cancelled
Build / Run Psalm (push) Has been cancelled
Build / Validate composer.json (push) Has been cancelled
Build / Validate Coding Standards (push) Has been cancelled
2026-06-15 15:13:58 +02:00
5 changed files with 171 additions and 27 deletions

View File

@@ -50,6 +50,46 @@ jobs:
- name: Run tests - name: Run tests
run: composer test run: composer test
symfony8-php85-consumer-install:
name: Symfony 8 + PHP 8.5 consumer install
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
coverage: none
ini-values: "memory_limit=-1"
php-version: '8.5'
tools: composer:v2
- name: Verify installability in a Symfony 8 consumer project
run: |
mkdir /tmp/fob-symfony8-consumer
cat > /tmp/fob-symfony8-consumer/composer.json <<'JSON'
{
"name": "friends-of-behat/symfony8-consumer-probe",
"type": "project",
"minimum-stability": "dev",
"prefer-stable": true,
"repositories": [
{"type": "path", "url": "${{ github.workspace }}", "options": {"symlink": false}}
],
"require-dev": {
"behat/behat": "4.x-dev",
"friends-of-behat/symfony-extension": "*",
"symfony/framework-bundle": "^8.0",
"symfony/yaml": "^8.0"
},
"config": {
"sort-packages": true
}
}
JSON
composer update --working-dir=/tmp/fob-symfony8-consumer --no-interaction --no-plugins --prefer-dist --no-progress
psalm: psalm:
name: Run Psalm name: Run Psalm
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04

View File

@@ -1,3 +1,17 @@
# CHANGELOG FOR `2.3.x`
## v2.3.0 (unreleased)
#### TL;DR
- **Added installability support for Symfony 8 and PHP 8.5**.
#### Details
- Allow `symfony/dependency-injection` and `symfony/http-kernel` `^8.0`.
- Allow Behat `^4.0`, which is required by Symfony 8 because Behat 3.x only supports Symfony components up to 7.x.
- Keep Symfony 7.4 / Behat 3.31 compatibility and add a CI consumer-install probe for Symfony 8 on PHP 8.5.
# CHANGELOG FOR `2.1.x` # CHANGELOG FOR `2.1.x`
## v2.2.0 (2021-02-04) ## v2.2.0 (2021-02-04)

16
behat.dist.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
use Behat\Config\Config;
use Behat\Config\Profile;
use Behat\Config\Suite;
use Tests\Behat\Context\TestContext;
return (new Config())
->withProfile((new Profile('default'))
->withSuite((new Suite('default'))
->withContexts(TestContext::class),
),
)
;

View File

@@ -11,23 +11,23 @@
} }
], ],
"require": { "require": {
"php": "^8.3", "php": ">=8.3 <8.6",
"behat/behat": "^3.22", "behat/behat": "^3.31 || ^4.0",
"symfony/dependency-injection": "^7.4", "symfony/dependency-injection": "^7.4 || ^8.0",
"symfony/http-kernel": "^7.4" "symfony/http-kernel": "^7.4 || ^8.0"
}, },
"require-dev": { "require-dev": {
"behat/mink-browserkit-driver": "^2.0", "behat/mink-browserkit-driver": "^2.0",
"behat/mink-selenium2-driver": "^1.3", "behat/mink-selenium2-driver": "^1.3",
"behat/mink": "^1.9", "behat/mink": "^1.9",
"friends-of-behat/mink-extension": "^2.5", "friends-of-behat/mink-extension": "^2.5",
"friends-of-behat/page-object-extension": "^0.3.2", "friends-of-behat/page-object-extension": "^0.4",
"friends-of-behat/service-container-extension": "^1.1", "friends-of-behat/service-container-extension": "^2.0",
"sylius-labs/coding-standard": ">=4.1.1, <=4.2.1", "sylius-labs/coding-standard": ">=4.1.1, <=4.2.1",
"symfony/browser-kit": "^7.4", "symfony/browser-kit": "^7.4 || ^8.0",
"symfony/framework-bundle": "^7.4", "symfony/framework-bundle": "^7.4 || ^8.0",
"symfony/process": "^7.4", "symfony/process": "^7.4 || ^8.0",
"symfony/yaml": "^7.4", "symfony/yaml": "^7.4 || ^8.0",
"vimeo/psalm": "^6.0" "vimeo/psalm": "^6.0"
}, },
"suggest": { "suggest": {
@@ -43,7 +43,7 @@
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.2-dev" "dev-master": "2.3-dev"
} }
}, },
"autoload": { "autoload": {

View File

@@ -5,6 +5,12 @@ declare(strict_types=1);
namespace Tests\Behat\Context; namespace Tests\Behat\Context;
use Behat\Behat\Context\Context; use Behat\Behat\Context\Context;
use Behat\Hook\AfterScenario as AfterScenarioHook;
use Behat\Hook\BeforeFeature as BeforeFeatureHook;
use Behat\Hook\BeforeScenario as BeforeScenarioHook;
use Behat\Step\Given as GivenStep;
use Behat\Step\Then as ThenStep;
use Behat\Step\When as WhenStep;
use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
@@ -28,8 +34,9 @@ final class TestContext implements Context
private $variables = []; private $variables = [];
/** /**
* @BeforeFeature * BeforeFeature
*/ */
#[BeforeFeatureHook]
public static function beforeFeature(): void public static function beforeFeature(): void
{ {
self::$workingDir = sprintf('%s/%s/', sys_get_temp_dir(), uniqid('', true)); self::$workingDir = sprintf('%s/%s/', sys_get_temp_dir(), uniqid('', true));
@@ -38,8 +45,9 @@ final class TestContext implements Context
} }
/** /**
* @BeforeScenario * BeforeScenario
*/ */
#[BeforeScenarioHook]
public function beforeScenario(): void public function beforeScenario(): void
{ {
self::$filesystem->remove(self::$workingDir); self::$filesystem->remove(self::$workingDir);
@@ -47,16 +55,18 @@ final class TestContext implements Context
} }
/** /**
* @AfterScenario * AfterScenario
*/ */
#[AfterScenarioHook]
public function afterScenario(): void public function afterScenario(): void
{ {
self::$filesystem->remove(self::$workingDir); self::$filesystem->remove(self::$workingDir);
} }
/** /**
* @Given a standard Symfony autoloader configured * Given a standard Symfony autoloader configured
*/ */
#[GivenStep('a standard Symfony autoloader configured')]
public function standardSymfonyAutoloaderConfigured(): void public function standardSymfonyAutoloaderConfigured(): void
{ {
$this->thereIsFile('vendor/autoload.php', sprintf(<<<'CON' $this->thereIsFile('vendor/autoload.php', sprintf(<<<'CON'
@@ -74,8 +84,9 @@ CON
} }
/** /**
* @Given a working Symfony application with SymfonyExtension configured * Given a working Symfony application with SymfonyExtension configured
*/ */
#[GivenStep('a working Symfony application with SymfonyExtension configured')]
public function workingSymfonyApplicationWithExtension(): void public function workingSymfonyApplicationWithExtension(): void
{ {
$this->thereIsConfiguration( $this->thereIsConfiguration(
@@ -217,24 +228,27 @@ YML
} }
/** /**
* @Given /^an? (server|environment) variable "([^"]++)" set to "([^"]++)"$/ * Given /^an? (server|environment) variable "([^"]++)" set to "([^"]++)"$/
*/ */
#[GivenStep('/^an? (server|environment) variable "([^"]++)" set to "([^"]++)"$/')]
public function variableSetTo(string $type, string $name, string $value): void public function variableSetTo(string $type, string $name, string $value): void
{ {
$this->variables[$type][$name] = $value; $this->variables[$type][$name] = $value;
} }
/** /**
* @Given /^a YAML services file containing:$/ * Given /^a YAML services file containing:$/
*/ */
#[GivenStep('/^a YAML services file containing:$/')]
public function yamlServicesFile($content): void public function yamlServicesFile($content): void
{ {
$this->thereIsFile('config/services.yaml', (string) $content); $this->thereIsFile('config/services.yaml', (string) $content);
} }
/** /**
* @Given /^a Behat configuration containing(?: "([^"]+)"|:)$/ * Given /^a Behat configuration containing(?: "([^"]+)"|:)$/
*/ */
#[GivenStep('/^a Behat configuration containing(?: "([^"]+)"|:)$/')]
public function thereIsConfiguration($content): void public function thereIsConfiguration($content): void
{ {
$mainConfigFile = sprintf('%s/behat.yml', self::$workingDir); $mainConfigFile = sprintf('%s/behat.yml', self::$workingDir);
@@ -250,11 +264,64 @@ YML
$mainBehatConfiguration['imports'][] = $newConfigFile; $mainBehatConfiguration['imports'][] = $newConfigFile;
self::$filesystem->dumpFile($mainConfigFile, Yaml::dump($mainBehatConfiguration)); self::$filesystem->dumpFile($mainConfigFile, Yaml::dump($mainBehatConfiguration));
$this->dumpPhpConfigurationBridge($mainConfigFile);
}
private function dumpPhpConfigurationBridge(string $yamlConfigFile): void
{
self::$filesystem->dumpFile(
sprintf('%s/behat.dist.php', self::$workingDir),
sprintf(
<<<'PHP'
<?php
declare(strict_types=1);
$load = static function (string $file): array {
$configuration = \Symfony\Component\Yaml\Yaml::parseFile($file);
$imports = $configuration['imports'] ?? [];
unset($configuration['imports']);
foreach ($imports as $import) {
$importedConfiguration = \Symfony\Component\Yaml\Yaml::parseFile($import);
$configuration = array_replace_recursive($configuration, $importedConfiguration);
}
$extensionClassMap = [
'FriendsOfBehat\\SymfonyExtension' => 'FriendsOfBehat\\SymfonyExtension\\ServiceContainer\\SymfonyExtension',
'Behat\\MinkExtension' => 'Behat\\MinkExtension\\ServiceContainer\\MinkExtension',
'FriendsOfBehat\\ServiceContainerExtension' => 'FriendsOfBehat\\ServiceContainerExtension\\ServiceContainer\\ServiceContainerExtension',
];
foreach ($configuration as &$profileConfiguration) {
if (!is_array($profileConfiguration['extensions'] ?? null)) {
continue;
}
foreach ($extensionClassMap as $legacyName => $className) {
if (!array_key_exists($legacyName, $profileConfiguration['extensions'])) {
continue;
}
$profileConfiguration['extensions'][$className] = $profileConfiguration['extensions'][$legacyName];
unset($profileConfiguration['extensions'][$legacyName]);
}
}
return $configuration;
};
return new \Behat\Config\Config($load(%s));
PHP
, var_export($yamlConfigFile, true),
),
);
} }
/** /**
* @Given /^a (?:.+ |)file "([^"]+)" containing(?: "([^"]+)"|:)$/ * Given /^a (?:.+ |)file "([^"]+)" containing(?: "([^"]+)"|:)$/
*/ */
#[GivenStep('/^a (?:.+ |)file "([^"]+)" containing(?: "([^"]+)"|:)$/')]
public function thereIsFile($file, $content): string public function thereIsFile($file, $content): string
{ {
$path = self::$workingDir . '/' . $file; $path = self::$workingDir . '/' . $file;
@@ -265,16 +332,18 @@ YML
} }
/** /**
* @Given /^a feature file containing(?: "([^"]+)"|:)$/ * Given /^a feature file containing(?: "([^"]+)"|:)$/
*/ */
#[GivenStep('/^a feature file containing(?: "([^"]+)"|:)$/')]
public function thereIsFeatureFile($content): void public function thereIsFeatureFile($content): void
{ {
$this->thereIsFile(sprintf('features/%s.feature', md5(uniqid('', true))), $content); $this->thereIsFile(sprintf('features/%s.feature', md5(uniqid('', true))), $content);
} }
/** /**
* @When /^I run Behat$/ * When /^I run Behat$/
*/ */
#[WhenStep('/^I run Behat$/')]
public function iRunBehat(): void public function iRunBehat(): void
{ {
$executablePath = BEHAT_BIN_PATH; $executablePath = BEHAT_BIN_PATH;
@@ -301,8 +370,9 @@ YML
} }
/** /**
* @Then /^it should pass$/ * Then /^it should pass$/
*/ */
#[ThenStep('/^it should pass$/')]
public function itShouldPass(): void public function itShouldPass(): void
{ {
if (0 === $this->getProcessExitCode()) { if (0 === $this->getProcessExitCode()) {
@@ -315,8 +385,9 @@ YML
} }
/** /**
* @Then /^it should pass with(?: "([^"]+)"|:)$/ * Then /^it should pass with(?: "([^"]+)"|:)$/
*/ */
#[ThenStep('/^it should pass with(?: "([^"]+)"|:)$/')]
public function itShouldPassWith($expectedOutput): void public function itShouldPassWith($expectedOutput): void
{ {
$this->itShouldPass(); $this->itShouldPass();
@@ -324,8 +395,9 @@ YML
} }
/** /**
* @Then /^it should fail$/ * Then /^it should fail$/
*/ */
#[ThenStep('/^it should fail$/')]
public function itShouldFail(): void public function itShouldFail(): void
{ {
if (0 !== $this->getProcessExitCode()) { if (0 !== $this->getProcessExitCode()) {
@@ -338,8 +410,9 @@ YML
} }
/** /**
* @Then /^it should fail with(?: "([^"]+)"|:)$/ * Then /^it should fail with(?: "([^"]+)"|:)$/
*/ */
#[ThenStep('/^it should fail with(?: "([^"]+)"|:)$/')]
public function itShouldFailWith($expectedOutput): void public function itShouldFailWith($expectedOutput): void
{ {
$this->itShouldFail(); $this->itShouldFail();
@@ -347,8 +420,9 @@ YML
} }
/** /**
* @Then /^it should end with(?: "([^"]+)"|:)$/ * Then /^it should end with(?: "([^"]+)"|:)$/
*/ */
#[ThenStep('/^it should end with(?: "([^"]+)"|:)$/')]
public function itShouldEndWith($expectedOutput): void public function itShouldEndWith($expectedOutput): void
{ {
$this->assertOutputMatches((string) $expectedOutput); $this->assertOutputMatches((string) $expectedOutput);