Skip to content

Commit 0c06f56

Browse files
Merge pull request #56 from MacPaw/cursor/dependency-constraint-widening-e8e1
chore: widen dependencies to support latest packages (2025-03-23)
2 parents e19374e + fb008c6 commit 0c06f56

15 files changed

Lines changed: 186 additions & 84 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ jobs:
2525
- php: '8.1'
2626
symfony-versions: '^5.4'
2727
coverage: 'none'
28+
- description: 'Symfony 8 + Behat 4.x-dev'
29+
php: '8.4'
30+
symfony-versions: '8.0.*'
31+
coverage: 'none'
2832
- description: 'Log Code Coverage'
2933
php: '8.4'
3034
coverage: 'xdebug'
@@ -60,6 +64,10 @@ jobs:
6064
key: ${{ runner.os }}-${{ matrix.php }}-${{ matrix.symfony-versions }}-composer-${{ hashFiles('composer.json') }}
6165
restore-keys: ${{ runner.os }}-${{ matrix.php }}-${{ matrix.symfony-versions }}-composer
6266

67+
- name: Use Behat 4.x-dev with Symfony 8
68+
if: matrix.symfony-versions == '8.0.*'
69+
run: composer require behat/behat:4.x-dev --no-update --no-scripts
70+
6371
- name: Update Symfony version
6472
if: matrix.symfony-versions != ''
6573
run: |
@@ -86,4 +94,22 @@ jobs:
8694
with:
8795
token: ${{ secrets.CODECOV_TOKEN }}
8896
file: './coverage.xml'
89-
fail_ci_if_error: true
97+
fail_ci_if_error: false
98+
99+
prefer-lowest:
100+
name: PHPUnit (composer --prefer-lowest)
101+
runs-on: ubuntu-latest
102+
steps:
103+
- name: Checkout
104+
uses: actions/checkout@v4
105+
106+
- name: Setup PHP
107+
uses: shivammathur/setup-php@v2
108+
with:
109+
php-version: '8.3'
110+
111+
- name: Install lowest compatible dependencies
112+
run: composer update --prefer-lowest --no-interaction --no-progress
113+
114+
- name: Run PHPUnit tests
115+
run: composer phpunit

Makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.PHONY: cs-fix rector phpunit phpstan phpcs dev-checks
2+
3+
cs-fix:
4+
composer run code-style-fix
5+
6+
rector:
7+
@if [ -x vendor/bin/rector ]; then vendor/bin/rector --dry-run; else echo "rector not installed; skipping"; fi
8+
9+
phpunit:
10+
composer run phpunit
11+
12+
phpstan:
13+
composer run phpstan
14+
15+
phpcs:
16+
composer run code-style
17+
18+
dev-checks:
19+
composer run dev-checks

