Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide assertion helpers through TestResponseMixin #1308

Merged
merged 5 commits into from
Apr 19, 2020
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
2 changes: 0 additions & 2 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
/.gitattributes export-ignore
/.gitignore export-ignore
/.styleci.yml export-ignore
/_ide_helper.php export-ignore
/CHANGELOG.md export-ignore
/CONTRIBUTING.md export-ignore
/docker-compose.yml export-ignore
/Dockerfile export-ignore
/logo.png export-ignore
/logo.png export-ignore
/Makefile export-ignore
/netlify.toml export-ignore
/phpbench.json export-ignore
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ You can find and compare releases at the [GitHub release page](https://github.co

- Add flag `--json` to `print-schema` to output JSON instead of GraphQL SDL https://github.com/nuwave/lighthouse/pull/1268
- Add TTL option for subscriptions storage https://github.com/nuwave/lighthouse/pull/1284
- Provide assertion helpers through `TestResponseMixin` https://github.com/nuwave/lighthouse/pull/1308

### Fixed

Expand Down
82 changes: 76 additions & 6 deletions _ide_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,43 @@ class TestResponse
/**
* Asserts that the response contains an error from a given category.
*
* @param string $category
* @param string $category The name of the expected error category.
* @return $this
*/
public function assertErrorCategory(string $category): self
public function assertGraphQLErrorCategory(string $category): self
{
return $this;
}

/**
* Assert that the returned result contains exactly the given validation keys.
*
* @param array $keys The validation keys the result should have.
* @return $this
*/
public function assertGraphQLValidationKeys(array $keys): self
{
return $this;
}

/**
* Assert that a given validation error is present in the response.
*
* @param string $key The validation key that should be present.
* @param string $message The expected validation message.
* @return $this
*/
public function assertGraphQLValidationError(string $key, string $message): self
{
return $this;
}

/**
* Assert that no validation errors are present in the response.
*
* @return $this
*/
public function assertGraphQLValidationPasses(): self
{
return $this;
}
Expand All @@ -20,7 +53,8 @@ public function assertErrorCategory(string $category): self
* @param string|null $key
* @return mixed
*/
public function jsonGet(string $key = null) {
public function jsonGet(string $key = null)
{
return;
}
}
Expand All @@ -32,10 +66,43 @@ class TestResponse
/**
* Asserts that the response contains an error from a given category.
*
* @param string $category
* @param string $category The name of the expected error category.
* @return $this
*/
public function assertErrorCategory(string $category): self
public function assertGraphQLErrorCategory(string $category): self
{
return $this;
}

/**
* Assert that the returned result contains exactly the given validation keys.
*
* @param array $keys The validation keys the result should have.
* @return $this
*/
public function assertGraphQLValidationKeys(array $keys): self
{
return $this;
}

/**
* Assert that a given validation error is present in the response.
*
* @param string $key The validation key that should be present.
* @param string $message The expected validation message.
* @return $this
*/
public function assertGraphQLValidationError(string $key, string $message): self
{
return $this;
}

/**
* Assert that no validation errors are present in the response.
*
* @return $this
*/
public function assertGraphQLValidationPasses(): self
{
return $this;
}
Expand All @@ -46,7 +113,8 @@ public function assertErrorCategory(string $category): self
* @param string|null $key
* @return mixed
*/
public function jsonGet(string $key = null) {
public function jsonGet(string $key = null)
{
return;
}
}
Expand All @@ -56,6 +124,8 @@ public function jsonGet(string $key = null) {
class ResolveInfo
{
/**
* We monkey patch this onto here to pass it down the resolver chain.
*
* @var \Nuwave\Lighthouse\Execution\Arguments\ArgumentSet
*/
public $argumentSet;
Expand Down
23 changes: 23 additions & 0 deletions docs/master/testing/phpunit.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,29 @@ public function testOrdersUsersByName(): void
}
```

### TestResponse Assertion Mixins

Lighthouse conveniently provides additional assertions as mixins to the `TestResponse` class.
Make sure to publish the latest [IDE-helper file](/_ide_helper.php) to get proper autocompletion:

```bash
php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=ide-helper
```

The provided assertions are prefixed with `assertGraphQL` for easy discovery.
They offer useful shortcuts to common testing tasks.
For example, you might want to ensure that validation works properly:

```php
$this
->graphQL(/** @lang GraphQL */ '
mutation {
createUser(email: "invalid email")
}
')
->assertGraphQLValidationKeys(['email']);
```

## Simulating File Uploads

Lighthouse allows you to [upload files](../digging-deeper/file-uploads.md) through GraphQL.
Expand Down
6 changes: 4 additions & 2 deletions src/Exceptions/ValidationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

class ValidationException extends \Illuminate\Validation\ValidationException implements RendersErrorsExtensions
{
const CATEGORY = 'validation';

/**
* Returns true when exception message is safe to be displayed to a client.
*
Expand All @@ -21,7 +23,7 @@ public function isClientSafe()
*/
public function getCategory()
{
return 'validation';
return self::CATEGORY;
}

/**
Expand All @@ -30,6 +32,6 @@ public function getCategory()
*/
public function extensionsContent(): array
{
return ['validation' => $this->errors()];
return [self::CATEGORY => $this->errors()];
}
}
5 changes: 4 additions & 1 deletion src/LighthouseServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ public function boot(ValidationFactory $validationFactory, ConfigRepository $con
__DIR__.'/../assets/default-schema.graphql' => $configRepository->get('lighthouse.schema.register'),
], 'schema');

$this->publishes([
__DIR__.'/../_ide_helper.php' => $this->app->make('path.base').'/_lighthouse_ide_helper.php',
], 'ide-helper');

$this->loadRoutesFrom(__DIR__.'/Support/Http/routes.php');

$validationFactory->resolver(
Expand Down Expand Up @@ -112,7 +116,6 @@ public function register(): void
$this->app->singleton(CanStreamResponse::class, ResponseStream::class);

$this->app->bind(CreatesResponse::class, SingleResponse::class);

$this->app->bind(GlobalIdContract::class, GlobalId::class);

$this->app->singleton(GraphQLRequest::class, function (Container $app): GraphQLRequest {
Expand Down
2 changes: 1 addition & 1 deletion src/Testing/MakesGraphQLRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Symfony\Component\HttpFoundation\StreamedResponse;

/**
* Useful helpers for PHPUnit testing.
* Testing helpers for making requests to the GraphQL endpoint.
*
* @mixin \Illuminate\Foundation\Testing\Concerns\MakesHttpRequests
*/
Expand Down
86 changes: 86 additions & 0 deletions src/Testing/TestResponseMixin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace Nuwave\Lighthouse\Testing;

use Closure;
use PHPUnit\Framework\Assert;

/**
* @mixin \Illuminate\Foundation\Testing\TestResponse
*/
class TestResponseMixin
{
public function assertGraphQLValidationError(): Closure
{
return function (string $key, ?string $message) {
$this->assertJson([
'errors' => [
[
'extensions' => [
'validation' => [
$key => [
$message,
],
],
],
],
],
]);

return $this;
};
}

public function assertGraphQLValidationKeys(): Closure
{
return function (array $keys) {
$validation = TestResponseUtils::extractValidationErrors($this);

Assert::assertSame(
$keys,
array_keys($validation['extensions']['validation']),
'Expected the query to return validation errors for specific fields.'
);

return $this;
};
}

public function assertGraphQLValidationPasses(): Closure
{
return function () {
$validation = TestResponseUtils::extractValidationErrors($this);

Assert::assertNull(
$validation,
'Expected the query to have no validation errors.'
);

return $this;
};
}

public function assertGraphQLErrorCategory(): Closure
{
return function (string $category) {
$this->assertJson([
'errors' => [
[
'extensions' => [
'category' => $category,
],
],
],
]);

return $this;
};
}

public function jsonGet(): Closure
{
return function (string $key = null) {
return data_get($this->decodeResponseJson(), $key);
};
}
}
29 changes: 29 additions & 0 deletions src/Testing/TestResponseUtils.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Nuwave\Lighthouse\Testing;

use Illuminate\Support\Arr;
use Nuwave\Lighthouse\Exceptions\ValidationException;

/**
* Because we can not have non-mixin methods in mixin classes.
*
* @see \Nuwave\Lighthouse\Testing\TestResponseMixin
*/
class TestResponseUtils
{
/**
* @param \Illuminate\Foundation\Testing\TestResponse|\Illuminate\Testing\TestResponse $response
*/
public static function extractValidationErrors($response): ?array
{
$errors = $response->json('errors') ?? [];

return Arr::first(
$errors,
function (array $error): bool {
return Arr::get($error, 'extensions.category') === ValidationException::CATEGORY;
}
);
}
}
6 changes: 6 additions & 0 deletions src/Testing/TestingServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,11 @@ static function (): string {
public function register(): void
{
$this->app->singleton(MockDirective::class);

if (class_exists('Illuminate\Testing\TestResponse')) {
\Illuminate\Testing\TestResponse::mixin(new TestResponseMixin());
} elseif (class_exists('Illuminate\Foundation\Testing\TestResponse')) {
\Illuminate\Foundation\Testing\TestResponse::mixin(new TestResponseMixin());
}
}
}
2 changes: 1 addition & 1 deletion tests/Integration/Schema/Directives/CanDirectiveDBTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ public function testThrowsIfNotAuthorized(): void
title
}
}
")->assertErrorCategory(AuthorizationException::CATEGORY);
")->assertGraphQLErrorCategory(AuthorizationException::CATEGORY);
}

public function testCanHandleMultipleModels(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ public function testHandlesPaginationWithCountZero(): void
'tasks' => null,
],
],
])->assertErrorCategory(Error::CATEGORY_GRAPHQL);
])->assertGraphQLErrorCategory(Error::CATEGORY_GRAPHQL);
}

public function testRelayTypeIsLimitedByMaxCountFromDirective(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ public function testHandlesPaginationWithCountZero(): void
'images' => null,
],
],
])->assertErrorCategory(Error::CATEGORY_GRAPHQL);
])->assertGraphQLErrorCategory(Error::CATEGORY_GRAPHQL);
}

public function testCanQueryMorphManyPaginatorWithADefaultCount(): void
Expand Down
Loading