newman/laravel-graphql-test-utils

Laravel GraphQL 测试工具包。帮助您轻松测试 GraphQL 查询和突变。

1.2.0 2024-03-12 21:51 UTC

This package is auto-updated.

Last update: 2024-09-14 08:13:28 UTC


README

此包帮助您在 TestCases 中测试 GraphQL 查询和突变。它与任何 Laravel GraphQL 服务器一起工作。

要求

  • Laravel 8.12+, 9.0+, 10.0+, 11.0
  • PHP 8.0+

安装

通过 Composer 需要此包

composer require newman/laravel-graphql-test-utils

📖 文档 & 使用

要开始使用,请将我们的 trait 导入到您的 TestCase 中

<?php

namespace Tests;

use \Newman\LaravelGraphQLTestUtils\Traits\WithGraphQL;

class SomeTest extends TestCase {
    use WithGraphQL;

    public function test_it_returns_cars(): void
    {
        $response = $this
            ->graphql()
            ->setQuery('query ($search: String!) {
                cars(search: $search) {
                    brand
                }
            }')
            ->setVariables([
                'search' => 'BMW',
            ])
            ->call();
            
        $this->assertEquals([
            'cars' => [
                ['brand' => 'BMW'],
            ],
        ], $response->json('data'));
    }
}

现在您可以使用我们的可用构建器方法了。

默认断言

默认情况下,我们在获取响应后不为您断言任何内容,但我们提供了注册您的处理程序以自定义此行为的功能。

<?php

namespace Tests;

use Newman\LaravelGraphQLTestUtils\GraphQLTesting;
use Newman\LaravelGraphQLTestUtils\TestResponse;

class TestCase extends \Illuminate\Foundation\Testing\TestCase
{
    protected function setUp(): void
    {
        parent::setUp();
    
        GraphQlTesting::defaultAssertions(function (TestResponse $response): void {
            $response->assertOk()
                ->assertNoGraphQLErrors();
        });
    }
}

构建器方法

setQuery

设置您的 GraphQL 查询。

$this
    ->graphql()
    ->setQuery('query {
        cars {
            brand
        }
    }')
    ->call();

setVariables

设置多个 GraphQL 变量作为键值对。

$this
    ->graphql()
    ->setVariables(['name' => 'John', 'email' => 'my@email.com'])
    ->call();

// Variables will result as: ['name' => 'John', 'email' => 'my@email.com']

注意:调用 setVariables 将替换之前设置的变量。在这种情况下,您可能希望使用 mergeVariables

setVariable

逐个设置变量。

$this
    ->graphql()
    ->setVariable('name', 'Oliver')
    ->setVariable('surname', 'Smith')
    ->call();

// Variables will result as: ['name' => 'Oliver', 'surname' => 'Smith']

您还可以将其与 setVariablesmergeVariables 混合。

$this
    ->graphql()
    ->setVariables(['name' => 'James', 'email' => 'my@email.com'])
    ->setVariable('name', 'Oliver')
    ->setVariable('surname', 'Smith')
    ->mergeVariables(['surname' => 'Williams', 'birthday' => '1990-01-01'])
    ->call();

// Variables will result as: ['name' => 'Oliver', 'email' => 'my@email.com', 'surname' => 'Williams', 'birthday' => '1990-01-01']

注意:使用相同键调用 setVariable 将覆盖之前的值。

mergeVariables

setVariables 不同,此方法将先前设置的变量与一对新变量合并。

$this
    ->graphql()
    ->setVariables(['name' => 'John', 'email' => 'my@email.com'])
    ->mergeVariables(['name' => 'James'])
    ->call();

// Variables will result as: ['name' => 'James', 'email' => 'my@email.com']

schema

指定要使用的 GraphQL 架构(名称)。

$this
    ->graphql()
    ->schema('users')
    ->call();

注意:根据使用的驱动程序,它可能会根据架构自动解析要使用的 HTTP 方法。更多信息。

httpMethod

强制使用特定的 HTTP 方法。默认情况下,它将从架构(如果驱动程序提供)解析,否则将使用 POST