composer.json

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,26 @@
2525
}
2626
],
2727
"license": "MIT",
28+
"minimum-stability": "stable",
29+
"prefer-stable": true,
2830
"require": {
2931
"ext-json": "*",
3032
"php": "^8.1",
31-
"behat/behat": "^3.0",
32-
"symfony/config": "^5.4 || ^6.4 || ^7.0",
33-
"symfony/dependency-injection": "^5.4.34 || ^6.4 || ^7.1",
34-
"symfony/http-client": "^5.4 || ^6.4 || ^7.1",
35-
"symfony/http-kernel": "^5.4 || ^6.4 || ^7.1",
36-
"symfony/routing": "^5.4 || ^6.4 || ^7.1",
33+
"behat/behat": "^3.0 || 4.x-dev@dev",
34+
"symfony/config": "^5.4 || ^6.4 || ^7.0 || ^8.0",
35+
"symfony/dependency-injection": "^5.4.34 || ^6.4 || ^7.1 || ^8.0",
36+
"symfony/http-client": "^5.4 || ^6.4 || ^7.1 || ^8.0",
37+
"symfony/http-kernel": "^5.4 || ^6.4 || ^7.1 || ^8.0",
38+
"symfony/routing": "^5.4 || ^6.4 || ^7.1 || ^8.0",
3739
"macpaw/similar-arrays": "^1.0"
3840
},
3941
"require-dev": {
4042
"phpstan/phpstan": "^2.0",
41-
"phpunit/phpunit": "^10.0",
42-
"slevomat/coding-standard": "^7.0",
43-
"squizlabs/php_codesniffer": "^3.6",
44-
"doctrine/orm": "^2.0"
43+
"phpunit/phpunit": "^10.5 || ^11.0 || ^12.0",
44+
"slevomat/coding-standard": "^8.0",
45+
"squizlabs/php_codesniffer": "^4.0",
46+
"doctrine/orm": "^2.0 || ^3.0",
47+
"dealerdirect/phpcodesniffer-composer-installer": "^1.0"
4548
},
4649
"autoload": {
4750
"psr-4": {

phpcs.xml.dist

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,19 @@
1414

1515
<rule ref="Generic.PHP.ForbiddenFunctions">
1616
<properties>
17-
<property name="forbiddenFunctions" type="array" value="eval=>NULL,dd=>NULL,die=>NULL,var_dump=>NULL,dump=>NULL,sizeof=>count,delete=>unset,print=>echo,echo=>NULL,print_r=>NULL,create_function=>NULL"/>
17+
<property name="forbiddenFunctions" type="array">
18+
<element key="eval" value="null"/>
19+
<element key="dd" value="null"/>
20+
<element key="die" value="null"/>
21+
<element key="var_dump" value="null"/>
22+
<element key="dump" value="null"/>
23+
<element key="sizeof" value="count"/>
24+
<element key="delete" value="unset"/>
25+
<element key="print" value="echo"/>
26+
<element key="echo" value="null"/>
27+
<element key="print_r" value="null"/>
28+
<element key="create_function" value="null"/>
29+
</property>
1830
</properties>
1931
</rule>
2032
<rule ref="Squiz.WhiteSpace.FunctionSpacing">

phpstan.neon.dist

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,5 @@ parameters:
33
- src
44
level: max
55
checkExplicitMixed: false
6-
ignoreErrors:
7-
-
8-
message: '#Parameter \#1 \$json of function json_decode expects string, string\|false given.*#'
9-
count: 3
10-
path: ./src/Context/ApiContext.php
11-
-
12-
message: '#Parameter \#3 \$actualJSON of method BehatApiContext\\Context\\ApiContext::compareStructureResponse\(\) expects string, string\|false given.*#'
13-
count: 1
14-
path: ./src/Context/ApiContext.php
15-
-
16-
identifier: missingType.iterableValue
6+
# Aligns Symfony Config generics with runtime checks (e.g. ArrayNodeDefinition) across Symfony versions.
7+
treatPhpDocTypesAsCertain: false

phpunit.xml.dist

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<phpunit bootstrap="vendor/autoload.php"
33
backupGlobals="false"
4-
backupStaticAttributes="false"
4+
backupStaticProperties="false"
55
colors="true"
6-
verbose="true"
7-
convertErrorsToExceptions="true"
8-
convertNoticesToExceptions="true"
9-
convertWarningsToExceptions="true"
106
processIsolation="false"
11-
stopOnFailure="false">
7+
stopOnFailure="false"
8+
failOnPhpunitWarning="false">
129
<testsuites>
1310
<testsuite name="Behat Api Context Test Suite">
1411
<directory>tests</directory>
1512
</testsuite>
1613
</testsuites>
17-
<coverage>
14+
<source>
1815
<include>
1916
<directory>./src</directory>
2017
</include>
18+
</source>
19+
<coverage>
2120
<report>
2221
<clover outputFile="clover.xml"/>
2322
</report>

src/Context/ApiContext.php

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,11 @@ public function responseStatusCodeShouldBe(string $httpStatus): void
246246
public function responseIsJson(): void
247247
{
248248
$response = $this->getResponse();
249-
$data = json_decode($response->getContent(), true, 512, JSON_THROW_ON_ERROR);
249+
$body = $this->getResponseBody($response);
250+
$data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
250251

251252
if (empty($data)) {
252-
throw new RuntimeException("Response was not JSON\n" . $response->getContent());
253+
throw new RuntimeException("Response was not JSON\n" . $body);
253254
}
254255
}
255256

@@ -258,7 +259,7 @@ public function responseIsJson(): void
258259
*/
259260
public function responseEmpty(): void
260261
{
261-
if (!empty($this->getResponse()->getContent())) {
262+
if ($this->getResponseBody($this->getResponse()) !== '') {
262263
throw new RuntimeException('Content not empty');
263264
}
264265
}
@@ -271,7 +272,7 @@ public function responseEmpty(): void
271272
public function responseShouldBeJson(PyStringNode $string): void
272273
{
273274
$expectedResponse = json_decode(trim($string->getRaw()), true, 512, JSON_THROW_ON_ERROR);
274-
$actualResponse = json_decode($this->getResponse()->getContent(), true, 512, JSON_THROW_ON_ERROR);
275+
$actualResponse = json_decode($this->getResponseBody($this->getResponse()), true, 512, JSON_THROW_ON_ERROR);
275276

276277
if ($expectedResponse !== $actualResponse) {
277278
$prettyJSON = json_encode($actualResponse, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT, 512);
@@ -286,7 +287,7 @@ public function responseShouldBeJson(PyStringNode $string): void
286287
*/
287288
public function iGetParamFromJsonResponse(string $paramPath, string $valueKey): void
288289
{
289-
$actualResponse = json_decode($this->getResponse()->getContent(), true, 512, JSON_THROW_ON_ERROR);
290+
$actualResponse = json_decode($this->getResponseBody($this->getResponse()), true, 512, JSON_THROW_ON_ERROR);
290291
$pathKeys = explode('.', $paramPath);
291292

292293
foreach ($pathKeys as $key) {
@@ -307,7 +308,7 @@ public function iGetParamFromJsonResponse(string $paramPath, string $valueKey):
307308
*/
308309
public function responseShouldBeJsonWithVariableFields(string $variableFields, PyStringNode $string): void
309310
{
310-
$this->compareStructureResponse($variableFields, $string, $this->getResponse()->getContent());
311+
$this->compareStructureResponse($variableFields, $string, $this->getResponseBody($this->getResponse()));
311312
}
312313

313314
protected function compareStructureResponse(
@@ -388,6 +389,11 @@ protected function checkResponseHeader(string $headerName, string $headerValue):
388389
}
389390
}
390391

392+
/**
393+
* @param array<string, mixed> $requestParams
394+
*
395+
* @return array<string, mixed>
396+
*/
391397
protected function convertRunnableCodeParams(array $requestParams): array
392398
{
393399
foreach ($requestParams as $key => $value) {
@@ -449,8 +455,21 @@ protected function getResponse(): Response
449455
return $this->response;
450456
}
451457

458+
/**
459+
* @return array<string, mixed>
460+
*/
452461
public function geRequestParams(): array
453462
{
454463
return $this->requestParams;
455464
}
465+
466+
private function getResponseBody(Response $response): string
467+
{
468+
$content = $response->getContent();
469+
if ($content === false) {
470+
throw new RuntimeException('The response body is not available.');
471+
}
472+
473+
return $content;
474+
}
456475
}

src/DependencyInjection/BehatApiContextExtension.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,20 @@
88
use Symfony\Component\Config\FileLocator;
99
use Symfony\Component\DependencyInjection\ContainerBuilder;
1010
use Symfony\Component\DependencyInjection\Extension\Extension;
11-
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
11+
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
1212

1313
class BehatApiContextExtension extends Extension
1414
{
15+
/**
16+
* @param array<string, mixed> $configs
17+
*/
1518
public function load(array $configs, ContainerBuilder $container): void
1619
{
1720
$configuration = new Configuration();
1821
/** @var array<string, mixed> $config */
1922
$config = $this->processConfiguration($configuration, $configs);
2023

21-
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
24+
$loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
2225

2326
$this->loadApiContext($config, $loader, $container);
2427
}
@@ -28,10 +31,10 @@ public function load(array $configs, ContainerBuilder $container): void
2831
*/
2932
private function loadApiContext(
3033
array $config,
31-
XmlFileLoader $loader,
34+
PhpFileLoader $loader,
3235
ContainerBuilder $container
3336
): void {
34-
$this->safeLoad($loader, 'api_context.xml');
37+
$this->safeLoad($loader, 'api_context.php');
3538

3639
$this->configureKernelResetManagers(
3740
$config,
@@ -62,7 +65,7 @@ private function configureKernelResetManagers(
6265
}
6366
}
6467

65-
private function safeLoad(XmlFileLoader $loader, string $file): void
68+
private function safeLoad(PhpFileLoader $loader, string $file): void
6669
{
6770
$loader->load($file);
6871
}

src/DependencyInjection/Configuration.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace BehatApiContext\DependencyInjection;
66

7+
use LogicException;
8+
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
79
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
810
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
911
use Symfony\Component\Config\Definition\ConfigurationInterface;
@@ -13,7 +15,15 @@ class Configuration implements ConfigurationInterface
1315
public function getConfigTreeBuilder(): TreeBuilder
1416
{
1517
$treeBuilder = new TreeBuilder('behat_api_context');
16-
$root = $treeBuilder->getRootNode()->children();
18+
$rootNode = $treeBuilder->getRootNode();
19+
// Symfony TreeBuilder root is always ArrayNodeDefinition; kept for static analysis / defensive parity.
20+
// @codeCoverageIgnoreStart
21+
if (!$rootNode instanceof ArrayNodeDefinition) {
22+
throw new LogicException('Expected configuration root to be an array node.');
23+
}
24+
// @codeCoverageIgnoreEnd
25+
26+
$root = $rootNode->children();
1727

1828
$this->addKernelResetManagersSection($root);
1929

@@ -22,10 +32,9 @@ public function getConfigTreeBuilder(): TreeBuilder
2232

2333
private function addKernelResetManagersSection(NodeBuilder $builder): void
2434
{
25-
$builder
26-
->arrayNode('kernel_reset_managers')
27-
->scalarPrototype()->end()
28-
->end()
29-
->end();
35+
$kernelResetManagers = $builder->arrayNode('kernel_reset_managers');
36+
$kernelResetManagers->scalarPrototype()->end();
37+
$kernelResetManagers->end();
38+
$builder->end();
3039
}
3140
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use BehatApiContext\Context\ApiContext;
6+
use BehatApiContext\Service\ResetManager\DoctrineResetManager;
7+
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
8+
9+
return static function (ContainerConfigurator $container): void {
10+
$services = $container->services();
11+
12+
$services->set(ApiContext::class)
13+
->public()
14+
->autowire()
15+
->autoconfigure();
16+
17+
$services->set(DoctrineResetManager::class)
18+
->autowire(false)
19+
->autoconfigure(false);
20+
};

0 commit comments

Comments
 (0)