diff --git a/tests/Server/Psr7/PsrRequestStub.php b/tests/Server/Psr7/PsrRequestStub.php index 6a912af..09513af 100644 --- a/tests/Server/Psr7/PsrRequestStub.php +++ b/tests/Server/Psr7/PsrRequestStub.php @@ -1,9 +1,13 @@ headers[$name]) ? $this->headers[$name] : []; + + return $this->headers[$name] ?? []; } /** @@ -137,7 +138,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function getHeaderLine($name) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -150,14 +151,14 @@ class PsrRequestStub implements ServerRequestInterface * immutability of the message, and MUST return an instance that has the * new and/or updated header and value. * - * @param string $name Case-insensitive header field name. + * @param string $name Case-insensitive header field name. * @param string|string[] $value Header value(s). * @return static * @throws \InvalidArgumentException for invalid header names or values. */ public function withHeader($name, $value) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -171,14 +172,14 @@ class PsrRequestStub implements ServerRequestInterface * immutability of the message, and MUST return an instance that has the * new header and/or value. * - * @param string $name Case-insensitive header field name to add. + * @param string $name Case-insensitive header field name to add. * @param string|string[] $value Header value(s). * @return static * @throws \InvalidArgumentException for invalid header names or values. */ public function withAddedHeader($name, $value) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -195,7 +196,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function withoutHeader($name) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -223,7 +224,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function withBody(StreamInterface $body) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -244,7 +245,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function getRequestTarget() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -266,7 +267,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function withRequestTarget($requestTarget) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -296,7 +297,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function withMethod($method) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -339,13 +340,13 @@ class PsrRequestStub implements ServerRequestInterface * new UriInterface instance. * * @link http://tools.ietf.org/html/rfc3986#section-4.3 - * @param UriInterface $uri New request URI to use. - * @param bool $preserveHost Preserve the original state of the Host header. + * @param UriInterface $uri New request URI to use. + * @param bool $preserveHost Preserve the original state of the Host header. * @return static */ public function withUri(UriInterface $uri, $preserveHost = false) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -359,7 +360,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function getServerParams() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -374,7 +375,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function getCookieParams() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -396,7 +397,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function withCookieParams(array $cookies) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -440,7 +441,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function withQueryParams(array $query) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -457,7 +458,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function getUploadedFiles() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -473,7 +474,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function withUploadedFiles(array $uploadedFiles) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -526,7 +527,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function withParsedBody($data) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -542,7 +543,7 @@ class PsrRequestStub implements ServerRequestInterface */ public function getAttributes() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -556,13 +557,13 @@ class PsrRequestStub implements ServerRequestInterface * specifying a default value to return if the attribute is not found. * * @see getAttributes() - * @param string $name The attribute name. - * @param mixed $default Default value to return if the attribute does not exist. + * @param string $name The attribute name. + * @param mixed $default Default value to return if the attribute does not exist. * @return mixed */ public function getAttribute($name, $default = null) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -576,13 +577,13 @@ class PsrRequestStub implements ServerRequestInterface * updated attribute. * * @see getAttributes() - * @param string $name The attribute name. - * @param mixed $value The value of the attribute. + * @param string $name The attribute name. + * @param mixed $value The value of the attribute. * @return static */ public function withAttribute($name, $value) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -601,6 +602,6 @@ class PsrRequestStub implements ServerRequestInterface */ public function withoutAttribute($name) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } } diff --git a/tests/Server/Psr7/PsrResponseStub.php b/tests/Server/Psr7/PsrResponseStub.php index 01201f2..ae3f858 100644 --- a/tests/Server/Psr7/PsrResponseStub.php +++ b/tests/Server/Psr7/PsrResponseStub.php @@ -1,6 +1,8 @@ headers[$name][] = $value; + return $tmp; } @@ -162,14 +165,14 @@ class PsrResponseStub implements ResponseInterface * immutability of the message, and MUST return an instance that has the * new header and/or value. * - * @param string $name Case-insensitive header field name to add. + * @param string $name Case-insensitive header field name to add. * @param string|string[] $value Header value(s). * @return static * @throws \InvalidArgumentException for invalid header names or values. */ public function withAddedHeader($name, $value) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -186,7 +189,7 @@ class PsrResponseStub implements ResponseInterface */ public function withoutHeader($name) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -196,7 +199,7 @@ class PsrResponseStub implements ResponseInterface */ public function getBody() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -214,8 +217,9 @@ class PsrResponseStub implements ResponseInterface */ public function withBody(StreamInterface $body) { - $tmp = clone $this; + $tmp = clone $this; $tmp->body = $body; + return $tmp; } @@ -229,7 +233,7 @@ class PsrResponseStub implements ResponseInterface */ public function getStatusCode() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -245,7 +249,7 @@ class PsrResponseStub implements ResponseInterface * * @link http://tools.ietf.org/html/rfc7231#section-6 * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml - * @param int $code The 3-digit integer result code to set. + * @param int $code The 3-digit integer result code to set. * @param string $reasonPhrase The reason phrase to use with the * provided status code; if none is provided, implementations MAY * use the defaults as suggested in the HTTP specification. @@ -254,8 +258,9 @@ class PsrResponseStub implements ResponseInterface */ public function withStatus($code, $reasonPhrase = '') { - $tmp = clone $this; + $tmp = clone $this; $tmp->statusCode = $code; + return $tmp; } @@ -274,6 +279,6 @@ class PsrResponseStub implements ResponseInterface */ public function getReasonPhrase() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } -} \ No newline at end of file +} diff --git a/tests/Server/Psr7/PsrStreamStub.php b/tests/Server/Psr7/PsrStreamStub.php index 50adecf..d05cf36 100644 --- a/tests/Server/Psr7/PsrStreamStub.php +++ b/tests/Server/Psr7/PsrStreamStub.php @@ -1,7 +1,12 @@ content?:''); + return strlen($this->content ?: ''); } /** @@ -66,7 +71,7 @@ class PsrStreamStub implements StreamInterface */ public function tell() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -76,7 +81,7 @@ class PsrStreamStub implements StreamInterface */ public function eof() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -86,7 +91,7 @@ class PsrStreamStub implements StreamInterface */ public function isSeekable() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -103,7 +108,7 @@ class PsrStreamStub implements StreamInterface */ public function seek($offset, $whence = SEEK_SET) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -118,7 +123,7 @@ class PsrStreamStub implements StreamInterface */ public function rewind() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -141,6 +146,7 @@ class PsrStreamStub implements StreamInterface public function write($string) { $this->content = $string; + return strlen($string); } @@ -151,7 +157,7 @@ class PsrStreamStub implements StreamInterface */ public function isReadable() { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -166,7 +172,7 @@ class PsrStreamStub implements StreamInterface */ public function read($length) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } /** @@ -195,6 +201,6 @@ class PsrStreamStub implements StreamInterface */ public function getMetadata($key = null) { - throw new \Exception("Not implemented"); + throw new \Exception('Not implemented'); } } diff --git a/tests/Server/PsrResponseTest.php b/tests/Server/PsrResponseTest.php index b3ff6ec..3f01538 100644 --- a/tests/Server/PsrResponseTest.php +++ b/tests/Server/PsrResponseTest.php @@ -1,18 +1,22 @@ 'value']); - $stream = new PsrStreamStub(); + $result = new ExecutionResult(['key' => 'value']); + $stream = new PsrStreamStub(); $psrResponse = new PsrResponseStub(); $helper = new Helper(); diff --git a/tests/Server/QueryExecutionTest.php b/tests/Server/QueryExecutionTest.php index 0b7d473..b6fc44e 100644 --- a/tests/Server/QueryExecutionTest.php +++ b/tests/Server/QueryExecutionTest.php @@ -1,11 +1,12 @@ buildSchema(); + $schema = $this->buildSchema(); $this->config = ServerConfig::create() ->setSchema($schema); } @@ -36,14 +37,30 @@ class QueryExecutionTest extends ServerTestCase $query = '{f1}'; $expected = [ - 'data' => [ - 'f1' => 'f1' - ] + 'data' => ['f1' => 'f1'], ]; $this->assertQueryResultEquals($expected, $query); } + private function assertQueryResultEquals($expected, $query, $variables = null) + { + $result = $this->executeQuery($query, $variables); + $this->assertArraySubset($expected, $result->toArray(true)); + + return $result; + } + + private function executeQuery($query, $variables = null, $readonly = false) + { + $op = OperationParams::create(['query' => $query, 'variables' => $variables], $readonly); + $helper = new Helper(); + $result = $helper->executeOperation($this->config, $op); + $this->assertInstanceOf(ExecutionResult::class, $result); + + return $result; + } + public function testReturnsSyntaxErrors() : void { $query = '{f1'; @@ -70,17 +87,17 @@ class QueryExecutionTest extends ServerTestCase '; $expected = [ - 'data' => [ + 'data' => [ 'fieldWithException' => null, - 'f1' => 'f1' + 'f1' => 'f1', ], 'errors' => [ [ 'message' => 'This is the exception we want', - 'path' => ['fieldWithException'], - 'trace' => [] - ] - ] + 'path' => ['fieldWithException'], + 'trace' => [], + ], + ], ]; $result = $this->executeQuery($query)->toArray(); @@ -90,7 +107,7 @@ class QueryExecutionTest extends ServerTestCase public function testPassesRootValueAndContext() : void { $rootValue = 'myRootValue'; - $context = new \stdClass(); + $context = new \stdClass(); $this->config ->setContext($context) @@ -102,7 +119,7 @@ class QueryExecutionTest extends ServerTestCase } '; - $this->assertTrue(!isset($context->testedRootValue)); + $this->assertTrue(! isset($context->testedRootValue)); $this->executeQuery($query); $this->assertSame($rootValue, $context->testedRootValue); } @@ -110,30 +127,30 @@ class QueryExecutionTest extends ServerTestCase public function testPassesVariables() : void { $variables = ['a' => 'a', 'b' => 'b']; - $query = ' + $query = ' query ($a: String!, $b: String!) { a: fieldWithArg(arg: $a) b: fieldWithArg(arg: $b) } '; - $expected = [ + $expected = [ 'data' => [ 'a' => 'a', - 'b' => 'b' - ] + 'b' => 'b', + ], ]; $this->assertQueryResultEquals($expected, $query, $variables); } public function testPassesCustomValidationRules() : void { - $query = ' + $query = ' {nonExistentField} '; $expected = [ 'errors' => [ - ['message' => 'Cannot query field "nonExistentField" on type "Query".'] - ] + ['message' => 'Cannot query field "nonExistentField" on type "Query".'], + ], ]; $this->assertQueryResultEquals($expected, $query); @@ -141,15 +158,16 @@ class QueryExecutionTest extends ServerTestCase $called = false; $rules = [ - new CustomValidationRule('SomeRule', function() use (&$called) { + new CustomValidationRule('SomeRule', function () use (&$called) { $called = true; + return []; - }) + }), ]; $this->config->setValidationRules($rules); $expected = [ - 'data' => [] + 'data' => [], ]; $this->assertQueryResultEquals($expected, $query); $this->assertTrue($called); @@ -160,11 +178,12 @@ class QueryExecutionTest extends ServerTestCase $called = false; $params = $doc = $operationType = null; - $this->config->setValidationRules(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) { - $called = true; - $params = $p; - $doc = $d; + $this->config->setValidationRules(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) { + $called = true; + $params = $p; + $doc = $d; $operationType = $o; + return []; }); @@ -178,23 +197,25 @@ class QueryExecutionTest extends ServerTestCase public function testAllowsDifferentValidationRulesDependingOnOperation() : void { - $q1 = '{f1}'; - $q2 = '{invalid}'; + $q1 = '{f1}'; + $q2 = '{invalid}'; $called1 = false; $called2 = false; - $this->config->setValidationRules(function(OperationParams $params) use ($q1, $q2, &$called1, &$called2) { + $this->config->setValidationRules(function (OperationParams $params) use ($q1, $q2, &$called1, &$called2) { if ($params->query === $q1) { $called1 = true; + return DocumentValidator::allRules(); - } else { - $called2 = true; - return [ - new CustomValidationRule('MyRule', function(ValidationContext $context) { - $context->reportError(new Error("This is the error we are looking for!")); - }) - ]; } + + $called2 = true; + + return [ + new CustomValidationRule('MyRule', function (ValidationContext $context) { + $context->reportError(new Error('This is the error we are looking for!')); + }), + ]; }); $expected = ['data' => ['f1' => 'f1']]; @@ -202,8 +223,8 @@ class QueryExecutionTest extends ServerTestCase $this->assertTrue($called1); $this->assertFalse($called2); - $called1 = false; - $called2 = false; + $called1 = false; + $called2 = false; $expected = ['errors' => [['message' => 'This is the error we are looking for!']]]; $this->assertQueryResultEquals($expected, $q2); $this->assertFalse($called1); @@ -213,7 +234,7 @@ class QueryExecutionTest extends ServerTestCase public function testAllowsSkippingValidation() : void { $this->config->setValidationRules([]); - $query = '{nonExistentField}'; + $query = '{nonExistentField}'; $expected = ['data' => []]; $this->assertQueryResultEquals($expected, $query); } @@ -225,23 +246,29 @@ class QueryExecutionTest extends ServerTestCase $expected = [ 'errors' => [ [ - 'message' => 'Persisted queries are not supported by this server', - 'category' => 'request' - ] - ] + 'message' => 'Persisted queries are not supported by this server', + 'category' => 'request', + ], + ], ]; $this->assertEquals($expected, $result->toArray()); } + private function executePersistedQuery($queryId, $variables = null) + { + $op = OperationParams::create(['queryId' => $queryId, 'variables' => $variables]); + $helper = new Helper(); + $result = $helper->executeOperation($this->config, $op); + $this->assertInstanceOf(ExecutionResult::class, $result); + + return $result; + } + public function testBatchedQueriesAreDisabledByDefault() : void { $batch = [ - [ - 'query' => '{invalid}' - ], - [ - 'query' => '{f1,fieldWithException}' - ] + ['query' => '{invalid}'], + ['query' => '{f1,fieldWithException}'], ]; $result = $this->executeBatchedQuery($batch); @@ -250,18 +277,18 @@ class QueryExecutionTest extends ServerTestCase [ 'errors' => [ [ - 'message' => 'Batched queries are not supported by this server', - 'category' => 'request' - ] - ] + 'message' => 'Batched queries are not supported by this server', + 'category' => 'request', + ], + ], ], [ 'errors' => [ [ - 'message' => 'Batched queries are not supported by this server', - 'category' => 'request' - ] - ] + 'message' => 'Batched queries are not supported by this server', + 'category' => 'request', + ], + ], ], ]; @@ -269,6 +296,31 @@ class QueryExecutionTest extends ServerTestCase $this->assertEquals($expected[1], $result[1]->toArray()); } + /** + * @param mixed[][] $qs + */ + private function executeBatchedQuery(array $qs) + { + $batch = []; + foreach ($qs as $params) { + $batch[] = OperationParams::create($params); + } + $helper = new Helper(); + $result = $helper->executeBatch($this->config, $batch); + $this->assertInternalType('array', $result); + $this->assertCount(count($qs), $result); + + foreach ($result as $index => $entry) { + $this->assertInstanceOf( + ExecutionResult::class, + $entry, + sprintf('Result at %s is not an instance of %s', $index, ExecutionResult::class) + ); + } + + return $result; + } + public function testMutationsAreNotAllowedInReadonlyMode() : void { $mutation = 'mutation { a }'; @@ -276,10 +328,10 @@ class QueryExecutionTest extends ServerTestCase $expected = [ 'errors' => [ [ - 'message' => 'GET supports only query operation', - 'category' => 'request' - ] - ] + 'message' => 'GET supports only query operation', + 'category' => 'request', + ], + ], ]; $result = $this->executeQuery($mutation, null, true); @@ -289,9 +341,10 @@ class QueryExecutionTest extends ServerTestCase public function testAllowsPersistentQueries() : void { $called = false; - $this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) { + $this->config->setPersistentQueryLoader(function ($queryId, OperationParams $params) use (&$called) { $called = true; $this->assertEquals('some-id', $queryId); + return '{f1}'; }); @@ -299,17 +352,16 @@ class QueryExecutionTest extends ServerTestCase $this->assertTrue($called); $expected = [ - 'data' => [ - 'f1' => 'f1' - ] + 'data' => ['f1' => 'f1'], ]; $this->assertEquals($expected, $result->toArray()); // Make sure it allows returning document node: $called = false; - $this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) { + $this->config->setPersistentQueryLoader(function ($queryId, OperationParams $params) use (&$called) { $called = true; $this->assertEquals('some-id', $queryId); + return Parser::parse('{f1}'); }); $result = $this->executePersistedQuery('some-id'); @@ -324,7 +376,7 @@ class QueryExecutionTest extends ServerTestCase 'Persistent query loader must return query string or instance of GraphQL\Language\AST\DocumentNode ' . 'but got: {"err":"err"}' ); - $this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) { + $this->config->setPersistentQueryLoader(function ($queryId, OperationParams $params) use (&$called) { return ['err' => 'err']; }); $this->executePersistedQuery('some-id'); @@ -332,56 +384,55 @@ class QueryExecutionTest extends ServerTestCase public function testPersistedQueriesAreStillValidatedByDefault() : void { - $this->config->setPersistentQueryLoader(function() { + $this->config->setPersistentQueryLoader(function () { return '{invalid}'; }); - $result = $this->executePersistedQuery('some-id'); + $result = $this->executePersistedQuery('some-id'); $expected = [ 'errors' => [ [ - 'message' => 'Cannot query field "invalid" on type "Query".', - 'locations' => [ ['line' => 1, 'column' => 2] ], - 'category' => 'graphql' - ] - ] + 'message' => 'Cannot query field "invalid" on type "Query".', + 'locations' => [['line' => 1, 'column' => 2]], + 'category' => 'graphql', + ], + ], ]; $this->assertEquals($expected, $result->toArray()); - } public function testAllowSkippingValidationForPersistedQueries() : void { $this->config - ->setPersistentQueryLoader(function($queryId) { + ->setPersistentQueryLoader(function ($queryId) { if ($queryId === 'some-id') { return '{invalid}'; - } else { - return '{invalid2}'; } + + return '{invalid2}'; }) - ->setValidationRules(function(OperationParams $params) { + ->setValidationRules(function (OperationParams $params) { if ($params->queryId === 'some-id') { return []; - } else { - return DocumentValidator::allRules(); } + + return DocumentValidator::allRules(); }); - $result = $this->executePersistedQuery('some-id'); + $result = $this->executePersistedQuery('some-id'); $expected = [ - 'data' => [] + 'data' => [], ]; $this->assertEquals($expected, $result->toArray()); - $result = $this->executePersistedQuery('some-other-id'); + $result = $this->executePersistedQuery('some-other-id'); $expected = [ 'errors' => [ [ - 'message' => 'Cannot query field "invalid2" on type "Query".', - 'locations' => [ ['line' => 1, 'column' => 2] ], - 'category' => 'graphql' - ] - ] + 'message' => 'Cannot query field "invalid2" on type "Query".', + 'locations' => [['line' => 1, 'column' => 2]], + 'category' => 'graphql', + ], + ], ]; $this->assertEquals($expected, $result->toArray()); } @@ -390,7 +441,7 @@ class QueryExecutionTest extends ServerTestCase { $this->expectException(InvariantViolation::class); $this->expectExceptionMessage('Expecting validation rules to be array or callable returning array, but got: instance of stdClass'); - $this->config->setValidationRules(function(OperationParams $params) { + $this->config->setValidationRules(function (OperationParams $params) { return new \stdClass(); }); $this->executeQuery('{f1}'); @@ -401,44 +452,40 @@ class QueryExecutionTest extends ServerTestCase $this->config->setQueryBatching(true); $batch = [ + ['query' => '{invalid}'], + ['query' => '{f1,fieldWithException}'], [ - 'query' => '{invalid}' - ], - [ - 'query' => '{f1,fieldWithException}' - ], - [ - 'query' => ' + 'query' => ' query ($a: String!, $b: String!) { a: fieldWithArg(arg: $a) b: fieldWithArg(arg: $b) } ', 'variables' => ['a' => 'a', 'b' => 'b'], - ] + ], ]; $result = $this->executeBatchedQuery($batch); $expected = [ [ - 'errors' => [['message' => 'Cannot query field "invalid" on type "Query".']] + 'errors' => [['message' => 'Cannot query field "invalid" on type "Query".']], ], [ - 'data' => [ - 'f1' => 'f1', - 'fieldWithException' => null + 'data' => [ + 'f1' => 'f1', + 'fieldWithException' => null, ], 'errors' => [ - ['message' => 'This is the exception we want'] - ] + ['message' => 'This is the exception we want'], + ], ], [ 'data' => [ 'a' => 'a', - 'b' => 'b' - ] - ] + 'b' => 'b', + ], + ], ]; $this->assertArraySubset($expected[0], $result[0]->toArray()); @@ -449,15 +496,9 @@ class QueryExecutionTest extends ServerTestCase public function testDeferredsAreSharedAmongAllBatchedQueries() : void { $batch = [ - [ - 'query' => '{dfd(num: 1)}' - ], - [ - 'query' => '{dfd(num: 2)}' - ], - [ - 'query' => '{dfd(num: 3)}', - ] + ['query' => '{dfd(num: 1)}'], + ['query' => '{dfd(num: 2)}'], + ['query' => '{dfd(num: 3)}'], ]; $calls = []; @@ -466,13 +507,14 @@ class QueryExecutionTest extends ServerTestCase ->setQueryBatching(true) ->setRootValue('1') ->setContext([ - 'buffer' => function($num) use (&$calls) { - $calls[] = "buffer: $num"; + 'buffer' => function ($num) use (&$calls) { + $calls[] = sprintf('buffer: %d', $num); + }, + 'load' => function ($num) use (&$calls) { + $calls[] = sprintf('load: %d', $num); + + return sprintf('loaded: %d', $num); }, - 'load' => function($num) use (&$calls) { - $calls[] = "load: $num"; - return "loaded: $num"; - } ]); $result = $this->executeBatchedQuery($batch); @@ -489,19 +531,13 @@ class QueryExecutionTest extends ServerTestCase $expected = [ [ - 'data' => [ - 'dfd' => 'loaded: 1' - ] + 'data' => ['dfd' => 'loaded: 1'], ], [ - 'data' => [ - 'dfd' => 'loaded: 2' - ] + 'data' => ['dfd' => 'loaded: 2'], ], [ - 'data' => [ - 'dfd' => 'loaded: 3' - ] + 'data' => ['dfd' => 'loaded: 3'], ], ]; @@ -512,7 +548,7 @@ class QueryExecutionTest extends ServerTestCase public function testValidatesParamsBeforeExecution() : void { - $op = OperationParams::create(['queryBad' => '{f1}']); + $op = OperationParams::create(['queryBad' => '{f1}']); $helper = new Helper(); $result = $helper->executeOperation($this->config, $op); $this->assertInstanceOf(ExecutionResult::class, $result); @@ -536,10 +572,10 @@ class QueryExecutionTest extends ServerTestCase $called = false; $params = $doc = $operationType = null; - $this->config->setContext(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) { - $called = true; - $params = $p; - $doc = $d; + $this->config->setContext(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) { + $called = true; + $params = $p; + $doc = $d; $operationType = $o; }); @@ -556,10 +592,10 @@ class QueryExecutionTest extends ServerTestCase $called = false; $params = $doc = $operationType = null; - $this->config->setRootValue(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) { - $called = true; - $params = $p; - $doc = $d; + $this->config->setRootValue(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) { + $called = true; + $params = $p; + $doc = $d; $operationType = $o; }); @@ -574,20 +610,21 @@ class QueryExecutionTest extends ServerTestCase public function testAppliesErrorFormatter() : void { $called = false; - $error = null; - $this->config->setErrorFormatter(function($e) use (&$called, &$error) { + $error = null; + $this->config->setErrorFormatter(function ($e) use (&$called, &$error) { $called = true; - $error = $e; + $error = $e; + return ['test' => 'formatted']; }); $result = $this->executeQuery('{fieldWithException}'); $this->assertFalse($called); $formatted = $result->toArray(); - $expected = [ + $expected = [ 'errors' => [ - ['test' => 'formatted'] - ] + ['test' => 'formatted'], + ], ]; $this->assertTrue($called); $this->assertArraySubset($expected, $formatted); @@ -595,28 +632,29 @@ class QueryExecutionTest extends ServerTestCase // Assert debugging still works even with custom formatter $formatted = $result->toArray(Debug::INCLUDE_TRACE); - $expected = [ + $expected = [ 'errors' => [ [ - 'test' => 'formatted', - 'trace' => [] - ] - ] + 'test' => 'formatted', + 'trace' => [], + ], + ], ]; $this->assertArraySubset($expected, $formatted); } public function testAppliesErrorsHandler() : void { - $called = false; - $errors = null; + $called = false; + $errors = null; $formatter = null; - $this->config->setErrorsHandler(function($e, $f) use (&$called, &$errors, &$formatter) { - $called = true; - $errors = $e; + $this->config->setErrorsHandler(function ($e, $f) use (&$called, &$errors, &$formatter) { + $called = true; + $errors = $e; $formatter = $f; + return [ - ['test' => 'handled'] + ['test' => 'handled'], ]; }); @@ -624,10 +662,10 @@ class QueryExecutionTest extends ServerTestCase $this->assertFalse($called); $formatted = $result->toArray(); - $expected = [ + $expected = [ 'errors' => [ - ['test' => 'handled'] - ] + ['test' => 'handled'], + ], ]; $this->assertTrue($called); $this->assertArraySubset($expected, $formatted); @@ -636,46 +674,4 @@ class QueryExecutionTest extends ServerTestCase $this->assertInternalType('callable', $formatter); $this->assertArraySubset($expected, $formatted); } - - private function executePersistedQuery($queryId, $variables = null) - { - $op = OperationParams::create(['queryId' => $queryId, 'variables' => $variables]); - $helper = new Helper(); - $result = $helper->executeOperation($this->config, $op); - $this->assertInstanceOf(ExecutionResult::class, $result); - return $result; - } - - private function executeQuery($query, $variables = null, $readonly = false) - { - $op = OperationParams::create(['query' => $query, 'variables' => $variables], $readonly); - $helper = new Helper(); - $result = $helper->executeOperation($this->config, $op); - $this->assertInstanceOf(ExecutionResult::class, $result); - return $result; - } - - private function executeBatchedQuery(array $qs) - { - $batch = []; - foreach ($qs as $params) { - $batch[] = OperationParams::create($params); - } - $helper = new Helper(); - $result = $helper->executeBatch($this->config, $batch); - $this->assertInternalType('array', $result); - $this->assertCount(count($qs), $result); - - foreach ($result as $index => $entry) { - $this->assertInstanceOf(ExecutionResult::class, $entry, "Result at $index is not an instance of " . ExecutionResult::class); - } - return $result; - } - - private function assertQueryResultEquals($expected, $query, $variables = null) - { - $result = $this->executeQuery($query, $variables); - $this->assertArraySubset($expected, $result->toArray(true)); - return $result; - } } diff --git a/tests/Server/RequestParsingTest.php b/tests/Server/RequestParsingTest.php index 47d715c..ba3a215 100644 --- a/tests/Server/RequestParsingTest.php +++ b/tests/Server/RequestParsingTest.php @@ -1,7 +1,9 @@ $this->parseRawRequest('application/graphql', $query), - 'psr' => $this->parsePsrRequest('application/graphql', $query) + 'psr' => $this->parsePsrRequest('application/graphql', $query), ]; foreach ($parsed as $source => $parsedBody) { @@ -26,20 +30,91 @@ class RequestParsingTest extends TestCase } } + /** + * @param string $contentType + * @param string $content + * + * @return OperationParams|OperationParams[] + */ + private function parseRawRequest($contentType, $content, string $method = 'POST') + { + $_SERVER['CONTENT_TYPE'] = $contentType; + $_SERVER['REQUEST_METHOD'] = $method; + + $helper = new Helper(); + + return $helper->parseHttpRequest(function () use ($content) { + return $content; + }); + } + + /** + * @param string $contentType + * @param string $content + * + * @return OperationParams|OperationParams[] + */ + private function parsePsrRequest($contentType, $content, string $method = 'POST') + { + $psrRequestBody = new PsrStreamStub(); + $psrRequestBody->content = $content; + + $psrRequest = new PsrRequestStub(); + $psrRequest->headers['content-type'] = [$contentType]; + $psrRequest->method = $method; + $psrRequest->body = $psrRequestBody; + + if ($contentType === 'application/json') { + $parsedBody = json_decode($content, true); + $parsedBody = $parsedBody === false ? null : $parsedBody; + } else { + $parsedBody = null; + } + + $psrRequest->parsedBody = $parsedBody; + + $helper = new Helper(); + + return $helper->parsePsrRequest($psrRequest); + } + + /** + * @param OperationParams $params + * @param string $query + * @param string $queryId + * @param mixed|null $variables + * @param string $operation + */ + private function assertValidOperationParams( + $params, + $query, + $queryId = null, + $variables = null, + $operation = null, + $message = '' + ) { + $this->assertInstanceOf(OperationParams::class, $params, $message); + + $this->assertSame($query, $params->query, $message); + $this->assertSame($queryId, $params->queryId, $message); + $this->assertSame($variables, $params->variables, $message); + $this->assertSame($operation, $params->operation, $message); + } + public function testParsesUrlencodedRequest() : void { - $query = '{my query}'; + $query = '{my query}'; $variables = ['test' => 1, 'test2' => 2]; $operation = 'op'; - $post = [ - 'query' => $query, - 'variables' => $variables, - 'operationName' => $operation + $post = [ + 'query' => $query, + 'variables' => $variables, + 'operationName' => $operation, ]; $parsed = [ 'raw' => $this->parseRawFormUrlencodedRequest($post), - 'psr' => $this->parsePsrFormUrlEncodedRequest($post) + 'psr' => $this->parsePsrFormUrlEncodedRequest($post), ]; foreach ($parsed as $method => $parsedBody) { @@ -48,20 +123,53 @@ class RequestParsingTest extends TestCase } } + /** + * @param mixed[] $postValue + * @return OperationParams|OperationParams[] + */ + private function parseRawFormUrlencodedRequest($postValue) + { + $_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST = $postValue; + + $helper = new Helper(); + + return $helper->parseHttpRequest(function () { + throw new InvariantViolation("Shouldn't read from php://input for urlencoded request"); + }); + } + + /** + * @param mixed[] $postValue + * @return OperationParams[]|OperationParams + */ + private function parsePsrFormUrlEncodedRequest($postValue) + { + $psrRequest = new PsrRequestStub(); + $psrRequest->headers['content-type'] = ['application/x-www-form-urlencoded']; + $psrRequest->method = 'POST'; + $psrRequest->parsedBody = $postValue; + + $helper = new Helper(); + + return $helper->parsePsrRequest($psrRequest); + } + public function testParsesGetRequest() : void { - $query = '{my query}'; + $query = '{my query}'; $variables = ['test' => 1, 'test2' => 2]; $operation = 'op'; - $get = [ - 'query' => $query, - 'variables' => $variables, - 'operationName' => $operation + $get = [ + 'query' => $query, + 'variables' => $variables, + 'operationName' => $operation, ]; $parsed = [ 'raw' => $this->parseRawGetRequest($get), - 'psr' => $this->parsePsrGetRequest($get) + 'psr' => $this->parsePsrGetRequest($get), ]; foreach ($parsed as $method => $parsedBody) { @@ -70,20 +178,51 @@ class RequestParsingTest extends TestCase } } + /** + * @param mixed[] $getValue + * @return OperationParams + */ + private function parseRawGetRequest($getValue) + { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_GET = $getValue; + + $helper = new Helper(); + + return $helper->parseHttpRequest(function () { + throw new InvariantViolation("Shouldn't read from php://input for urlencoded request"); + }); + } + + /** + * @param mixed[] $getValue + * @return OperationParams[]|OperationParams + */ + private function parsePsrGetRequest($getValue) + { + $psrRequest = new PsrRequestStub(); + $psrRequest->method = 'GET'; + $psrRequest->queryParams = $getValue; + + $helper = new Helper(); + + return $helper->parsePsrRequest($psrRequest); + } + public function testParsesMultipartFormdataRequest() : void { - $query = '{my query}'; + $query = '{my query}'; $variables = ['test' => 1, 'test2' => 2]; $operation = 'op'; - $post = [ - 'query' => $query, - 'variables' => $variables, - 'operationName' => $operation + $post = [ + 'query' => $query, + 'variables' => $variables, + 'operationName' => $operation, ]; $parsed = [ 'raw' => $this->parseRawMultipartFormdataRequest($post), - 'psr' => $this->parsePsrMultipartFormdataRequest($post) + 'psr' => $this->parsePsrMultipartFormdataRequest($post), ]; foreach ($parsed as $method => $parsedBody) { @@ -92,20 +231,53 @@ class RequestParsingTest extends TestCase } } + /** + * @param mixed[] $postValue + * @return OperationParams|OperationParams[] + */ + private function parseRawMultipartFormDataRequest($postValue) + { + $_SERVER['CONTENT_TYPE'] = 'multipart/form-data; boundary=----FormBoundary'; + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST = $postValue; + + $helper = new Helper(); + + return $helper->parseHttpRequest(function () { + throw new InvariantViolation("Shouldn't read from php://input for multipart/form-data request"); + }); + } + + /** + * @param mixed[] $postValue + * @return OperationParams|OperationParams[] + */ + private function parsePsrMultipartFormDataRequest($postValue) + { + $psrRequest = new PsrRequestStub(); + $psrRequest->headers['content-type'] = ['multipart/form-data; boundary=----FormBoundary']; + $psrRequest->method = 'POST'; + $psrRequest->parsedBody = $postValue; + + $helper = new Helper(); + + return $helper->parsePsrRequest($psrRequest); + } + public function testParsesJSONRequest() : void { - $query = '{my query}'; + $query = '{my query}'; $variables = ['test' => 1, 'test2' => 2]; $operation = 'op'; - $body = [ - 'query' => $query, - 'variables' => $variables, - 'operationName' => $operation + $body = [ + 'query' => $query, + 'variables' => $variables, + 'operationName' => $operation, ]; $parsed = [ 'raw' => $this->parseRawRequest('application/json', json_encode($body)), - 'psr' => $this->parsePsrRequest('application/json', json_encode($body)) + 'psr' => $this->parsePsrRequest('application/json', json_encode($body)), ]; foreach ($parsed as $method => $parsedBody) { $this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method); @@ -115,18 +287,18 @@ class RequestParsingTest extends TestCase public function testParsesVariablesAsJSON() : void { - $query = '{my query}'; + $query = '{my query}'; $variables = ['test' => 1, 'test2' => 2]; $operation = 'op'; - $body = [ - 'query' => $query, - 'variables' => json_encode($variables), - 'operationName' => $operation + $body = [ + 'query' => $query, + 'variables' => json_encode($variables), + 'operationName' => $operation, ]; $parsed = [ 'raw' => $this->parseRawRequest('application/json', json_encode($body)), - 'psr' => $this->parsePsrRequest('application/json', json_encode($body)) + 'psr' => $this->parsePsrRequest('application/json', json_encode($body)), ]; foreach ($parsed as $method => $parsedBody) { $this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method); @@ -136,14 +308,14 @@ class RequestParsingTest extends TestCase public function testIgnoresInvalidVariablesJson() : void { - $query = '{my query}'; + $query = '{my query}'; $variables = '"some invalid json'; $operation = 'op'; - $body = [ - 'query' => $query, - 'variables' => $variables, - 'operationName' => $operation + $body = [ + 'query' => $query, + 'variables' => $variables, + 'operationName' => $operation, ]; $parsed = [ 'raw' => $this->parseRawRequest('application/json', json_encode($body)), @@ -157,27 +329,41 @@ class RequestParsingTest extends TestCase public function testParsesBatchJSONRequest() : void { - $body = [ + $body = [ [ - 'query' => '{my query}', - 'variables' => ['test' => 1, 'test2' => 2], - 'operationName' => 'op' + 'query' => '{my query}', + 'variables' => ['test' => 1, 'test2' => 2], + 'operationName' => 'op', ], [ - 'queryId' => 'my-query-id', - 'variables' => ['test' => 1, 'test2' => 2], - 'operationName' => 'op2' + 'queryId' => 'my-query-id', + 'variables' => ['test' => 1, 'test2' => 2], + 'operationName' => 'op2', ], ]; $parsed = [ 'raw' => $this->parseRawRequest('application/json', json_encode($body)), - 'psr' => $this->parsePsrRequest('application/json', json_encode($body)) + 'psr' => $this->parsePsrRequest('application/json', json_encode($body)), ]; foreach ($parsed as $method => $parsedBody) { $this->assertInternalType('array', $parsedBody, $method); $this->assertCount(2, $parsedBody, $method); - $this->assertValidOperationParams($parsedBody[0], $body[0]['query'], null, $body[0]['variables'], $body[0]['operationName'], $method); - $this->assertValidOperationParams($parsedBody[1], null, $body[1]['queryId'], $body[1]['variables'], $body[1]['operationName'], $method); + $this->assertValidOperationParams( + $parsedBody[0], + $body[0]['query'], + null, + $body[0]['variables'], + $body[0]['operationName'], + $method + ); + $this->assertValidOperationParams( + $parsedBody[1], + null, + $body[1]['queryId'], + $body[1]['variables'], + $body[1]['operationName'], + $method + ); } } @@ -187,8 +373,8 @@ class RequestParsingTest extends TestCase $this->expectException(RequestError::class); $this->expectExceptionMessage('Could not parse JSON: Syntax error'); - $this->parseRawRequest('application/json', $body); - } + $this->parseRawRequest('application/json', $body); + } public function testFailsParsingInvalidRawJsonRequestPsr() : void { @@ -196,7 +382,7 @@ class RequestParsingTest extends TestCase $this->expectException(InvariantViolation::class); $this->expectExceptionMessage('PSR-7 request is expected to provide parsed body for "application/json" requests but got null'); - $this->parsePsrRequest('application/json', $body); + $this->parsePsrRequest('application/json', $body); } public function testFailsParsingNonPreParsedPsrRequest() : void @@ -222,8 +408,8 @@ class RequestParsingTest extends TestCase $this->expectException(RequestError::class); $this->expectExceptionMessage('GraphQL Server expects JSON object or array, but got "str"'); - $this->parseRawRequest('application/json', $body); - } + $this->parseRawRequest('application/json', $body); + } public function testFailsParsingNonArrayOrObjectJsonRequestPsr() : void { @@ -231,13 +417,13 @@ class RequestParsingTest extends TestCase $this->expectException(RequestError::class); $this->expectExceptionMessage('GraphQL Server expects JSON object or array, but got "str"'); - $this->parsePsrRequest('application/json', $body); - } + $this->parsePsrRequest('application/json', $body); + } public function testFailsParsingInvalidContentTypeRaw() : void { $contentType = 'not-supported-content-type'; - $body = 'test'; + $body = 'test'; $this->expectException(RequestError::class); $this->expectExceptionMessage('Unexpected content type: "not-supported-content-type"'); @@ -247,194 +433,38 @@ class RequestParsingTest extends TestCase public function testFailsParsingInvalidContentTypePsr() : void { $contentType = 'not-supported-content-type'; - $body = 'test'; + $body = 'test'; $this->expectException(RequestError::class); $this->expectExceptionMessage('Unexpected content type: "not-supported-content-type"'); - $this->parseRawRequest($contentType, $body); - } + $this->parseRawRequest($contentType, $body); + } public function testFailsWithMissingContentTypeRaw() : void { $this->expectException(RequestError::class); $this->expectExceptionMessage('Missing "Content-Type" header'); - $this->parseRawRequest(null, 'test'); - } + $this->parseRawRequest(null, 'test'); + } public function testFailsWithMissingContentTypePsr() : void { $this->expectException(RequestError::class); $this->expectExceptionMessage('Missing "Content-Type" header'); - $this->parsePsrRequest(null, 'test'); + $this->parsePsrRequest(null, 'test'); } public function testFailsOnMethodsOtherThanPostOrGetRaw() : void { $this->expectException(RequestError::class); $this->expectExceptionMessage('HTTP Method "PUT" is not supported'); - $this->parseRawRequest('application/json', json_encode([]), "PUT"); + $this->parseRawRequest('application/json', json_encode([]), 'PUT'); } public function testFailsOnMethodsOtherThanPostOrGetPsr() : void { $this->expectException(RequestError::class); $this->expectExceptionMessage('HTTP Method "PUT" is not supported'); - $this->parsePsrRequest('application/json', json_encode([]), "PUT"); - } - - /** - * @param string $contentType - * @param string $content - * @param $method - * - * @return OperationParams|OperationParams[] - */ - private function parseRawRequest($contentType, $content, $method = 'POST') - { - $_SERVER['CONTENT_TYPE'] = $contentType; - $_SERVER['REQUEST_METHOD'] = $method; - - $helper = new Helper(); - return $helper->parseHttpRequest(function() use ($content) { - return $content; - }); - } - - /** - * @param string $contentType - * @param string $content - * @param $method - * - * @return OperationParams|OperationParams[] - */ - private function parsePsrRequest($contentType, $content, $method = 'POST') - { - $psrRequestBody = new PsrStreamStub(); - $psrRequestBody->content = $content; - - $psrRequest = new PsrRequestStub(); - $psrRequest->headers['content-type'] = [$contentType]; - $psrRequest->method = $method; - $psrRequest->body = $psrRequestBody; - - if ($contentType === 'application/json') { - $parsedBody = json_decode($content, true); - $parsedBody = $parsedBody === false ? null : $parsedBody; - } else { - $parsedBody = null; - } - - $psrRequest->parsedBody = $parsedBody; - - $helper = new Helper(); - return $helper->parsePsrRequest($psrRequest); - } - - /** - * @param array $postValue - * @return OperationParams|OperationParams[] - */ - private function parseRawFormUrlencodedRequest($postValue) - { - $_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; - $_SERVER['REQUEST_METHOD'] = 'POST'; - $_POST = $postValue; - - $helper = new Helper(); - return $helper->parseHttpRequest(function() { - throw new InvariantViolation("Shouldn't read from php://input for urlencoded request"); - }); - } - - /** - * @param $postValue - * @return array|Helper - */ - private function parsePsrFormUrlEncodedRequest($postValue) - { - $psrRequest = new PsrRequestStub(); - $psrRequest->headers['content-type'] = ['application/x-www-form-urlencoded']; - $psrRequest->method = 'POST'; - $psrRequest->parsedBody = $postValue; - - $helper = new Helper(); - return $helper->parsePsrRequest($psrRequest); - } - - /** - * @param array $postValue - * @return OperationParams|OperationParams[] - */ - private function parseRawMultipartFormDataRequest($postValue) - { - $_SERVER['CONTENT_TYPE'] = 'multipart/form-data; boundary=----FormBoundary'; - $_SERVER['REQUEST_METHOD'] = 'POST'; - $_POST = $postValue; - - $helper = new Helper(); - return $helper->parseHttpRequest(function() { - throw new InvariantViolation("Shouldn't read from php://input for multipart/form-data request"); - }); - } - - /** - * @param $postValue - * @return array|Helper - */ - private function parsePsrMultipartFormDataRequest($postValue) - { - $psrRequest = new PsrRequestStub(); - $psrRequest->headers['content-type'] = ['multipart/form-data; boundary=----FormBoundary']; - $psrRequest->method = 'POST'; - $psrRequest->parsedBody = $postValue; - - $helper = new Helper(); - return $helper->parsePsrRequest($psrRequest); - } - - /** - * @param $getValue - * @return OperationParams - */ - private function parseRawGetRequest($getValue) - { - $_SERVER['REQUEST_METHOD'] = 'GET'; - $_GET = $getValue; - - $helper = new Helper(); - return $helper->parseHttpRequest(function() { - throw new InvariantViolation("Shouldn't read from php://input for urlencoded request"); - }); - } - - /** - * @param $getValue - * @return array|Helper - */ - private function parsePsrGetRequest($getValue) - { - $psrRequest = new PsrRequestStub(); - $psrRequest->method = 'GET'; - $psrRequest->queryParams = $getValue; - - $helper = new Helper(); - return $helper->parsePsrRequest($psrRequest); - } - - /** - * @param OperationParams $params - * @param string $query - * @param string $queryId - * @param array $variables - * @param string $operation - */ - private function assertValidOperationParams($params, $query, $queryId = null, $variables = null, $operation = null, $message = '') - { - $this->assertInstanceOf(OperationParams::class, $params, $message); - - $this->assertSame($query, $params->query, $message); - $this->assertSame($queryId, $params->queryId, $message); - $this->assertSame($variables, $params->variables, $message); - $this->assertSame($operation, $params->operation, $message); + $this->parsePsrRequest('application/json', json_encode([]), 'PUT'); } } diff --git a/tests/Server/RequestValidationTest.php b/tests/Server/RequestValidationTest.php index e205bfd..07b99fe 100644 --- a/tests/Server/RequestValidationTest.php +++ b/tests/Server/RequestValidationTest.php @@ -1,4 +1,7 @@ 'b', 'c' => 'd']; $operation = 'op'; $parsedBody = OperationParams::create([ - 'query' => $query, - 'variables' => $variables, + 'query' => $query, + 'variables' => $variables, 'operationName' => $operation, ]); $this->assertValid($parsedBody); } + private function assertValid($parsedRequest) + { + $helper = new Helper(); + $errors = $helper->validateOperationParams($parsedRequest); + $this->assertEmpty($errors, isset($errors[0]) ? $errors[0]->getMessage() : ''); + } + public function testRequestWithQueryIdShouldValidate() : void { - $queryId = 'some-query-id'; + $queryId = 'some-query-id'; $variables = ['a' => 'b', 'c' => 'd']; $operation = 'op'; $parsedBody = OperationParams::create([ - 'queryId' => $queryId, - 'variables' => $variables, + 'queryId' => $queryId, + 'variables' => $variables, 'operationName' => $operation, ]); @@ -40,7 +50,7 @@ class RequestValidationTest extends TestCase public function testRequiresQueryOrQueryId() : void { $parsedBody = OperationParams::create([ - 'variables' => ['foo' => 'bar'], + 'variables' => ['foo' => 'bar'], 'operationName' => 'op', ]); @@ -50,10 +60,21 @@ class RequestValidationTest extends TestCase ); } + private function assertInputError($parsedRequest, $expectedMessage) + { + $helper = new Helper(); + $errors = $helper->validateOperationParams($parsedRequest); + if (! empty($errors[0])) { + $this->assertEquals($expectedMessage, $errors[0]->getMessage()); + } else { + $this->fail('Expected error not returned'); + } + } + public function testFailsWhenBothQueryAndQueryIdArePresent() : void { $parsedBody = OperationParams::create([ - 'query' => '{my query}', + 'query' => '{my query}', 'queryId' => 'my-query-id', ]); @@ -66,7 +87,7 @@ class RequestValidationTest extends TestCase public function testFailsWhenQueryParameterIsNotString() : void { $parsedBody = OperationParams::create([ - 'query' => ['t' => '{my query}'] + 'query' => ['t' => '{my query}'], ]); $this->assertInputError( @@ -78,7 +99,7 @@ class RequestValidationTest extends TestCase public function testFailsWhenQueryIdParameterIsNotString() : void { $parsedBody = OperationParams::create([ - 'queryId' => ['t' => '{my query}'] + 'queryId' => ['t' => '{my query}'], ]); $this->assertInputError( @@ -90,8 +111,8 @@ class RequestValidationTest extends TestCase public function testFailsWhenOperationParameterIsNotString() : void { $parsedBody = OperationParams::create([ - 'query' => '{my query}', - 'operationName' => [] + 'query' => '{my query}', + 'operationName' => [], ]); $this->assertInputError( @@ -105,17 +126,17 @@ class RequestValidationTest extends TestCase */ public function testIgnoresNullAndEmptyStringVariables() : void { - $query = '{my q}'; + $query = '{my q}'; $parsedBody = OperationParams::create([ - 'query' => $query, - 'variables' => null + 'query' => $query, + 'variables' => null, ]); $this->assertValid($parsedBody); - $variables = ""; + $variables = ''; $parsedBody = OperationParams::create([ - 'query' => $query, - 'variables' => $variables + 'query' => $query, + 'variables' => $variables, ]); $this->assertValid($parsedBody); } @@ -123,8 +144,8 @@ class RequestValidationTest extends TestCase public function testFailsWhenVariablesParameterIsNotObject() : void { $parsedBody = OperationParams::create([ - 'query' => '{my query}', - 'variables' => 0 + 'query' => '{my query}', + 'variables' => 0, ]); $this->assertInputError( @@ -132,22 +153,4 @@ class RequestValidationTest extends TestCase 'GraphQL Request parameter "variables" must be object or JSON string parsed to object, but got 0' ); } - - private function assertValid($parsedRequest) - { - $helper = new Helper(); - $errors = $helper->validateOperationParams($parsedRequest); - $this->assertEmpty($errors, isset($errors[0]) ? $errors[0]->getMessage() : ''); - } - - private function assertInputError($parsedRequest, $expectedMessage) - { - $helper = new Helper(); - $errors = $helper->validateOperationParams($parsedRequest); - if (!empty($errors[0])) { - $this->assertEquals($expectedMessage, $errors[0]->getMessage()); - } else { - $this->fail('Expected error not returned'); - } - } } diff --git a/tests/Server/ServerConfigTest.php b/tests/Server/ServerConfigTest.php index d8af920..1fc2be8 100644 --- a/tests/Server/ServerConfigTest.php +++ b/tests/Server/ServerConfigTest.php @@ -1,12 +1,15 @@ setErrorFormatter($formatter); $this->assertSame($formatter, $config->getErrorFormatter()); @@ -83,7 +87,8 @@ class ServerConfigTest extends TestCase { $config = ServerConfig::create(); - $handler = function() {}; + $handler = function () { + }; $config->setErrorsHandler($handler); $this->assertSame($handler, $config->getErrorsHandler()); @@ -113,11 +118,17 @@ class ServerConfigTest extends TestCase $config->setValidationRules($rules); $this->assertSame($rules, $config->getValidationRules()); - $rules = [function() {}]; + $rules = [function () { + }, + ]; $config->setValidationRules($rules); $this->assertSame($rules, $config->getValidationRules()); - $rules = function() {return [function() {}];}; + $rules = function () { + return [function () { + }, + ]; + }; $config->setValidationRules($rules); $this->assertSame($rules, $config->getValidationRules()); } @@ -126,7 +137,8 @@ class ServerConfigTest extends TestCase { $config = ServerConfig::create(); - $resolver = function() {}; + $resolver = function () { + }; $config->setFieldResolver($resolver); $this->assertSame($resolver, $config->getFieldResolver()); @@ -139,7 +151,8 @@ class ServerConfigTest extends TestCase { $config = ServerConfig::create(); - $loader = function() {}; + $loader = function () { + }; $config->setPersistentQueryLoader($loader); $this->assertSame($loader, $config->getPersistentQueryLoader()); @@ -162,18 +175,23 @@ class ServerConfigTest extends TestCase public function testAcceptsArray() : void { $arr = [ - 'schema' => new \GraphQL\Type\Schema([ - 'query' => new ObjectType(['name' => 't', 'fields' => ['a' => Type::string()]]) + 'schema' => new Schema([ + 'query' => new ObjectType(['name' => 't', 'fields' => ['a' => Type::string()]]), ]), - 'context' => new \stdClass(), - 'rootValue' => new \stdClass(), - 'errorFormatter' => function() {}, - 'promiseAdapter' => new SyncPromiseAdapter(), - 'validationRules' => [function() {}], - 'fieldResolver' => function() {}, - 'persistentQueryLoader' => function() {}, - 'debug' => true, - 'queryBatching' => true, + 'context' => new \stdClass(), + 'rootValue' => new \stdClass(), + 'errorFormatter' => function () { + }, + 'promiseAdapter' => new SyncPromiseAdapter(), + 'validationRules' => [function () { + }, + ], + 'fieldResolver' => function () { + }, + 'persistentQueryLoader' => function () { + }, + 'debug' => true, + 'queryBatching' => true, ]; $config = ServerConfig::create($arr); @@ -192,9 +210,7 @@ class ServerConfigTest extends TestCase public function testThrowsOnInvalidArrayKey() : void { - $arr = [ - 'missingKey' => 'value' - ]; + $arr = ['missingKey' => 'value']; $this->expectException(InvariantViolation::class); $this->expectExceptionMessage('Unknown server config option "missingKey"'); @@ -204,7 +220,7 @@ class ServerConfigTest extends TestCase public function testInvalidValidationRules() : void { - $rules = new \stdClass(); + $rules = new \stdClass(); $config = ServerConfig::create(); $this->expectException(InvariantViolation::class); diff --git a/tests/Server/ServerTestCase.php b/tests/Server/ServerTestCase.php index e76d8f4..1e67d87 100644 --- a/tests/Server/ServerTestCase.php +++ b/tests/Server/ServerTestCase.php @@ -1,6 +1,8 @@ new ObjectType([ - 'name' => 'Query', + 'query' => new ObjectType([ + 'name' => 'Query', 'fields' => [ - 'f1' => [ - 'type' => Type::string(), - 'resolve' => function($root, $args, $context, $info) { + 'f1' => [ + 'type' => Type::string(), + 'resolve' => function ($root, $args, $context, $info) { return $info->fieldName; - } + }, ], - 'fieldWithPhpError' => [ - 'type' => Type::string(), - 'resolve' => function($root, $args, $context, $info) { + 'fieldWithPhpError' => [ + 'type' => Type::string(), + 'resolve' => function ($root, $args, $context, $info) { trigger_error('deprecated', E_USER_DEPRECATED); trigger_error('notice', E_USER_NOTICE); trigger_error('warning', E_USER_WARNING); $a = []; $a['test']; // should produce PHP notice + return $info->fieldName; - } + }, ], - 'fieldWithException' => [ - 'type' => Type::string(), - 'resolve' => function($root, $args, $context, $info) { - throw new UserError("This is the exception we want"); - } + 'fieldWithException' => [ + 'type' => Type::string(), + 'resolve' => function ($root, $args, $context, $info) { + throw new UserError('This is the exception we want'); + }, ], 'testContextAndRootValue' => [ - 'type' => Type::string(), - 'resolve' => function($root, $args, $context, $info) { + 'type' => Type::string(), + 'resolve' => function ($root, $args, $context, $info) { $context->testedRootValue = $root; + return $info->fieldName; - } + }, ], - 'fieldWithArg' => [ - 'type' => Type::string(), - 'args' => [ + 'fieldWithArg' => [ + 'type' => Type::string(), + 'args' => [ 'arg' => [ - 'type' => Type::nonNull(Type::string()) + 'type' => Type::nonNull(Type::string()), ], ], - 'resolve' => function($root, $args) { + 'resolve' => function ($root, $args) { return $args['arg']; - } + }, ], - 'dfd' => [ - 'type' => Type::string(), - 'args' => [ + 'dfd' => [ + 'type' => Type::string(), + 'args' => [ 'num' => [ - 'type' => Type::nonNull(Type::int()) + 'type' => Type::nonNull(Type::int()), ], ], - 'resolve' => function($root, $args, $context) { + 'resolve' => function ($root, $args, $context) { $context['buffer']($args['num']); - return new Deferred(function() use ($args, $context) { + return new Deferred(function () use ($args, $context) { return $context['load']($args['num']); }); - } - ] - ] + }, + ], + ], ]), 'mutation' => new ObjectType([ - 'name' => 'Mutation', + 'name' => 'Mutation', 'fields' => [ 'm1' => [ 'type' => new ObjectType([ - 'name' => 'TestMutation', + 'name' => 'TestMutation', 'fields' => [ - 'result' => Type::string() - ] - ]) - ] - ] - ]) + 'result' => Type::string(), + ], + ]), + ], + ], + ]), ]); + return $schema; } } diff --git a/tests/Server/StandardServerTest.php b/tests/Server/StandardServerTest.php index 5c22788..3f5bfe4 100644 --- a/tests/Server/StandardServerTest.php +++ b/tests/Server/StandardServerTest.php @@ -1,4 +1,7 @@ buildSchema(); + $schema = $this->buildSchema(); $this->config = ServerConfig::create() ->setSchema($schema); } public function testSimpleRequestExecutionWithOutsideParsing() : void { - $body = json_encode([ - 'query' => '{f1}' - ]); + $body = json_encode(['query' => '{f1}']); $parsedBody = $this->parseRawRequest('application/json', $body); - $server = new StandardServer($this->config); + $server = new StandardServer($this->config); - $result = $server->executeRequest($parsedBody); + $result = $server->executeRequest($parsedBody); $expected = [ - 'data' => [ - 'f1' => 'f1', - ] + 'data' => ['f1' => 'f1'], ]; $this->assertEquals($expected, $result->toArray(true)); } + private function parseRawRequest($contentType, $content, $method = 'POST') + { + $_SERVER['CONTENT_TYPE'] = $contentType; + $_SERVER['REQUEST_METHOD'] = $method; + + $helper = new Helper(); + + return $helper->parseHttpRequest(function () use ($content) { + return $content; + }); + } + public function testSimplePsrRequestExecution() : void { - $body = [ - 'query' => '{f1}' - ]; + $body = ['query' => '{f1}']; $expected = [ - 'data' => [ - 'f1' => 'f1' - ] + 'data' => ['f1' => 'f1'], ]; $request = $this->preparePsrRequest('application/json', $body); $this->assertPsrRequestEquals($expected, $request); } - public function testMultipleOperationPsrRequestExecution() : void + private function preparePsrRequest($contentType, $parsedBody) { - $body = [ - 'query' => 'query firstOp {fieldWithPhpError} query secondOp {f1}', - 'operationName' => 'secondOp' - ]; + $psrRequest = new PsrRequestStub(); + $psrRequest->headers['content-type'] = [$contentType]; + $psrRequest->method = 'POST'; + $psrRequest->parsedBody = $parsedBody; - $expected = [ - 'data' => [ - 'f1' => 'f1' - ] - ]; + return $psrRequest; + } - $request = $this->preparePsrRequest('application/json', $body); - $this->assertPsrRequestEquals($expected, $request); + private function assertPsrRequestEquals($expected, $request) + { + $result = $this->executePsrRequest($request); + $this->assertArraySubset($expected, $result->toArray(true)); + + return $result; } private function executePsrRequest($psrRequest) @@ -79,33 +85,22 @@ class StandardServerTest extends ServerTestCase $server = new StandardServer($this->config); $result = $server->executePsrRequest($psrRequest); $this->assertInstanceOf(ExecutionResult::class, $result); + return $result; } - private function assertPsrRequestEquals($expected, $request) + public function testMultipleOperationPsrRequestExecution() : void { - $result = $this->executePsrRequest($request); - $this->assertArraySubset($expected, $result->toArray(true)); - return $result; - } + $body = [ + 'query' => 'query firstOp {fieldWithPhpError} query secondOp {f1}', + 'operationName' => 'secondOp', + ]; - private function preparePsrRequest($contentType, $parsedBody) - { - $psrRequest = new PsrRequestStub(); - $psrRequest->headers['content-type'] = [$contentType]; - $psrRequest->method = 'POST'; - $psrRequest->parsedBody = $parsedBody; - return $psrRequest; - } + $expected = [ + 'data' => ['f1' => 'f1'], + ]; - private function parseRawRequest($contentType, $content, $method = 'POST') - { - $_SERVER['CONTENT_TYPE'] = $contentType; - $_SERVER['REQUEST_METHOD'] = $method; - - $helper = new Helper(); - return $helper->parseHttpRequest(function() use ($content) { - return $content; - }); + $request = $this->preparePsrRequest('application/json', $body); + $this->assertPsrRequestEquals($expected, $request); } }