$this
    ->graphql()
    ->httpMethod('GET')
    ->call();

driver

您可以选择将此查询切换到默认以外的其他驱动程序。您可能不需要这样做。

$this
    ->graphql()
    ->driver('myCustom')
    ->call();

withToken

将 Bearer 授权令牌添加到请求中。

$this
    ->graphql()
    ->withToken('U88Itq0x3yHrhAgCa8mOWuUMKScGAX3zs0xHGnJnvHJoTOmpVTaDX2SVxwxQIsL8')
    ->call();

withoutToken

从请求中删除授权令牌。

$this
    ->graphql()
    ->withoutToken()
    ->call();

withHeader

将单个标头添加到请求中。

$this
    ->graphql()
    ->withHeader('Authorization', 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==')
    ->call();

withHeader

将多个标头添加到请求中。

$this
    ->graphql()
    ->withHeaders([
        'X-User-Language' => 'en',
        'X-Client' => 'GraphQL-Test',
    ])
    ->call();

modifyRequest

由于我们在基础中使用了 Laravel 的 MakesHttpRequests Trait,您也可以访问这些函数。

use \Newman\LaravelGraphQLTestUtils\GraphQLRequest;

$this
    ->graphql()
    ->modifyRequest(function (GraphQLRequest $request) {
        $request->flushHeaders();
        
        // all MakesHttpRequest public methods can be called.
        
        // https://github.com/laravel/framework/blob/9.x/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php
    })
    ->call();

withDefaultAssertionswithoutDefaultAssertions

您可能希望单独禁用或重新启用默认断言。

禁用此查询的默认断言

$this
    ->graphql()
    ->withoutDefaultAssertions()
    ->call();
function getBaseBuilder() {
    return $this->graphql()->withoutDefaultAssertions();
}

// I want them to be enabled here.
getBaseBuilder()
    ->withDefaultAssertions()
    ->call();

call

调用 GraphQL 并返回我们的 TestResponse 类。该函数有两个参数

$this
    ->graphql()
    ->call('query ($search: String!) { cars (search: $search) { brand } }', ['search' => 'BMW']);

注意:传递给此函数的变量将合并到现有的变量中。

响应

我们通过一些与 GraphQL 相关的函数/断言扩展了默认的 Laravel 的 Illuminate\Testing\TestResponse

assertNoGraphQLErrors

断言没有返回 GraphQL 错误。

assertGraphQLUnauthorized

断言存在未授权错误,格式为相应的 GraphQL 错误。

getQuery

访问请求中使用的查询。

getVariables

访问请求中使用的变量。

getGraphQLErrors

返回 GraphQL 错误的 array 或不存在时返回 null

hasGraphQLErrors

确定是否存在任何 GraphQL 错误。

getGraphQLValidationMessages

获取 Laravel 验证消息列表或为空数组时。

[
    'name' => ['This field is required.', 'It must be a string'],
    // ...
]

getValidationFieldMessages

获取特定字段的 Laravel 验证消息或空数组(当没有或字段不存在时)。

$messages = $response->getValidationFieldMessages('name'); // ['This field is required.', 'It must be a string']

getValidationFieldFirstMessage

获取特定字段的第一个 Laravel 验证消息或 null(当没有或字段不存在时)。

$message = $response->getValidationFieldFirstMessage('name'); // 'This field is required.'

ℹ️ 记住,您也可以访问所有 Illuminate\Testing\TestResponse 函数。

❓ 缺少频繁使用的响应辅助函数?请打开一个新问题。

自定义响应类

此示例向您展示如何使用自定义函数创建自己的 TestResponse 类。

<?php

declare(strict_types=1);

namespace App\Support;

use Newman\LaravelGraphQLTestUtils\TestResponse;

class CustomTestResponse extends TestResponse 
{

    public function assertDataAlwaysContainsAge(): static 
    {
        if (!$this->json('data.age')) {
            Assert::fail('Failed to assert that response contains age key.');
        }
    }
}

然后在您的 ServiceProvider(例如 AppServiceProvider)或 TestCase 中

<?php

namespace App\Providers;

use App\Support\CustomTestResponse;
use Newman\LaravelGraphQLTestUtils\GraphQLTesting;

class AppServiceProvider extends \Illuminate\Support\ServiceProvider
{

    public function boot()
    {
        GraphQLTesting::useCustomResponseHandler(CustomTestResponse::class);
    }
}

自定义构建器类

此示例向您展示如何使用自定义函数创建自己的 GraphQLBuilder 类。

<?php

declare(strict_types=1);

namespace App\Support;

use App\Models\User;
use Newman\LaravelGraphQLTestUtils\GraphQLBuilder;

class CustomGraphQLBuilder extends GraphQLBuilder 
{

    public function withUser(User $user): static 
    {
        $this->withToken($user->api_token)
    
        return $this;
    }
}

然后在您的 ServiceProvider(例如 AppServiceProvider)中

<?php

namespace App\Providers;

use App\Support\CustomGraphQLBuilder;
use Newman\LaravelGraphQLTestUtils\Contracts\GraphQLBuilderContract;

class AppServiceProvider extends \Illuminate\Support\ServiceProvider
{

    public function register()
    {
        $this->app->bind(GraphQLBuilderContract::class, CustomGraphQLBuilder::class);
    }
}

驱动器

驱动器通过从 GraphQL 服务器配置中提取信息来帮助您构建请求,因此您可以省略一些构建器调用。如果您需要的不是我们提供的任何驱动器,您可以编写自己的自定义驱动器。

RebingDriver(默认)

https://github.com/rebing/graphql-laravel

它从配置 graphql.route.prefix 读取 URL 前缀,并根据模式名称从配置中获取第一个 HTTP 方法。

这是默认驱动器。

NullDriver

它使用 /graphql URL 前缀和 POST HTTP 方法。

要使用,请在 AppServiceProvider.phpboot() 方法中调用 GraphQLTesting::useNullDriver()

自定义驱动器

以下是如何实现名为 myCustom 的自定义驱动器的示例。

<?php

declare(strict_types=1);

namespace App\Support\GraphQLTestingDrivers;

use Illuminate\Contracts\Config\Repository as ConfigContract;
use Illuminate\Contracts\Container\Container;
use Newman\LaravelGraphQLTestUtils\Contracts\DriverContract;

class MyCustomDriver implements DriverContract
{
    /**
     * @var Container
     */
    protected $app;

    public function __construct(Container $app)
    {
        $this->app = $app;
    }

    public function getUrlPrefix(): ?string
    {
        // ... return your url prefix to GraphQL endpoint. in this case it would be /my-graphql
        // returning null will fallback to default URL prefix.
        return 'my-graphql';
    }

    public function getHttpMethodForSchema(string $schemaName): ?string
    {
        // ... detect HTTP method from schema name and return it.
        // below is an example. You may read it from config or resolve any other way.
        // returning null will fallback to default HTTP method.
        return $schemaName == 'default' ? 'GET' : 'POST';
    }
}

然后在您的 ServiceProvider(例如 AppServiceProvider)中

<?php

namespace App\Providers;

use App\Support\GraphQLTestingDrivers\MyCustomDriver;
use Newman\LaravelGraphQLTestUtils\GraphQLTesting;

class AppServiceProvider extends \Illuminate\Support\ServiceProvider
{
    public function boot()
    {
        // to activate this driver
        
        GraphQlTesting::useDriver('myCustom');
    }
    
    public function register()
    {
        // ... your other bindings
        $this->app->bind('laravel-graphql-utils-driver:myCustom', MyCustomDriver::class);
    }
}

🤝 贡献

我们感谢您为此包提供合作。

在制作拉取请求时,请确保

  • 所有测试都通过: composer test
  • 测试覆盖率没有降低: composer test-coverage
  • 没有 PHPStan 错误: composer phpstan
  • 遵循编码规范: composer lintcomposer fix-style 以自动修复。