├── .github ├── FUNDING.yml └── workflows │ ├── psalm.yml │ └── run-tests.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── composer.json ├── phpunit.xml.dist ├── psalm.xml.dist ├── src ├── GraphQLClient.php ├── QueryBuilder.php ├── Scalar.php ├── Scalars │ ├── BooleanType.php │ ├── EnumType.php │ ├── NullType.php │ └── StringType.php └── TestGraphQL.php └── tests ├── FakeTestCase.php ├── GraphQLClientTest.php ├── QueryBuilderTest.php ├── TestCase.php └── TestGraphQLTest.php /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [marvinrabe] 4 | -------------------------------------------------------------------------------- /.github/workflows/psalm.yml: -------------------------------------------------------------------------------- 1 | name: Psalm 2 | 3 | on: 4 | push: 5 | paths: 6 | - '**.php' 7 | - 'psalm.xml.dist' 8 | 9 | jobs: 10 | psalm: 11 | name: psalm 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Setup PHP 17 | uses: shivammathur/setup-php@v2 18 | with: 19 | php-version: '7.4' 20 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick 21 | coverage: none 22 | 23 | - name: Cache composer dependencies 24 | uses: actions/cache@v2 25 | with: 26 | path: vendor 27 | key: composer-${{ hashFiles('composer.lock') }} 28 | 29 | - name: Run composer install 30 | run: composer install -n --prefer-dist 31 | 32 | - name: Run psalm 33 | run: ./vendor/bin/psalm --output-format=github -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | fail-fast: true 10 | matrix: 11 | php: [7.4, 8.0, 8.1] 12 | 13 | name: P${{ matrix.php }} 14 | 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v2 18 | 19 | - name: Setup PHP 20 | uses: shivammathur/setup-php@v2 21 | with: 22 | php-version: ${{ matrix.php }} 23 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick 24 | coverage: none 25 | 26 | - name: Setup problem matchers 27 | run: | 28 | echo "::add-matcher::${{ runner.tool_cache }}/php.json" 29 | echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" 30 | - name: Install dependencies 31 | run: composer install --prefer-dist --no-interaction 32 | - name: Execute tests 33 | run: vendor/bin/phpunit 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .php_cs 3 | .php_cs.cache 4 | .phpunit.result.cache 5 | build 6 | composer.lock 7 | coverage 8 | docs 9 | phpunit.xml 10 | psalm.xml 11 | vendor -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Marvin Rabe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GraphQL Testing Helper for Laravel 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/marvinrabe/laravel-graphql-test.svg?style=flat-square)](https://packagist.org/packages/marvinrabe/laravel-graphql-test) 4 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/marvinrabe/laravel-graphql-test/run-tests.yml?branch=master)](https://github.com/marvinrabe/laravel-graphql-test/actions?query=workflow%3ATests+branch%3Amaster) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/marvinrabe/laravel-graphql-test.svg?style=flat-square)](https://packagist.org/packages/marvinrabe/laravel-graphql-test) 6 | 7 | Elegant GraphQL testing utilities for Laravel. Works with any GraphQL library. Especially with [Lighthouse](https://lighthouse-php.com/). 8 | 9 | ## Installation 10 | 11 | You can install the package via composer: 12 | 13 | ```bash 14 | composer require --dev marvinrabe/laravel-graphql-test 15 | ``` 16 | 17 | And then add the trait to your `TestCase` class: 18 | 19 | ```php 20 | query('account', ['id' => 123], ['id']); 46 | ``` 47 | 48 | Note that this function returns an `\Illuminate\Foundation\Testing\TestResponse`. Therefore you might use any Laravel testing methods. For example: 49 | 50 | ```php 51 | $this->query('account', ['id' => 123], ['id']) 52 | ->assertSuccessful() 53 | ->assertJsonFragment([ 54 | 'id' => 123 55 | ]); 56 | ``` 57 | 58 | With nested resources: 59 | 60 | ```php 61 | $this->query('account', ['id' => 123], ['transactions' => ['id']]); 62 | ``` 63 | 64 | Without a third argument it will be assumed that the second one is the selection set: 65 | 66 | ```php 67 | $this->query('accounts', ['id']); 68 | ``` 69 | 70 | When you only pass the object name, you get the `GraphQLClient` instead of the Laravel `TestResponse`: 71 | 72 | ```php 73 | $this->query('accounts')->getGql(); 74 | ``` 75 | 76 | ### Mutations 77 | 78 | Same as queries: 79 | 80 | ```php 81 | $this->mutation('accounts')->getGql(); 82 | $this->mutation('accounts', ['id']); 83 | $this->mutation('accounts', ['id' => 123]); 84 | ``` 85 | 86 | ### Argument Order 87 | 88 | For simplicity you can find the correct argument order in the following table: 89 | 90 | | Method | Arguments | Returns | 91 | |---------:|----------------------------------:|--------------:| 92 | | query | (object) | GraphQLClient | 93 | | query | (object, selectionSet) | TestResponse | 94 | | query | (object, arguments, selectionSet) | TestResponse | 95 | | mutation | (object) | GraphQLClient | 96 | | mutation | (object, selectionSet) | TestResponse | 97 | | mutation | (object, arguments, selectionSet) | TestResponse | 98 | 99 | ### Enums 100 | 101 | Because PHP has no built in Enum support. You have to use the provided enum helper: 102 | 103 | ```php 104 | $this->query('accounts', ['status' => $this->enum('closed')], ['id']); 105 | ``` 106 | 107 | Or create a `EnumType` manually: 108 | 109 | ```php 110 | $this->query('accounts', ['status' => new \MarvinRabe\LaravelGraphQLTest\Scalars\EnumType('closed')], ['id']); 111 | ``` 112 | 113 | ### Headers 114 | 115 | You can add additional HTTP headers by using `withHeader` or `withHeaders` methods provided by Laravel. For example: 116 | 117 | $this->withHeaders(["Authorization" => "Bearer TOKEN"])->query('accounts', ['id']); 118 | 119 | If you always provide the same headers, you could define them on your TestCase. 120 | 121 | ```php 122 | class AccountsTest extends TestCase 123 | { 124 | protected $defaultHeaders = [ 125 | "Authorization" => "Bearer TOKEN", 126 | ]; 127 | 128 | // ... 129 | } 130 | ``` 131 | 132 | ### Limitations 133 | 134 | The `QueryBuilder` provided by this library is not safe for use in production code. It is designed for ease of use and does not comply to the GraphQL specifications fully. Use it only for testing purposes! You have been warned. 135 | 136 | ## Testing 137 | 138 | ``` bash 139 | composer test 140 | ``` 141 | 142 | ## License 143 | 144 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 145 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "marvinrabe/laravel-graphql-test", 3 | "description": "Provides you with a simple GraphQL testing trait.", 4 | "keywords": [ 5 | "php", 6 | "laravel", 7 | "graphql", 8 | "testing" 9 | ], 10 | "homepage": "https://github.com/marvinrabe/laravel-graphql-test", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Marvin Rabe", 15 | "email": "marvin@rabe.pro", 16 | "homepage": "https://www.rabe.pro", 17 | "role": "Developer" 18 | } 19 | ], 20 | "require": { 21 | "php": ">=7.0.0", 22 | "illuminate/contracts": ">=8.0.0" 23 | }, 24 | "require-dev": { 25 | "orchestra/testbench": "^6.0", 26 | "phpunit/phpunit": "^9.3", 27 | "vimeo/psalm": "^3.11" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "MarvinRabe\\LaravelGraphQLTest\\": "src" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "MarvinRabe\\LaravelGraphQLTest\\Tests\\": "tests" 37 | } 38 | }, 39 | "scripts": { 40 | "psalm": "vendor/bin/psalm", 41 | "test": "vendor/bin/phpunit --colors=always", 42 | "test-coverage": "vendor/bin/phpunit --coverage-html coverage" 43 | }, 44 | "config": { 45 | "sort-packages": true 46 | }, 47 | "minimum-stability": "dev", 48 | "prefer-stable": true 49 | } 50 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | tests 16 | 17 | 18 | 19 | 20 | ./src 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /psalm.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/GraphQLClient.php: -------------------------------------------------------------------------------- 1 | builder = $builder; 20 | $this->endpoint = $fun; 21 | } 22 | 23 | public static function query($object, $fun) 24 | { 25 | return new self(new QueryBuilder("query", $object), $fun); 26 | } 27 | 28 | public static function mutation($object, $fun) 29 | { 30 | return new self(new QueryBuilder("mutation", $object), $fun); 31 | } 32 | 33 | public function setArguments(array $arguments = null) 34 | { 35 | $this->builder->setArguments($arguments ?? []); 36 | 37 | return $this; 38 | } 39 | 40 | public function setSelectionSet(array $selectionSet = null) 41 | { 42 | $this->builder->setSelectionSet($selectionSet ?? []); 43 | 44 | return $this; 45 | } 46 | 47 | /** 48 | * @psalm-suppress UndefinedDocblockClass 49 | * @return \Illuminate\Testing\TestResponse 50 | */ 51 | public function getData() 52 | { 53 | return ($this->endpoint)($this->getGql()); 54 | } 55 | 56 | public function getGql(): string 57 | { 58 | return $this->builder->getGql(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/QueryBuilder.php: -------------------------------------------------------------------------------- 1 | operation = $operation; 29 | $this->object = $object; 30 | } 31 | 32 | public function setSelectionSet(array $selectionSet) 33 | { 34 | $this->selectionSet = $selectionSet; 35 | 36 | return $this; 37 | } 38 | 39 | public function setArguments(array $arguments) 40 | { 41 | $this->arguments = $arguments; 42 | 43 | return $this; 44 | } 45 | 46 | public function getGql(): string 47 | { 48 | return sprintf('%s { %s }', $this->operation, implode("", [ 49 | $this->object, 50 | $this->arguments(), 51 | $this->selectionSet(), 52 | ])); 53 | } 54 | 55 | protected function arguments() 56 | { 57 | if (count($this->arguments) == 0) { 58 | return ''; 59 | } 60 | 61 | return sprintf('(%s)', $this->formatArgument($this->arguments)); 62 | } 63 | 64 | protected function formatArgument($arguments) 65 | { 66 | array_walk($arguments, function (&$value, $key) { 67 | $value = sprintf('%s: %s', $key, $this->formatValue($value)); 68 | }); 69 | 70 | return implode(', ', $arguments); 71 | } 72 | 73 | protected function formatValue($value) 74 | { 75 | if (is_array($value) && $this->is_assoc($value)) { 76 | return sprintf("{%s}", $this->formatArgument($value)); 77 | } elseif (is_array($value)) { 78 | return $this->formatArray($value); 79 | } 80 | 81 | return $this->formatScalar($value); 82 | } 83 | 84 | protected function is_assoc(array $array) 85 | { 86 | return count(array_filter(array_keys($array), 'is_string')) > 0; 87 | } 88 | 89 | protected function formatArray(array $value) 90 | { 91 | return sprintf('[%s]', implode(', ', array_map(function ($value) { 92 | return $this->formatValue($value); 93 | }, $value))); 94 | } 95 | 96 | protected function formatScalar($scalar) 97 | { 98 | foreach ($this->convertScalars as $scalarType) { 99 | /** 100 | * @var class-string $scalarType 101 | */ 102 | if ($scalarType::match($scalar)) { 103 | return new $scalarType($scalar); 104 | } 105 | } 106 | 107 | return (string) $scalar; 108 | } 109 | 110 | protected function selectionSet() 111 | { 112 | if (count($this->selectionSet) == 0) { 113 | return ''; 114 | } 115 | 116 | return $this->formatSelectionSet($this->selectionSet); 117 | } 118 | 119 | protected function formatSelectionSet($selectionSet) 120 | { 121 | array_walk($selectionSet, function (&$value, $key) { 122 | if (is_array($value)) { 123 | $value = sprintf('%s %s', $key, $this->formatSelectionSet($value)); 124 | } 125 | }); 126 | 127 | return sprintf("{\n%s\n}", implode("\n", $selectionSet)); 128 | } 129 | 130 | public function __toString() 131 | { 132 | return $this->getGql(); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/Scalar.php: -------------------------------------------------------------------------------- 1 | value = $value; 14 | } 15 | 16 | public function __toString() 17 | { 18 | return $this->value ? 'true' : 'false'; 19 | } 20 | 21 | public static function match($value): bool 22 | { 23 | return is_bool($value); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Scalars/EnumType.php: -------------------------------------------------------------------------------- 1 | value = $value; 14 | } 15 | 16 | public function __toString() 17 | { 18 | return $this->value; 19 | } 20 | 21 | public static function match($value): bool 22 | { 23 | return false; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Scalars/NullType.php: -------------------------------------------------------------------------------- 1 | value = $value; 14 | } 15 | 16 | public function __toString() 17 | { 18 | $escaped = str_replace('\\', '\\\\', $this->value); 19 | $escaped = str_replace('"', '\"', $escaped); 20 | 21 | return sprintf('"%s"', $escaped); 22 | } 23 | 24 | public static function match($value): bool 25 | { 26 | return is_string($value); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/TestGraphQL.php: -------------------------------------------------------------------------------- 1 | postJson( 27 | $this->graphQLEndpoint ?? 'graphql', 28 | [ 29 | 'query' => $query, 30 | ] 31 | ); 32 | }); 33 | 34 | return $this->prepareClient($client, $arguments, $selection); 35 | } 36 | 37 | /** 38 | * Returns a TestGraphQL client. If no arguments and selection is provided, it will query the server directly. 39 | * @param string $object GraphQL query name 40 | * @param array|null $arguments Specifies arguments send to the server. When selection is null it will be used as a selection set instead. 41 | * @param array|null $selection Specifies Selection set send to the server. 42 | * @return GraphQLClient|\Illuminate\Testing\TestResponse 43 | */ 44 | public function mutation(string $object, $arguments = null, $selection = null) 45 | { 46 | $client = GraphQLClient::mutation($object, function ($query) { 47 | return $this->postJson( 48 | $this->graphQLEndpoint ?? 'graphql', 49 | [ 50 | 'query' => $query, 51 | ] 52 | ); 53 | }); 54 | 55 | return $this->prepareClient($client, $arguments, $selection); 56 | } 57 | 58 | private function prepareClient(GraphQLClient $client, $arguments, $selection) 59 | { 60 | if (! is_null($arguments) && is_null($selection)) { 61 | $client->setSelectionSet($arguments); 62 | 63 | return $client->getData(); 64 | } 65 | 66 | if (! is_null($arguments) && ! is_null($selection)) { 67 | $client->setArguments($arguments); 68 | $client->setSelectionSet($selection); 69 | 70 | return $client->getData(); 71 | } 72 | 73 | return $client; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/FakeTestCase.php: -------------------------------------------------------------------------------- 1 | uri = $uri; 18 | $this->data = $data; 19 | $this->headers = $headers; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/GraphQLClientTest.php: -------------------------------------------------------------------------------- 1 | setArguments(null); 14 | $client->setSelectionSet(null); 15 | 16 | $this->assertEquals('query { foo }', $client->getGql()); 17 | } 18 | 19 | public function testReturnsQuery() 20 | { 21 | $client = GraphQLClient::query('foo', function () { 22 | }); 23 | $client->setArguments(['id' => 123]); 24 | $client->setSelectionSet(['bar']); 25 | 26 | $this->assertEquals("query { foo(id: 123){\nbar\n} }", $client->getGql()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/QueryBuilderTest.php: -------------------------------------------------------------------------------- 1 | setArguments([]); 13 | $qb->setSelectionSet([]); 14 | 15 | $this->assertEquals("query { foo }", $qb->getGql()); 16 | } 17 | 18 | public function testFormatSelectionSet() 19 | { 20 | $qb = new QueryBuilder('query', 'acme'); 21 | $qb->setSelectionSet([ 22 | 'foo', 23 | 'bar', 24 | ]); 25 | 26 | $this->assertEquals("query { acme{\nfoo\nbar\n} }", $qb->getGql()); 27 | } 28 | 29 | public function testFormatNestedQueries() 30 | { 31 | $qb = new QueryBuilder('query', 'acme'); 32 | $qb->setSelectionSet([ 33 | 'foo' => ['bar'], 34 | ]); 35 | 36 | $this->assertEquals("query { acme{\nfoo {\nbar\n}\n} }", $qb->getGql()); 37 | } 38 | 39 | public function testFormatStringAttributes() 40 | { 41 | $qb = new QueryBuilder('mutation', 'foo'); 42 | $qb->setArguments([ 43 | 'bar' => 'Jonathan "Johnny" Johnson', 44 | ]); 45 | 46 | $this->assertEquals('mutation { foo(bar: "Jonathan \"Johnny\" Johnson") }', $qb->getGql()); 47 | } 48 | 49 | public function testFormatsBoolean() 50 | { 51 | $qb = new QueryBuilder('mutation', 'foo'); 52 | $qb->setArguments([ 53 | 'bar' => true, 54 | ]); 55 | 56 | $this->assertEquals('mutation { foo(bar: true) }', $qb->getGql()); 57 | } 58 | 59 | public function testFormatsInputArguments() 60 | { 61 | $qb = new QueryBuilder('mutation', 'foo'); 62 | $qb->setArguments([ 63 | 'bar' => ['a' => 1, 'b' => 2, 'c' => 3], 64 | ]); 65 | 66 | $this->assertEquals('mutation { foo(bar: {a: 1, b: 2, c: 3}) }', $qb->getGql()); 67 | } 68 | 69 | public function testFormatsArrayArguments() 70 | { 71 | $qb = new QueryBuilder('mutation', 'foo'); 72 | $qb->setArguments([ 73 | 'bar' => [1, 2, 3], 74 | ]); 75 | 76 | $this->assertEquals('mutation { foo(bar: [1, 2, 3]) }', $qb->getGql()); 77 | } 78 | 79 | public function testFormatInputsInArrayArgument() 80 | { 81 | $qb = new QueryBuilder('mutation', 'foo'); 82 | $qb->setArguments([ 83 | 'bar' => [['a' => 1], ['a' => 2], ['a' => 3]], 84 | ]); 85 | 86 | $this->assertEquals('mutation { foo(bar: [{a: 1}, {a: 2}, {a: 3}]) }', $qb->getGql()); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | enum('payed'); 15 | 16 | $this->assertInstanceOf(EnumType::class, $result); 17 | $this->assertEquals('payed', (string) $result); 18 | } 19 | 20 | public function testQueryOneArgument() 21 | { 22 | $testCase = new FakeTestCase(); 23 | 24 | $result = $testCase->query('accounts'); 25 | 26 | $this->assertInstanceOf(GraphQLClient::class, $result); 27 | } 28 | 29 | public function testQueryTwoArguments() 30 | { 31 | $testCase = new FakeTestCase(); 32 | 33 | $testCase->query('accounts', ['id']); 34 | 35 | $this->assertEquals('graphql', $testCase->uri); 36 | $this->assertEquals(['query' => "query { accounts{\nid\n} }"], $testCase->data); 37 | } 38 | 39 | public function testQueryThreeArguments() 40 | { 41 | $testCase = new FakeTestCase(); 42 | 43 | $testCase->query('accounts', ['id' => 123], ['id']); 44 | 45 | $this->assertEquals('graphql', $testCase->uri); 46 | $this->assertEquals(['query' => "query { accounts(id: 123){\nid\n} }"], $testCase->data); 47 | } 48 | 49 | public function testMutationOneArgument() 50 | { 51 | $testCase = new FakeTestCase(); 52 | 53 | $result = $testCase->mutation('createAccount'); 54 | 55 | $this->assertInstanceOf(GraphQLClient::class, $result); 56 | } 57 | 58 | public function testMutationTwoArguments() 59 | { 60 | $testCase = new FakeTestCase(); 61 | 62 | $testCase->mutation('createAccount', ['id']); 63 | 64 | $this->assertEquals('graphql', $testCase->uri); 65 | $this->assertEquals(['query' => "mutation { createAccount{\nid\n} }"], $testCase->data); 66 | } 67 | 68 | public function testMutationThreeArguments() 69 | { 70 | $testCase = new FakeTestCase(); 71 | 72 | $testCase->mutation('createAccount', ['id' => 123], ['id']); 73 | 74 | $this->assertEquals('graphql', $testCase->uri); 75 | $this->assertEquals(['query' => "mutation { createAccount(id: 123){\nid\n} }"], $testCase->data); 76 | } 77 | 78 | public function testMutationWithEmptyArrays() 79 | { 80 | $testCase = new FakeTestCase(); 81 | 82 | $testCase->mutation('logout', [], []); 83 | 84 | $this->assertEquals(['query' => "mutation { logout }"], $testCase->data); 85 | } 86 | 87 | public function testMutationWithOneEmptyArrayArguments() 88 | { 89 | $testCase = new FakeTestCase(); 90 | 91 | $testCase->mutation('logout', [], ['success']); 92 | 93 | $this->assertEquals(['query' => "mutation { logout{\nsuccess\n} }"], $testCase->data); 94 | } 95 | } 96 | --------------------------------------------------------------------------------