Skip to content

Commit 6961eac

Browse files
authored
tests(assertions): Implement leaked metadata detection for QueryResultAssertionTrait (#1207)
This adds detection of leaked cacheability metadata to assertResults and assertErrors in the QueryResultAssertionTrait. The context is serialized in the error message because this is always possible and while serialized content isn't the most readable it provides the most robust method of easily showing what metadata was leaked. Fixes #1206
1 parent 054b77d commit 6961eac

File tree

1 file changed

+47
-10
lines changed

1 file changed

+47
-10
lines changed

tests/src/Traits/QueryResultAssertionTrait.php

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace Drupal\Tests\graphql\Traits;
44

55
use Drupal\Core\Cache\CacheableMetadata;
6+
use Drupal\Core\Render\RenderContext;
7+
use Drupal\Core\Render\RendererInterface;
68
use Drupal\graphql\GraphQL\Execution\ExecutionResult;
79
use GraphQL\Server\OperationParams;
810

@@ -16,6 +18,11 @@ trait QueryResultAssertionTrait {
1618
*/
1719
protected $server;
1820

21+
/**
22+
* @var \Drupal\Core\Render\RendererInterface
23+
*/
24+
protected $renderer;
25+
1926
/**
2027
* Return the default cache max age for this test case.
2128
*
@@ -81,16 +88,23 @@ protected function defaultMutationCacheMetaData() {
8188
* The expected cache metadata object.
8289
*/
8390
protected function assertResults($query, array $variables, array $expected, CacheableMetadata $metadata = NULL): void {
84-
$result = $this->server->executeOperation(
85-
OperationParams::create([
86-
'query' => $query,
87-
'variables' => $variables,
88-
])
91+
$context = new RenderContext();
92+
$result = $this->getRenderer()->executeInRenderContext(
93+
$context,
94+
function () use ($query, $variables) {
95+
return $this->server->executeOperation(
96+
OperationParams::create([
97+
'query' => $query,
98+
'variables' => $variables,
99+
])
100+
);
101+
}
89102
);
90103

91104
$this->assertResultErrors($result, []);
92105
$this->assertResultData($result, $expected);
93106
$this->assertResultMetadata($result, $metadata ?: $this->defaultCacheMetaData());
107+
self::assertTrue($context->isEmpty(), "Metadata was leaked during operation execution: {$context->serialize()}");
94108
}
95109

96110
/**
@@ -106,15 +120,22 @@ protected function assertResults($query, array $variables, array $expected, Cach
106120
* The expected cache metadata object.
107121
*/
108122
protected function assertErrors($query, array $variables, $expected, CacheableMetadata $metadata): void {
109-
$result = $this->server->executeOperation(
110-
OperationParams::create([
111-
'query' => $query,
112-
'variables' => $variables,
113-
])
123+
$context = new RenderContext();
124+
$result = $this->getRenderer()->executeInRenderContext(
125+
$context,
126+
function () use ($query, $variables) {
127+
return $this->server->executeOperation(
128+
OperationParams::create([
129+
'query' => $query,
130+
'variables' => $variables,
131+
])
132+
);
133+
}
114134
);
115135

116136
$this->assertResultErrors($result, $expected);
117137
$this->assertResultMetadata($result, $metadata);
138+
self::assertTrue($context->isEmpty(), "Metadata was leaked during operation execution: {$context->serialize()}");
118139
}
119140

120141
/**
@@ -210,4 +231,20 @@ private function assertResultMetadata(ExecutionResult $result, CacheableMetadata
210231
$this->assertEmpty($unexpectedTags, 'Unexpected cache tags: ' . implode(', ', $unexpectedTags));
211232
}
212233

234+
/**
235+
* Get the Drupal renderer.
236+
*
237+
* Uses either the renderer available in the test class or fetches the Drupal
238+
* renderer service.
239+
*
240+
* @return \Drupal\Core\Render\RendererInterface
241+
* The renderer service for the test.
242+
*/
243+
private function getRenderer() : RendererInterface {
244+
if (!isset($this->renderer)) {
245+
$this->renderer = \Drupal::service('renderer');
246+
}
247+
return $this->renderer;
248+
}
249+
213250
}

0 commit comments

Comments
 (0)