Skip to content

Instantly share code, notes, and snippets.

@devster
Last active May 12, 2023 20:24
Show Gist options
  • Select an option

  • Save devster/ecb6f4701f5d516300b385fe83618b16 to your computer and use it in GitHub Desktop.

Select an option

Save devster/ecb6f4701f5d516300b385fe83618b16 to your computer and use it in GitHub Desktop.

Revisions

  1. devster revised this gist Jan 25, 2021. 3 changed files with 59 additions and 17 deletions.
    2 changes: 1 addition & 1 deletion ExampleTest.php
    Original file line number Diff line number Diff line change
    @@ -16,7 +16,7 @@ public function testListing()
    $client = static::createClient();
    $client->request('GET', '/channels');

    $this->openApiValidate();
    $this->assertOpenApi();

    $response = $client->getResponse();

    65 changes: 49 additions & 16 deletions OpenApiTrait.php
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,9 @@
    use League\OpenAPIValidation\PSR7\OperationAddress;
    use League\OpenAPIValidation\PSR7\SchemaFactory\YamlFileFactory;
    use League\OpenAPIValidation\PSR7\ValidatorBuilder;
    use League\OpenAPIValidation\Schema\Exception\SchemaMismatch;
    use Nyholm\Psr7\Factory\Psr17Factory;
    use PHPUnit\Framework\AssertionFailedError;
    use Psr\Http\Message\ResponseInterface;
    use Psr\Http\Message\ServerRequestInterface;
    use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
    @@ -17,9 +19,7 @@

    trait OpenApiTrait
    {
    public static array $openApiSpecFiles = [
    'channel' => __DIR__ . '/../../documentation/channel/openapi.yaml',
    ];
    public static array $openApiSpecFiles = [];

    private static string $currentOpenApiFile;

    @@ -34,26 +34,37 @@ public static function useOpenApiSchema(string $name): void
    static::$currentOpenApiFile = $name;
    }

    public static function openApiValidateRequest(Request $request): OperationAddress
    public function assertOpenApiRequest(Request $request): OperationAddress
    {
    $psrRequest = static::createPsrRequest($request);
    return static::getValidatorBuilder()->getRequestValidator()->validate($psrRequest);
    try {
    $psrRequest = static::createPsrRequest($request);
    $op = static::getValidatorBuilder()->getRequestValidator()->validate($psrRequest);
    $this->addToAssertionCount(1);
    return $op;
    } catch (\Throwable $e) {
    throw static::createAssertionError('request', $e);
    }
    }

    public static function openApiValidateResponse(OperationAddress $operationAddress, Response $response): void
    public function assertOpenApiResponse(OperationAddress $operationAddress, Response $response): void
    {
    $psrResponse = static::createPsrResponse($response);
    static::getValidatorBuilder()->getResponseValidator()->validate($operationAddress, $psrResponse);
    try {
    $psrResponse = static::createPsrResponse($response);
    static::getValidatorBuilder()->getResponseValidator()->validate($operationAddress, $psrResponse);
    $this->addToAssertionCount(1);
    } catch (\Throwable $e) {
    throw static::createAssertionError('response', $e);
    }
    }

    public static function openApiValidate(KernelBrowser $client = null): void
    public function assertOpenApi(KernelBrowser $client = null): void
    {
    $client = $client ?? static::$client;
    $request = $client->getRequest();
    $response = $client->getResponse();

    $operationAddress = static::openApiValidateRequest($request);
    static::openApiValidateResponse($operationAddress, $response);
    $operationAddress = $this->assertOpenApiRequest($request);
    $this->assertOpenApiResponse($operationAddress, $response);
    }

    /**
    @@ -69,11 +80,9 @@ protected static function createClient(array $options = [], array $server = [])
    return static::$client = parent::createClient($options, $server);
    }

    private static function getValidatorBuilder(string $name = null): ValidatorBuilder
    private static function getValidatorBuilder(): ValidatorBuilder
    {
    if (null === $name) {
    $name = static::$currentOpenApiFile;
    }
    $name = static::$currentOpenApiFile;

    if (!array_key_exists($name, static::$validatorsBuilder)) {
    $schemaFactory = new YamlFileFactory(static::$openApiSpecFiles[$name]);
    @@ -104,4 +113,28 @@ private static function getPsrHttpFactory(): PsrHttpFactory

    return static::$psrHttpFactory;
    }

    private static function createAssertionError(string $type, \Throwable $e): \Throwable
    {
    $message = "OpenApi [$type] validation error:";

    $f = function (\Throwable $e) use (&$f) {
    $message = "\n " . get_class($e) . ': ';
    $message .= $e->getMessage();

    if ($e instanceof SchemaMismatch && $bc = $e->dataBreadCrumb()) {
    $message .= "\n Breadcrumbs: " . implode(' -> ', $bc->buildChain());
    }

    if ($p = $e->getPrevious()) {
    $message .= $f($p);
    }

    return $message;
    };

    $message .= $f($e);

    return new AssertionFailedError($message);
    }
    }
    9 changes: 9 additions & 0 deletions tests_bootstrap.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    <?php

    require_once '../vendor/autoload.php';

    use OpenApiTrait;

    OpenApiTrait::$openApiSpecFiles = [
    'channel' => __DIR__ . '/../documentation/channel/openapi.yaml',
    ];
  2. devster revised this gist Jan 25, 2021. 1 changed file with 14 additions and 7 deletions.
    21 changes: 14 additions & 7 deletions OpenApiTrait.php
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,7 @@

    namespace Tests\TestCase;

    use League\OpenAPIValidation\PSR7\OperationAddress;
    use League\OpenAPIValidation\PSR7\SchemaFactory\YamlFileFactory;
    use League\OpenAPIValidation\PSR7\ValidatorBuilder;
    use Nyholm\Psr7\Factory\Psr17Factory;
    @@ -33,17 +34,14 @@ public static function useOpenApiSchema(string $name): void
    static::$currentOpenApiFile = $name;
    }

    public static function openApiValidateRequest(Request $request): void
    public static function openApiValidateRequest(Request $request): OperationAddress
    {
    $psrRequest = static::createPsrRequest($request);
    static::getValidatorBuilder()->getRequestValidator()->validate($psrRequest);
    return static::getValidatorBuilder()->getRequestValidator()->validate($psrRequest);
    }

    public static function openApiValidateResponse(Request $request, Response $response): void
    public static function openApiValidateResponse(OperationAddress $operationAddress, Response $response): void
    {
    $psrRequest = static::createPsrRequest($request);
    $operationAddress = static::getValidatorBuilder()->getServerRequestValidator()->validate($psrRequest);

    $psrResponse = static::createPsrResponse($response);
    static::getValidatorBuilder()->getResponseValidator()->validate($operationAddress, $psrResponse);
    }
    @@ -54,9 +52,18 @@ public static function openApiValidate(KernelBrowser $client = null): void
    $request = $client->getRequest();
    $response = $client->getResponse();

    static::openApiValidateResponse($request, $response);
    $operationAddress = static::openApiValidateRequest($request);
    static::openApiValidateResponse($operationAddress, $response);
    }

    /**
    * Proxy to create a KernelBrowser and keep a reference of that client.
    *
    * @param array $options An array of options to pass to the createKernel method
    * @param array $server An array of server parameters
    *
    * @return KernelBrowser A KernelBrowser instance
    */
    protected static function createClient(array $options = [], array $server = [])
    {
    return static::$client = parent::createClient($options, $server);
  3. devster revised this gist Jan 25, 2021. 2 changed files with 10 additions and 2 deletions.
    2 changes: 1 addition & 1 deletion ExampleTest.php
    Original file line number Diff line number Diff line change
    @@ -16,7 +16,7 @@ public function testListing()
    $client = static::createClient();
    $client->request('GET', '/channels');

    $this->openApiValidate($client);
    $this->openApiValidate();

    $response = $client->getResponse();

    10 changes: 9 additions & 1 deletion OpenApiTrait.php
    Original file line number Diff line number Diff line change
    @@ -26,6 +26,8 @@ trait OpenApiTrait

    private static PsrHttpFactory $psrHttpFactory;

    private static KernelBrowser $client;

    public static function useOpenApiSchema(string $name): void
    {
    static::$currentOpenApiFile = $name;
    @@ -46,14 +48,20 @@ public static function openApiValidateResponse(Request $request, Response $respo
    static::getValidatorBuilder()->getResponseValidator()->validate($operationAddress, $psrResponse);
    }

    public static function openApiValidate(KernelBrowser $client): void
    public static function openApiValidate(KernelBrowser $client = null): void
    {
    $client = $client ?? static::$client;
    $request = $client->getRequest();
    $response = $client->getResponse();

    static::openApiValidateResponse($request, $response);
    }

    protected static function createClient(array $options = [], array $server = [])
    {
    return static::$client = parent::createClient($options, $server);
    }

    private static function getValidatorBuilder(string $name = null): ValidatorBuilder
    {
    if (null === $name) {
  4. devster created this gist Jan 25, 2021.
    25 changes: 25 additions & 0 deletions ExampleTest.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,25 @@
    <?php

    namespace Tests\Infrastructure\Action\Channel;

    use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
    use Tests\TestCase\OpenApiTrait;

    class ExampleTest extends WebTestCase
    {
    use OpenApiTrait;

    public function testListing()
    {
    static::useOpenApiSchema('channel');

    $client = static::createClient();
    $client->request('GET', '/channels');

    $this->openApiValidate($client);

    $response = $client->getResponse();

    $this->assertTrue($response->isSuccessful());
    }
    }
    92 changes: 92 additions & 0 deletions OpenApiTrait.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,92 @@
    <?php

    declare(strict_types=1);

    namespace Tests\TestCase;

    use League\OpenAPIValidation\PSR7\SchemaFactory\YamlFileFactory;
    use League\OpenAPIValidation\PSR7\ValidatorBuilder;
    use Nyholm\Psr7\Factory\Psr17Factory;
    use Psr\Http\Message\ResponseInterface;
    use Psr\Http\Message\ServerRequestInterface;
    use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
    use Symfony\Bundle\FrameworkBundle\KernelBrowser;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;

    trait OpenApiTrait
    {
    public static array $openApiSpecFiles = [
    'channel' => __DIR__ . '/../../documentation/channel/openapi.yaml',
    ];

    private static string $currentOpenApiFile;

    private static array $validatorsBuilder = [];

    private static PsrHttpFactory $psrHttpFactory;

    public static function useOpenApiSchema(string $name): void
    {
    static::$currentOpenApiFile = $name;
    }

    public static function openApiValidateRequest(Request $request): void
    {
    $psrRequest = static::createPsrRequest($request);
    static::getValidatorBuilder()->getRequestValidator()->validate($psrRequest);
    }

    public static function openApiValidateResponse(Request $request, Response $response): void
    {
    $psrRequest = static::createPsrRequest($request);
    $operationAddress = static::getValidatorBuilder()->getServerRequestValidator()->validate($psrRequest);

    $psrResponse = static::createPsrResponse($response);
    static::getValidatorBuilder()->getResponseValidator()->validate($operationAddress, $psrResponse);
    }

    public static function openApiValidate(KernelBrowser $client): void
    {
    $request = $client->getRequest();
    $response = $client->getResponse();

    static::openApiValidateResponse($request, $response);
    }

    private static function getValidatorBuilder(string $name = null): ValidatorBuilder
    {
    if (null === $name) {
    $name = static::$currentOpenApiFile;
    }

    if (!array_key_exists($name, static::$validatorsBuilder)) {
    $schemaFactory = new YamlFileFactory(static::$openApiSpecFiles[$name]);
    $validatorBuilder = new ValidatorBuilder();
    $validatorBuilder->fromSchema($schemaFactory->createSchema());
    static::$validatorsBuilder[$name] = $validatorBuilder;
    }

    return static::$validatorsBuilder[$name];
    }

    private static function createPsrRequest(Request $request): ServerRequestInterface
    {
    return static::getPsrHttpFactory()->createRequest($request);
    }

    private static function createPsrResponse(Response $response): ResponseInterface
    {
    return static::getPsrHttpFactory()->createResponse($response);
    }

    private static function getPsrHttpFactory(): PsrHttpFactory
    {
    if (!isset(static::$psrHttpFactory)) {
    $psr17Factory = new Psr17Factory();
    static::$psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);
    }

    return static::$psrHttpFactory;
    }
    }
    3 changes: 3 additions & 0 deletions packages.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    league/openapi-psr7-validator
    nyholm/psr7
    symfony/psr-http-message-bridge