Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# brainbits Functional Test Helpers

[![Latest Version](https://img.shields.io/github/release/brainbits/functional-test-helpers.svg?style=flat-square)](https://github.com/brainbits/functional-test-helpers/releases)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
[![Build Status](https://img.shields.io/github/check-runs/brainbits/functional-test-helpers/main)](https://github.com/brainbits/functional-test-helpers/actions)
[![Coverage Status](https://img.shields.io/codecov/c/github/brainbits/functional-test-helpers)](https://app.codecov.io/gh/brainbits/functional-test-helpers)
[![Total Downloads](https://img.shields.io/packagist/dt/brainbits/functional-test-helpers.svg?style=flat-square)](https://packagist.org/packages/brainbits/functional-test-helpers)

A collection of test helper traits for symfony projects.
Please look at the respective READMEs for details.

Expand Down
60 changes: 29 additions & 31 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
{
"name": "brainbits/functional-test-helpers",
"type": "library",
"description": "brainbits controlling functional test helpers",
"license": "MIT",
"type": "library",
"require": {
"php": "^8.3",
"thecodingmachine/safe": "^2.0"
"thecodingmachine/safe": "^2.0 || ^3.0"
},
"require-dev": {
"ext-dom": "*",
"ext-iconv": "*",
"ext-mbstring": "*",
"ext-simplexml": "*",
"ext-tidy": "*",
"brainbits/phpcs-standard": "^7.0",
"brainbits/phpstan-rules": "^3.1.2",
"dama/doctrine-test-bundle": "^8.0",
"doctrine/dbal": "^3.4",
"ergebnis/phpstan-rules": "^2.5.2",
"gemorroj/archive7z": "^5.3",
"jangregor/phpstan-prophecy": "^1.0.2",
"mikey179/vfsstream": "^1.6.11",
"monolog/monolog": "^2.3|^3.0",
"phpstan/phpstan": "^1.12.15",
"phpstan/phpstan-phpunit": "^1.4.2",
"phpstan/phpstan-symfony": "^1.4.13",
"phpunit/phpunit": "^11.4",
"brainbits/phpcs-standard": "^7.0.1",
"brainbits/phpstan-rules": "^4.0",
"dama/doctrine-test-bundle": "^8.2",
"doctrine/dbal": "^3.9",
"ergebnis/phpstan-rules": "^2.6",
"gemorroj/archive7z": "^5.7",
"mikey179/vfsstream": "^1.6.12",
"monolog/monolog": "^2.0 || ^3.0",
"phpstan/phpstan": "^2.1.4",
"phpstan/phpstan-phpunit": "^2.0.4",
"phpstan/phpstan-symfony": "^2.0.2",
"phpunit/phpunit": "^12.0.2",
"psr/http-message": "^2.0",
"riverline/multipart-parser": "^2.1",
"slam/phpstan-extensions": "^6.5.0",
"squizlabs/php_codesniffer": "^3.10",
"slam/phpstan-extensions": "^6.6.0",
"squizlabs/php_codesniffer": "^3.11.3",
"symfony/browser-kit": "^7.0",
"symfony/console": "^7.0",
"symfony/dependency-injection": "^7.0",
Expand All @@ -41,40 +40,30 @@
"symfony/security-core": "^7.0",
"symfony/security-csrf": "^7.0",
"symfony/uid": "^7.0",
"thecodingmachine/phpstan-safe-rule": "^1.2",
"thecodingmachine/phpstan-strict-rules": "^1.0"
"thecodingmachine/phpstan-safe-rule": "^1.4"
},
"suggest": {
"ext-dom": "For mocking xml requests",
"ext-iconv": "For asserting zip files",
"ext-mbstring": "For asserting zip files",
"ext-json": "For json snapshot tests",
"ext-mbstring": "For asserting zip files",
"ext-simplexml": "For mocking xml requests",
"ext-tidy": "For html snapshots",
"dama/doctrine-test-bundle": "For schema trait, when using DAMA Static Driver",
"doctrine/dbal": "For schema trait",
"doctrine/event-manager": "For schema trait",
"dama/doctrine-test-bundle": "For schema trait, when using DAMA Static Driver",
"gemorroj/archive7z": "For 7z file support",
"monolog/monolog": "For http client mock trait",
"riverline/multipart-parser": "For multipart file uploads",
"symfony/browser-kit": "For request trait",
"symfony/console": "For console trait",
"symfony/filesystem": "For request trait",
"symfony/framework-bundle": "For request trait, when using authLogin(). Requires version >= 7.0",
"symfony/http-client": "For http client mock trait",
"symfony/http-foundation": "For request trait",
"symfony/framework-bundle": "For request trait, when using authLogin(). Requires version >= 5.1",
"symfony/security-core": "For request trait",
"symfony/uid": "For uuid trait"
},
"config": {
"preferred-install": {
"*": "dist"
},
"sort-packages": true,
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
},
"autoload": {
"psr-4": {
"Brainbits\\FunctionalTestHelpers\\": "src/"
Expand All @@ -84,5 +73,14 @@
"psr-4": {
"Brainbits\\FunctionalTestHelpers\\Tests\\": "tests/"
}
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
},
"preferred-install": {
"*": "dist"
},
"sort-packages": true
}
}
12 changes: 3 additions & 9 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
parameters:
level: 6
treatPhpDocTypesAsCertain: false
paths:
- src
- tests
excludePaths:
- src/Kernel.php
- tests/bootstrap.php
- src/HttpClientMock/CallbackHandler.php # needed because of unknown classes when installed with monolog 2.x
- src/HttpClientMock/LegacyCallbackHandler.php # needed because of unknown classes when installed with monolog 2.x
ignoreErrors:
- '#Constructor in .* has parameter .* with default value#'
- '#In method "Brainbits\\FunctionalTestHelpers\\Snapshot\\IsXml::.*", caught "Throwable" must be rethrown. Either catch a more specific exception or add a "throw" clause in the "catch" block to propagate the exception.#'
- '#In method "Brainbits\\FunctionalTestHelpers\\Tests\\Uuid\\UuidTraitTest::.*", caught "Throwable" must be rethrown. Either catch a more specific exception or add a "throw" clause in the "catch" block to propagate the exception.#'
- '#Safe\\DateTimeImmutable#'
- '#SchemaBuilder::foo\(\)#'
ergebnis:
noNullableReturnTypeDeclaration:
Expand All @@ -31,9 +26,8 @@ parameters:
includes:
- %rootDir%/../../brainbits/phpstan-rules/rules.neon
- %rootDir%/../../ergebnis/phpstan-rules/rules.neon
- %rootDir%/../../jangregor/phpstan-prophecy/extension.neon
- %rootDir%/../../phpstan/phpstan-phpunit/extension.neon
- %rootDir%/../../phpstan/phpstan-phpunit/rules.neon
- %rootDir%/../../phpstan/phpstan-symfony/extension.neon
- %rootDir%/../../thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon
- %rootDir%/../../thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon
# - %rootDir%/../../thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon
# - %rootDir%/../../thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon
2 changes: 1 addition & 1 deletion src/HttpClientMock/Matcher/CatchAllMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

final readonly class CatchAllMatcher implements Matcher
{
public function __invoke(RealRequest $realRequest): Hit|Mismatch|Missing
public function __invoke(RealRequest $realRequest): Hit
{
return Hit::catchAll();
}
Expand Down
2 changes: 1 addition & 1 deletion src/HttpClientMock/Matcher/ContentMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function __construct(string|callable $content)
$this->content = $content;
}

public function __invoke(RealRequest $realRequest): Hit|Mismatch|Missing
public function __invoke(RealRequest $realRequest): Hit|Mismatch
{
$expectedContent = $this->content;
$realContent = $realRequest->getContent();
Expand Down
2 changes: 1 addition & 1 deletion src/HttpClientMock/Matcher/JsonMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function __construct(array|callable $json)
$this->json = $json;
}

public function __invoke(RealRequest $realRequest): Hit|Mismatch|Missing
public function __invoke(RealRequest $realRequest): Hit|Mismatch
{
$expectedJson = $this->json;
$realJson = $realRequest->getJson();
Expand Down
2 changes: 1 addition & 1 deletion src/HttpClientMock/Matcher/MethodMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function __construct(string|callable $method)
$this->method = $method;
}

public function __invoke(RealRequest $realRequest): Hit|Mismatch|Missing
public function __invoke(RealRequest $realRequest): Hit|Mismatch
{
$expectedMethod = $this->method;
$realMethod = $realRequest->getMethod();
Expand Down
2 changes: 1 addition & 1 deletion src/HttpClientMock/Matcher/ThatMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function __construct(callable $that)
$this->that = $that;
}

public function __invoke(RealRequest $realRequest): Hit|Mismatch|Missing
public function __invoke(RealRequest $realRequest): Hit|Mismatch
{
if (($this->that)($realRequest) === false) {
return Mismatch::mismatchingThat('returned false');
Expand Down
2 changes: 1 addition & 1 deletion src/HttpClientMock/Matcher/UriMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function __construct(string|callable $uri, private UriParams $uriParams)
$this->uri = $uri;
}

public function __invoke(RealRequest $realRequest): Hit|Mismatch|Missing
public function __invoke(RealRequest $realRequest): Hit|Mismatch
{
$realUri = $realRequest->getUri();

Expand Down
2 changes: 1 addition & 1 deletion src/HttpClientMock/Matcher/XmlMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function __construct(string|callable $xml)
$this->xml = $xml;
}

public function __invoke(RealRequest $realRequest): Hit|Mismatch|Missing
public function __invoke(RealRequest $realRequest): Hit|Mismatch
{
$expectedXml = $this->xml;
$realXml = $realRequest->getContent();
Expand Down
2 changes: 1 addition & 1 deletion src/HttpClientMock/MockRequestBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ public function hasResponse(): bool
return !$this->responses->isEmpty();
}

public function nextResponse(): MockResponseBuilder|Throwable|null
public function nextResponse(): MockResponseBuilder|Throwable
{
try {
return $this->responses->next();
Expand Down
4 changes: 2 additions & 2 deletions src/HttpClientMock/MockRequestBuilderCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function __invoke(string $method, string $url, array $options): ResponseI
$requestBuilder->assert($realRequest);
$requestBuilder->called($realRequest);

if ($requestBuilder->onMatch && is_callable($requestBuilder->onMatch)) { // @phpstan-ignore-line
if ($requestBuilder->onMatch && is_callable($requestBuilder->onMatch)) {
($requestBuilder->onMatch)($realRequest);
}

Expand All @@ -58,7 +58,7 @@ public function getCallStack(): CallStack
return CallStack::fromCallStacks(...$callStacks);
}

/** @return Traversable<MockRequestBuilder>|MockRequestBuilder[] */
/** @return Traversable<MockRequestBuilder> */
public function getIterator(): Traversable
{
yield from $this->requestBuilders;
Expand Down
2 changes: 1 addition & 1 deletion src/SevenZipContents/SevenZipArchive.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ private static function getBinary7zFromPath(): string
$binary7z = null;
foreach (self::EXECUTABLES as $executable) {
$resultCode = 0;
$binary7z = exec('which ' . escapeshellarg($executable), result_code: $resultCode); // @phpstan-ignore-line
$binary7z = exec('which ' . escapeshellarg($executable), result_code: $resultCode);

if ($resultCode === 0 && is_string($binary7z) && $binary7z !== '' && file_exists($binary7z)) {
break;
Expand Down
35 changes: 35 additions & 0 deletions tests/Application/ApplicationTraitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Brainbits\FunctionalTestHelpers\Tests\Application;

use Brainbits\FunctionalTestHelpers\Console\ApplicationTrait;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpKernel\KernelInterface;

final class ApplicationTraitTest extends TestCase
{
use ApplicationTrait;

private static KernelInterface|null $kernel = null;

public function testMockRequest(): void
{
$container = new Container();
$container->set('event_dispatcher', new EventDispatcher());

self::$kernel = $this->createMock(KernelInterface::class);
self::$kernel->expects($this->atLeastOnce())
->method('getContainer')
->willReturn($container);

$tester = $this->runApplication(['help']);

$this->assertApplicationOutputContains('help', $tester);

self::$kernel->shutdown();
}
}
31 changes: 31 additions & 0 deletions tests/Console/CommandTraitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Brainbits\FunctionalTestHelpers\Tests\Console;

use Brainbits\FunctionalTestHelpers\Console\CommandTrait;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpKernel\KernelInterface;

final class CommandTraitTest extends TestCase
{
use CommandTrait;

private static KernelInterface|null $kernel = null;

public function testMockRequest(): void
{
$container = new Container();

self::$kernel = $this->createMock(KernelInterface::class);
self::$kernel->expects($this->atLeastOnce())
->method('getContainer')
->willReturn($container);

$tester = $this->runCommand('help');

$this->assertCommandOutputContains('help', $tester);
}
}
2 changes: 0 additions & 2 deletions tests/HttpClientMock/Matcher/CatchAllMatcherTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Brainbits\FunctionalTestHelpers\Tests\HttpClientMock\Matcher;

use Brainbits\FunctionalTestHelpers\HttpClientMock\Matcher\CatchAllMatcher;
use Brainbits\FunctionalTestHelpers\HttpClientMock\Matcher\Hit;
use Brainbits\FunctionalTestHelpers\Tests\HttpClientMock\RealRequestTrait;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
Expand All @@ -24,7 +23,6 @@ public function testMatchContent(): void

$result = $matcher($realRequest);

self::assertInstanceOf(Hit::class, $result);
self::assertScore(1, $result);
self::assertMatcher('catchAll', $result);
}
Expand Down
21 changes: 0 additions & 21 deletions tests/Request/RequestBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,11 @@
use Symfony\Component\Security\Core\User\InMemoryUser;

use function current;
use function method_exists;
use function Safe\json_encode;

#[CoversClass(RequestBuilder::class)]
final class RequestBuilderTest extends TestCase
{
public function testItCanBeCreated(): void
{
$builder = RequestBuilder::create(
static fn (...$params) => $params,
static fn (...$params) => $params,
'POST',
'/test',
);

$this->assertInstanceOf(RequestBuilder::class, $builder);
}

public function testMethodIsReturned(): void
{
$builder = $this->createRequestBuilder('POST');
Expand Down Expand Up @@ -232,10 +219,6 @@ public function testAuthenticationHeadersAreSetOnAuthCall(): void

public function testAuthorizationHeaderIsSetOnAuthLoginWithDeprecatedFindUser(): void
{
if (!method_exists(KernelBrowser::class, 'loginUser')) {
$this->markTestSkipped('authLogin() only available for symfony/framework-bundle >= 5.1');
}

$browser = $this->createMock(KernelBrowser::class);
$browser->expects($this->once())
->method('loginUser')
Expand All @@ -253,10 +236,6 @@ public function testAuthorizationHeaderIsSetOnAuthLoginWithDeprecatedFindUser():

public function testAuthorizationHeaderIsSetOnAuthLoginCall(): void
{
if (!method_exists(KernelBrowser::class, 'loginUser')) {
$this->markTestSkipped('authLogin() only available for symfony/framework-bundle >= 5.1');
}

$browser = $this->createMock(KernelBrowser::class);
$browser->expects($this->never())
->method('loginUser');
Expand Down
Loading
Loading