comparison core/modules/jsonapi/tests/src/Functional/TermTest.php @ 5:12f9dff5fda9 tip

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:34:47 +0100
parents
children
comparison
equal deleted inserted replaced
4:a9cd425dd02b 5:12f9dff5fda9
1 <?php
2
3 namespace Drupal\Tests\jsonapi\Functional;
4
5 use Drupal\Component\Serialization\Json;
6 use Drupal\Component\Utility\NestedArray;
7 use Drupal\Core\Cache\Cache;
8 use Drupal\Core\Entity\EntityInterface;
9 use Drupal\Core\Url;
10 use Drupal\taxonomy\Entity\Term;
11 use Drupal\taxonomy\Entity\Vocabulary;
12 use Drupal\Tests\jsonapi\Traits\CommonCollectionFilterAccessTestPatternsTrait;
13 use GuzzleHttp\RequestOptions;
14
15 /**
16 * JSON:API integration test for the "Term" content entity type.
17 *
18 * @group jsonapi
19 */
20 class TermTest extends ResourceTestBase {
21
22 use CommonCollectionFilterAccessTestPatternsTrait;
23
24 /**
25 * {@inheritdoc}
26 */
27 public static $modules = ['taxonomy', 'path'];
28
29 /**
30 * {@inheritdoc}
31 */
32 protected static $entityTypeId = 'taxonomy_term';
33
34 /**
35 * {@inheritdoc}
36 */
37 protected static $resourceTypeName = 'taxonomy_term--camelids';
38
39 /**
40 * {@inheritdoc}
41 */
42 protected static $patchProtectedFieldNames = [
43 'changed' => NULL,
44 ];
45
46 /**
47 * {@inheritdoc}
48 *
49 * @var \Drupal\taxonomy\TermInterface
50 */
51 protected $entity;
52
53 /**
54 * {@inheritdoc}
55 */
56 protected function setUpAuthorization($method) {
57 switch ($method) {
58 case 'GET':
59 $this->grantPermissionsToTestedRole(['access content']);
60 break;
61
62 case 'POST':
63 $this->grantPermissionsToTestedRole(['create terms in camelids']);
64 break;
65
66 case 'PATCH':
67 // Grant the 'create url aliases' permission to test the case when
68 // the path field is accessible, see
69 // \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase
70 // for a negative test.
71 $this->grantPermissionsToTestedRole(['edit terms in camelids', 'create url aliases']);
72 break;
73
74 case 'DELETE':
75 $this->grantPermissionsToTestedRole(['delete terms in camelids']);
76 break;
77 }
78 }
79
80 /**
81 * {@inheritdoc}
82 */
83 protected function createEntity() {
84 $vocabulary = Vocabulary::load('camelids');
85 if (!$vocabulary) {
86 // Create a "Camelids" vocabulary.
87 $vocabulary = Vocabulary::create([
88 'name' => 'Camelids',
89 'vid' => 'camelids',
90 ]);
91 $vocabulary->save();
92 }
93
94 // Create a "Llama" taxonomy term.
95 $term = Term::create(['vid' => $vocabulary->id()])
96 ->setName('Llama')
97 ->setDescription("It is a little known fact that llamas cannot count higher than seven.")
98 ->setChangedTime(123456789)
99 ->set('path', '/llama');
100 $term->save();
101
102 return $term;
103 }
104
105 /**
106 * {@inheritdoc}
107 */
108 protected function getExpectedDocument() {
109 $self_url = Url::fromUri('base:/jsonapi/taxonomy_term/camelids/' . $this->entity->uuid())->setAbsolute()->toString(TRUE)->getGeneratedUrl();
110
111 // We test with multiple parent terms, and combinations thereof.
112 // @see ::createEntity()
113 // @see ::testGetIndividual()
114 // @see ::testGetIndividualTermWithParent()
115 // @see ::providerTestGetIndividualTermWithParent()
116 $parent_term_ids = [];
117 for ($i = 0; $i < $this->entity->get('parent')->count(); $i++) {
118 $parent_term_ids[$i] = (int) $this->entity->get('parent')[$i]->target_id;
119 }
120
121 $expected_parent_normalization = FALSE;
122 switch ($parent_term_ids) {
123 case [0]:
124 $expected_parent_normalization = [
125 'data' => [
126 [
127 'id' => 'virtual',
128 'type' => 'taxonomy_term--camelids',
129 'meta' => [
130 'links' => [
131 'help' => [
132 'href' => 'https://www.drupal.org/docs/8/modules/json-api/core-concepts#virtual',
133 'meta' => [
134 'about' => "Usage and meaning of the 'virtual' resource identifier.",
135 ],
136 ],
137 ],
138 ],
139 ],
140 ],
141 'links' => [
142 'related' => ['href' => $self_url . '/parent'],
143 'self' => ['href' => $self_url . '/relationships/parent'],
144 ],
145 ];
146 break;
147
148 case [2]:
149 $expected_parent_normalization = [
150 'data' => [
151 [
152 'id' => Term::load(2)->uuid(),
153 'type' => 'taxonomy_term--camelids',
154 ],
155 ],
156 'links' => [
157 'related' => ['href' => $self_url . '/parent'],
158 'self' => ['href' => $self_url . '/relationships/parent'],
159 ],
160 ];
161 break;
162
163 case [0, 2]:
164 $expected_parent_normalization = [
165 'data' => [
166 [
167 'id' => 'virtual',
168 'type' => 'taxonomy_term--camelids',
169 'meta' => [
170 'links' => [
171 'help' => [
172 'href' => 'https://www.drupal.org/docs/8/modules/json-api/core-concepts#virtual',
173 'meta' => [
174 'about' => "Usage and meaning of the 'virtual' resource identifier.",
175 ],
176 ],
177 ],
178 ],
179 ],
180 [
181 'id' => Term::load(2)->uuid(),
182 'type' => 'taxonomy_term--camelids',
183 ],
184 ],
185 'links' => [
186 'related' => ['href' => $self_url . '/parent'],
187 'self' => ['href' => $self_url . '/relationships/parent'],
188 ],
189 ];
190 break;
191
192 case [3, 2]:
193 $expected_parent_normalization = [
194 'data' => [
195 [
196 'id' => Term::load(3)->uuid(),
197 'type' => 'taxonomy_term--camelids',
198 ],
199 [
200 'id' => Term::load(2)->uuid(),
201 'type' => 'taxonomy_term--camelids',
202 ],
203 ],
204 'links' => [
205 'related' => ['href' => $self_url . '/parent'],
206 'self' => ['href' => $self_url . '/relationships/parent'],
207 ],
208 ];
209 break;
210 }
211
212 return [
213 'jsonapi' => [
214 'meta' => [
215 'links' => [
216 'self' => ['href' => 'http://jsonapi.org/format/1.0/'],
217 ],
218 ],
219 'version' => '1.0',
220 ],
221 'links' => [
222 'self' => ['href' => $self_url],
223 ],
224 'data' => [
225 'id' => $this->entity->uuid(),
226 'type' => 'taxonomy_term--camelids',
227 'links' => [
228 'self' => ['href' => $self_url],
229 ],
230 'attributes' => [
231 'changed' => (new \DateTime())->setTimestamp($this->entity->getChangedTime())->setTimezone(new \DateTimeZone('UTC'))->format(\DateTime::RFC3339),
232 'default_langcode' => TRUE,
233 'description' => [
234 'value' => 'It is a little known fact that llamas cannot count higher than seven.',
235 'format' => NULL,
236 'processed' => "<p>It is a little known fact that llamas cannot count higher than seven.</p>\n",
237 ],
238 'langcode' => 'en',
239 'name' => 'Llama',
240 'path' => [
241 'alias' => '/llama',
242 'pid' => 1,
243 'langcode' => 'en',
244 ],
245 'weight' => 0,
246 'drupal_internal__tid' => 1,
247 'status' => TRUE,
248 'drupal_internal__revision_id' => 1,
249 'revision_created' => (new \DateTime())->setTimestamp($this->entity->getRevisionCreationTime())->setTimezone(new \DateTimeZone('UTC'))->format(\DateTime::RFC3339),
250 'revision_log_message' => NULL,
251 // @todo Attempt to remove this in https://www.drupal.org/project/drupal/issues/2933518.
252 'revision_translation_affected' => TRUE,
253 ],
254 'relationships' => [
255 'parent' => $expected_parent_normalization,
256 'vid' => [
257 'data' => [
258 'id' => Vocabulary::load('camelids')->uuid(),
259 'type' => 'taxonomy_vocabulary--taxonomy_vocabulary',
260 ],
261 'links' => [
262 'related' => ['href' => $self_url . '/vid'],
263 'self' => ['href' => $self_url . '/relationships/vid'],
264 ],
265 ],
266 'revision_user' => [
267 'data' => NULL,
268 'links' => [
269 'related' => [
270 'href' => $self_url . '/revision_user',
271 ],
272 'self' => [
273 'href' => $self_url . '/relationships/revision_user',
274 ],
275 ],
276 ],
277 ],
278 ],
279 ];
280 }
281
282 /**
283 * {@inheritdoc}
284 */
285 protected function getExpectedGetRelationshipDocumentData($relationship_field_name, EntityInterface $entity = NULL) {
286 $data = parent::getExpectedGetRelationshipDocumentData($relationship_field_name, $entity);
287 if ($relationship_field_name === 'parent') {
288 $data = [
289 0 => [
290 'id' => 'virtual',
291 'type' => 'taxonomy_term--camelids',
292 'meta' => [
293 'links' => [
294 'help' => [
295 'href' => 'https://www.drupal.org/docs/8/modules/json-api/core-concepts#virtual',
296 'meta' => [
297 'about' => "Usage and meaning of the 'virtual' resource identifier.",
298 ],
299 ],
300 ],
301 ],
302 ],
303 ];
304 }
305 return $data;
306 }
307
308 /**
309 * {@inheritdoc}
310 */
311 protected function getPostDocument() {
312 return [
313 'data' => [
314 'type' => 'taxonomy_term--camelids',
315 'attributes' => [
316 'name' => 'Dramallama',
317 'description' => [
318 'value' => 'Dramallamas are the coolest camelids.',
319 'format' => NULL,
320 ],
321 ],
322 ],
323 ];
324 }
325
326 /**
327 * {@inheritdoc}
328 */
329 protected function getExpectedUnauthorizedAccessMessage($method) {
330 switch ($method) {
331 case 'GET':
332 return "The 'access content' permission is required and the taxonomy term must be published.";
333
334 case 'POST':
335 return "The following permissions are required: 'create terms in camelids' OR 'administer taxonomy'.";
336
337 case 'PATCH':
338 return "The following permissions are required: 'edit terms in camelids' OR 'administer taxonomy'.";
339
340 case 'DELETE':
341 return "The following permissions are required: 'delete terms in camelids' OR 'administer taxonomy'.";
342
343 default:
344 return parent::getExpectedUnauthorizedAccessMessage($method);
345 }
346 }
347
348 /**
349 * {@inheritdoc}
350 */
351 protected function getExpectedUnauthorizedAccessCacheability() {
352 $cacheability = parent::getExpectedUnauthorizedAccessCacheability();
353 $cacheability->addCacheableDependency($this->entity);
354 return $cacheability;
355 }
356
357 /**
358 * Tests PATCHing a term's path.
359 *
360 * For a negative test, see the similar test coverage for Node.
361 *
362 * @see \Drupal\Tests\jsonapi\Functional\NodeTest::testPatchPath()
363 * @see \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase::testPatchPath()
364 */
365 public function testPatchPath() {
366 $this->setUpAuthorization('GET');
367 $this->setUpAuthorization('PATCH');
368 $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE);
369
370 // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463.
371 $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $this->entity->uuid()]);
372 /* $url = $this->entity->toUrl('jsonapi'); */
373 $request_options = [];
374 $request_options[RequestOptions::HEADERS]['Accept'] = 'application/vnd.api+json';
375 $request_options[RequestOptions::HEADERS]['Content-Type'] = 'application/vnd.api+json';
376 $request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions());
377
378 // GET term's current normalization.
379 $response = $this->request('GET', $url, $request_options);
380 $normalization = Json::decode((string) $response->getBody());
381
382 // Change term's path alias.
383 $normalization['data']['attributes']['path']['alias'] .= 's-rule-the-world';
384
385 // Create term PATCH request.
386 $request_options[RequestOptions::BODY] = Json::encode($normalization);
387
388 // PATCH request: 200.
389 $response = $this->request('PATCH', $url, $request_options);
390 $this->assertResourceResponse(200, FALSE, $response);
391 $updated_normalization = Json::decode((string) $response->getBody());
392 $this->assertSame($normalization['data']['attributes']['path']['alias'], $updated_normalization['data']['attributes']['path']['alias']);
393 }
394
395 /**
396 * {@inheritdoc}
397 */
398 protected function getExpectedCacheTags(array $sparse_fieldset = NULL) {
399 $tags = parent::getExpectedCacheTags($sparse_fieldset);
400 if ($sparse_fieldset === NULL || in_array('description', $sparse_fieldset)) {
401 $tags = Cache::mergeTags($tags, ['config:filter.format.plain_text', 'config:filter.settings']);
402 }
403 return $tags;
404 }
405
406 /**
407 * {@inheritdoc}
408 */
409 protected function getExpectedCacheContexts(array $sparse_fieldset = NULL) {
410 $contexts = parent::getExpectedCacheContexts($sparse_fieldset);
411 if ($sparse_fieldset === NULL || in_array('description', $sparse_fieldset)) {
412 $contexts = Cache::mergeContexts($contexts, ['languages:language_interface', 'theme']);
413 }
414 return $contexts;
415 }
416
417 /**
418 * Tests GETting a term with a parent term other than the default <root> (0).
419 *
420 * @see ::getExpectedNormalizedEntity()
421 *
422 * @dataProvider providerTestGetIndividualTermWithParent
423 */
424 public function testGetIndividualTermWithParent(array $parent_term_ids) {
425 // Create all possible parent terms.
426 Term::create(['vid' => Vocabulary::load('camelids')->id()])
427 ->setName('Lamoids')
428 ->save();
429 Term::create(['vid' => Vocabulary::load('camelids')->id()])
430 ->setName('Wimoids')
431 ->save();
432
433 // Modify the entity under test to use the provided parent terms.
434 $this->entity->set('parent', $parent_term_ids)->save();
435
436 // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463.
437 $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $this->entity->uuid()]);
438 /* $url = $this->entity->toUrl('jsonapi'); */
439 $request_options = [];
440 $request_options[RequestOptions::HEADERS]['Accept'] = 'application/vnd.api+json';
441 $request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions());
442 $this->setUpAuthorization('GET');
443 $response = $this->request('GET', $url, $request_options);
444 $this->assertSameDocument($this->getExpectedDocument(), Json::decode($response->getBody()));
445 }
446
447 /**
448 * Data provider for ::testGetIndividualTermWithParent().
449 */
450 public function providerTestGetIndividualTermWithParent() {
451 return [
452 'root parent: [0] (= no parent)' => [
453 [0],
454 ],
455 'non-root parent: [2]' => [
456 [2],
457 ],
458 'multiple parents: [0,2] (root + non-root parent)' => [
459 [0, 2],
460 ],
461 'multiple parents: [3,2] (both non-root parents)' => [
462 [3, 2],
463 ],
464 ];
465 }
466
467 /**
468 * {@inheritdoc}
469 */
470 public function testRelated() {
471 $this->markTestSkipped('Remove this in https://www.drupal.org/project/jsonapi/issues/2940339');
472 }
473
474 /**
475 * {@inheritdoc}
476 */
477 public function testCollectionFilterAccess() {
478 $this->doTestCollectionFilterAccessBasedOnPermissions('name', 'access content');
479 }
480
481 }