Issue #3440993 by bbrala, bradjones1, larowlan, quietone: Improve JSON:API test failure messages to include errors when data is expected

merge-requests/7539/merge
quietone 2024-05-03 16:04:06 +12:00
parent 918b86294c
commit 74a6dce280
No known key found for this signature in database
GPG Key ID: 43BFBBB26EA09FE1
19 changed files with 209 additions and 140 deletions

View File

@ -377,8 +377,9 @@ class CommentTest extends ResourceTestBase {
// Status should be FALSE when posting as anonymous.
$response = $this->request('POST', $url, $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertResourceResponse(201, FALSE, $response);
$this->assertFalse(Json::decode((string) $response->getBody())['data']['attributes']['status']);
$this->assertFalse($document['data']['attributes']['status']);
$this->assertFalse($this->entityStorage->loadUnchanged(2)->isPublished());
// Grant anonymous permission to skip comment approval.
@ -386,8 +387,9 @@ class CommentTest extends ResourceTestBase {
// Status must be TRUE when posting as anonymous and skip comment approval.
$response = $this->request('POST', $url, $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertResourceResponse(201, FALSE, $response);
$this->assertTrue(Json::decode((string) $response->getBody())['data']['attributes']['status']);
$this->assertTrue($document['data']['attributes']['status']);
$this->assertTrue($this->entityStorage->loadUnchanged(3)->isPublished());
}
@ -441,14 +443,14 @@ class CommentTest extends ResourceTestBase {
// ::doTestCollectionFilterAccessForPublishableEntities().
$collection_filter_url = $collection_url->setOption('query', ["filter[spotlight.subject]" => $this->entity->label()]);
$response = $this->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(1, $doc['data']);
// Mark the commented entity as inaccessible.
\Drupal::state()->set('jsonapi__entity_test_filter_access_blacklist', [$this->entity->getCommentedEntityId()]);
Cache::invalidateTags(['state:jsonapi__entity_test_filter_access_blacklist']);
// ?filter[spotlight.LABEL]: 0 results.
$response = $this->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(0, $doc['data']);
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Drupal\Tests\jsonapi\Functional;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Url;
@ -134,7 +133,7 @@ class ConfigurableLanguageTest extends ConfigEntityResourceTestBase {
$this->setUpAuthorization('GET');
$response = $this->request('GET', $url, $request_options);
$normalization = Json::decode((string) $response->getBody());
$normalization = $this->getDocumentFromResponse($response);
$this->assertArrayNotHasKey('_core', $normalization['data']['attributes']);
}

View File

@ -4,9 +4,9 @@ declare(strict_types=1);
namespace Drupal\Tests\jsonapi\Functional;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\jsonapi\Traits\GetDocumentFromResponseTrait;
use Drupal\Tests\user\Traits\UserCreationTrait;
use GuzzleHttp\RequestOptions;
@ -19,6 +19,7 @@ use GuzzleHttp\RequestOptions;
*/
class EntryPointTest extends BrowserTestBase {
use GetDocumentFromResponseTrait;
use JsonApiRequestTestTrait;
use UserCreationTrait;
@ -43,7 +44,7 @@ class EntryPointTest extends BrowserTestBase {
$request_options = [];
$request_options[RequestOptions::HEADERS]['Accept'] = 'application/vnd.api+json';
$response = $this->request('GET', Url::fromUri('base://jsonapi'), $request_options);
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$expected_cache_contexts = [
'url.site',
'user.roles:authenticated',
@ -61,7 +62,7 @@ class EntryPointTest extends BrowserTestBase {
$user = $this->createUser();
$request_options[RequestOptions::HEADERS]['Authorization'] = 'Basic ' . base64_encode($user->name->value . ':' . $user->passRaw);
$response = $this->request('GET', Url::fromUri('base://jsonapi'), $request_options);
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$this->assertArrayHasKey('meta', $document);
$this->assertStringEndsWith('/jsonapi/user/user/' . $user->uuid(), $document['meta']['links']['me']['href']);
}

View File

@ -10,6 +10,7 @@ use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\jsonapi\Traits\GetDocumentFromResponseTrait;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
use GuzzleHttp\RequestOptions;
@ -23,6 +24,8 @@ use GuzzleHttp\RequestOptions;
*/
class ExternalNormalizersTest extends BrowserTestBase {
use GetDocumentFromResponseTrait;
/**
* {@inheritdoc}
*/
@ -152,7 +155,7 @@ class ExternalNormalizersTest extends BrowserTestBase {
// $url = $this->entity->toUrl('jsonapi');
$client = $this->getSession()->getDriver()->getClient()->getClient();
$response = $client->request('GET', $url->setAbsolute(TRUE)->toString());
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$this->assertSame($expected_value_jsonapi_normalization, $document['data']['attributes']['field_test']);
// Asserts the expected JSON:API denormalization.
@ -167,7 +170,7 @@ class ExternalNormalizersTest extends BrowserTestBase {
]);
$request_options[RequestOptions::HEADERS]['Content-Type'] = 'application/vnd.api+json';
$response = $client->request('POST', Url::fromRoute('jsonapi.entity_test--entity_test.collection.post')->setAbsolute(TRUE)->toString(), $request_options);
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$this->assertSame(static::VALUE_OVERRIDDEN, $document['data']['attributes']['field_test']);
$entity_type_manager = $this->container->get('entity_type.manager');
$uuid_key = $entity_type_manager->getDefinition('entity_test')->getKey('uuid');

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Drupal\Tests\jsonapi\Functional;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
@ -241,7 +240,7 @@ class FileTest extends ResourceTestBase {
$this->entity->setOwner($this->account);
$this->entity->save();
$response = $this->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(1, $doc['data']);
// 0 results because the current user is no longer the file owner and the
@ -249,7 +248,7 @@ class FileTest extends ResourceTestBase {
$this->entity->setOwner(User::load(0));
$this->entity->save();
$response = $this->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(0, $doc['data']);
}

View File

@ -905,7 +905,7 @@ class FileUploadTest extends ResourceTestBase {
*/
protected function assertResponseData(array $expected, ResponseInterface $response): void {
static::recursiveKSort($expected);
$actual = Json::decode((string) $response->getBody());
$actual = $this->getDocumentFromResponse($response);
static::recursiveKSort($actual);
$this->assertSame($expected, $actual);

View File

@ -7,7 +7,6 @@ namespace Drupal\Tests\jsonapi\Functional;
use Drupal\comment\Entity\Comment;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Url;
use Drupal\node\Entity\Node;
@ -109,8 +108,8 @@ class JsonApiFilterRegressionTest extends JsonApiFunctionalTestBase {
$user->pass_raw,
],
]);
$doc = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$doc = Json::decode((string) $response->getBody());
$this->assertNotEmpty($doc['data']);
$this->assertSame($doc['data'][0]['id'], $shortcut->uuid());
$this->assertSame($doc['data'][0]['attributes']['drupal_internal__id'], (int) $shortcut->id());
@ -157,20 +156,24 @@ class JsonApiFilterRegressionTest extends JsonApiFunctionalTestBase {
RequestOptions::AUTH => [$user->getAccountName(), $user->pass_raw],
];
$response = $this->request('GET', $url, $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode(), (string) $response->getBody());
$this->assertSame($node->uuid(), Json::decode((string) $response->getBody())['data'][0]['id']);
$this->assertSame($node->uuid(), $document['data'][0]['id']);
$response = $this->request('GET', $url->setOption('query', [
'filter[test][condition][path]' => 'field_parent_folder',
'filter[test][condition][operator]' => 'IS NULL',
]), $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode(), (string) $response->getBody());
$this->assertSame($node->uuid(), Json::decode((string) $response->getBody())['data'][0]['id']);
$this->assertSame($node->uuid(), $document['data'][0]['id']);
$response = $this->request('GET', $url->setOption('query', [
'filter[test][condition][path]' => 'field_parent_folder',
'filter[test][condition][operator]' => 'IS NOT NULL',
]), $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode(), (string) $response->getBody());
$this->assertEmpty(Json::decode((string) $response->getBody())['data']);
$this->assertEmpty($document['data']);
}
/**
@ -213,13 +216,13 @@ class JsonApiFilterRegressionTest extends JsonApiFunctionalTestBase {
// Ensure that an entity can be filtered by a target machine name.
$response = $this->request('GET', Url::fromUri('internal:/jsonapi/user/user?filter[roles.meta.drupal_internal__target_id]=llamalovers'), $request_options);
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode(), var_export($document, TRUE));
// Only one user should have the first role.
$this->assertCount(1, $document['data']);
$this->assertSame($users[0]->uuid(), $document['data'][0]['id']);
$response = $this->request('GET', Url::fromUri('internal:/jsonapi/user/user?sort=drupal_internal__uid&filter[roles.meta.drupal_internal__target_id]=catcuddlers'), $request_options);
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode(), var_export($document, TRUE));
// Two users should have the second role. A sort is used on this request to
// ensure a consistent ordering with different databases.
@ -229,7 +232,7 @@ class JsonApiFilterRegressionTest extends JsonApiFunctionalTestBase {
// Ensure that an entity can be filtered by an target entity integer ID.
$response = $this->request('GET', Url::fromUri('internal:/jsonapi/node/article?filter[uid.meta.drupal_internal__target_id]=' . $users[1]->id()), $request_options);
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode(), var_export($document, TRUE));
// Only the node authored by the filtered user should be returned.
$this->assertCount(1, $document['data']);

View File

@ -158,20 +158,20 @@ class JsonApiFunctionalMultilingualTest extends JsonApiFunctionalTestBase {
->save();
$response = $this->request('PATCH', Url::fromUri('base:/ca/jsonapi/node/article/' . $this->nodes[0]->uuid()), $request_options);
$this->assertSame(500, $response->getStatusCode());
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame('The translation language cannot be changed (ca).', $document['errors'][0]['detail']);
// Changing the langcode of the default ('en') translation is possible:
// first verify that it currently is 'en', then change it to 'ca-fr', and
// verify that the title is unchanged, but the langcode is updated.
$response = $this->request('GET', Url::fromUri('base:/jsonapi/node/article/' . $this->nodes[0]->uuid()), $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$document = Json::decode((string) $response->getBody());
$this->assertSame($node->getTitle(), $document['data']['attributes']['title']);
$this->assertSame('en', $document['data']['attributes']['langcode']);
$response = $this->request('PATCH', Url::fromUri('base:/jsonapi/node/article/' . $this->nodes[0]->uuid()), $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$document = Json::decode((string) $response->getBody());
$this->assertSame($node->getTitle(), $document['data']['attributes']['title']);
$this->assertSame('ca-fr', $document['data']['attributes']['langcode']);
@ -179,18 +179,18 @@ class JsonApiFunctionalMultilingualTest extends JsonApiFunctionalTestBase {
// - When GETting the 'en' translation, we get 'ca-fr', since the 'en'
// translation doesn't exist anymore.
$response = $this->request('GET', Url::fromUri('base:/jsonapi/node/article/' . $this->nodes[0]->uuid()), $request_options);
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$this->assertSame('ca-fr', $document['data']['attributes']['langcode']);
$this->assertSame($node->getTitle(), $document['data']['attributes']['title']);
// - When GETting the 'ca' translation, we still get the 'ca' one.
$response = $this->request('GET', Url::fromUri('base:/ca/jsonapi/node/article/' . $this->nodes[0]->uuid()), $request_options);
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$this->assertSame('ca', $document['data']['attributes']['langcode']);
$this->assertSame($node->getTitle() . ' (ca) UPDATED', $document['data']['attributes']['title']);
// - When GETting the 'ca-fr' translation, we now get the default
// translation.
$response = $this->request('GET', Url::fromUri('base:/ca-fr/jsonapi/node/article/' . $this->nodes[0]->uuid()), $request_options);
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$this->assertSame('ca-fr', $document['data']['attributes']['langcode']);
$this->assertSame($node->getTitle(), $document['data']['attributes']['title']);
}
@ -232,7 +232,7 @@ class JsonApiFunctionalMultilingualTest extends JsonApiFunctionalTestBase {
]);
$response = $this->request('PATCH', Url::fromUri('base:/ca-fr/jsonapi/node/article/' . $this->nodes[0]->uuid()), $request_options);
$this->assertSame(405, $response->getStatusCode());
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame('The requested translation of the resource object does not exist, instead modify one of the translations that do exist: ca, en.', $document['errors'][0]['detail']);
}
@ -263,7 +263,7 @@ class JsonApiFunctionalMultilingualTest extends JsonApiFunctionalTestBase {
$request_options[RequestOptions::BODY] = Json::encode($request_document);
$response = $this->request('POST', Url::fromUri('base:/ca/jsonapi/node/article/'), $request_options);
$this->assertSame(403, $response->getStatusCode());
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame('The current user is not allowed to POST the selected field (langcode).', $document['errors'][0]['detail']);
// Omitting a langcode results in an entity in 'en': the default language of
@ -271,8 +271,8 @@ class JsonApiFunctionalMultilingualTest extends JsonApiFunctionalTestBase {
unset($request_document['data']['attributes']['langcode']);
$request_options[RequestOptions::BODY] = Json::encode($request_document);
$response = $this->request('POST', Url::fromUri('base:/ca/jsonapi/node/article/'), $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(201, $response->getStatusCode());
$document = Json::decode((string) $response->getBody());
$this->assertSame($title, $document['data']['attributes']['title']);
$this->assertSame('en', $document['data']['attributes']['langcode']);
$this->assertSame(['en'], array_keys(Node::load($document['data']['attributes']['drupal_internal__nid'])->getTranslationLanguages()));
@ -285,16 +285,16 @@ class JsonApiFunctionalMultilingualTest extends JsonApiFunctionalTestBase {
$request_document['data']['attributes']['langcode'] = 'ca';
$request_options[RequestOptions::BODY] = Json::encode($request_document);
$response = $this->request('POST', Url::fromUri('base:/ca/jsonapi/node/article/'), $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(201, $response->getStatusCode());
$document = Json::decode((string) $response->getBody());
$this->assertSame($title, $document['data']['attributes']['title']);
$this->assertSame('ca', $document['data']['attributes']['langcode']);
$this->assertSame(['ca'], array_keys(Node::load($document['data']['attributes']['drupal_internal__nid'])->getTranslationLanguages()));
// Same request, but sent to the URL without the language prefix.
$response = $this->request('POST', Url::fromUri('base:/jsonapi/node/article/'), $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(201, $response->getStatusCode());
$document = Json::decode((string) $response->getBody());
$this->assertSame($title, $document['data']['attributes']['title']);
$this->assertSame('ca', $document['data']['attributes']['langcode']);
$this->assertSame(['ca'], array_keys(Node::load($document['data']['attributes']['drupal_internal__nid'])->getTranslationLanguages()));
@ -311,12 +311,12 @@ class JsonApiFunctionalMultilingualTest extends JsonApiFunctionalTestBase {
$response = $this->request('DELETE', Url::fromUri('base:/ca/jsonapi/node/article/' . $this->nodes[0]->uuid()), []);
$this->assertSame(405, $response->getStatusCode());
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame('Deleting a resource object translation is not yet supported. See https://www.drupal.org/docs/8/modules/jsonapi/translations.', $document['errors'][0]['detail']);
$response = $this->request('DELETE', Url::fromUri('base:/ca-fr/jsonapi/node/article/' . $this->nodes[0]->uuid()), []);
$this->assertSame(405, $response->getStatusCode());
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame('Deleting a resource object translation is not yet supported. See https://www.drupal.org/docs/8/modules/jsonapi/translations.', $document['errors'][0]['detail']);
$response = $this->request('DELETE', Url::fromUri('base:/jsonapi/node/article/' . $this->nodes[0]->uuid()), []);

View File

@ -282,7 +282,7 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
$this->userCanViewProfiles->pass_raw,
],
]);
$single_output = Json::decode($response->getBody()->__toString());
$single_output = $this->getDocumentFromResponse($response);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('user--user', $single_output['data']['type']);
$this->assertEquals($this->user->get('name')->value, $single_output['data']['attributes']['name']);
@ -608,22 +608,22 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'auth' => [$this->user->getAccountName(), $this->user->pass_raw],
'headers' => ['Content-Type' => 'application/vnd.api+json'],
]);
$created_response = Json::decode($response->getBody()->__toString());
$document = $this->getDocumentFromResponse($response);
$this->assertEquals(201, $response->getStatusCode());
$this->assertArrayNotHasKey('uuid', $created_response['data']['attributes']);
$uuid = $created_response['data']['id'];
$this->assertCount(2, $created_response['data']['relationships']['field_tags']['data']);
$this->assertEquals($created_response['data']['links']['self']['href'], $response->getHeader('Location')[0]);
$this->assertArrayNotHasKey('uuid', $document['data']['attributes']);
$uuid = $document['data']['id'];
$this->assertCount(2, $document['data']['relationships']['field_tags']['data']);
$this->assertEquals($document['data']['links']['self']['href'], $response->getHeader('Location')[0]);
// 2. Authorization error.
$response = $this->request('POST', $collection_url, [
'body' => Json::encode($body),
'headers' => ['Content-Type' => 'application/vnd.api+json'],
]);
$created_response = Json::decode($response->getBody()->__toString());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertEquals(401, $response->getStatusCode());
$this->assertNotEmpty($created_response['errors']);
$this->assertEquals('Unauthorized', $created_response['errors'][0]['title']);
$this->assertNotEmpty($document['errors']);
$this->assertEquals('Unauthorized', $document['errors'][0]['title']);
// 2.1 Authorization error with a user without create permissions.
$response = $this->request('POST', $collection_url, [
@ -631,10 +631,10 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'auth' => [$this->userCanViewProfiles->getAccountName(), $this->userCanViewProfiles->pass_raw],
'headers' => ['Content-Type' => 'application/vnd.api+json'],
]);
$created_response = Json::decode($response->getBody()->__toString());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertEquals(403, $response->getStatusCode());
$this->assertNotEmpty($created_response['errors']);
$this->assertEquals('Forbidden', $created_response['errors'][0]['title']);
$this->assertNotEmpty($document['errors']);
$this->assertEquals('Forbidden', $document['errors'][0]['title']);
// 3. Missing Content-Type error.
$response = $this->request('POST', $collection_url, [
@ -655,10 +655,10 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'Content-Type' => 'application/vnd.api+json',
],
]);
$created_response = Json::decode($response->getBody()->__toString());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertEquals(409, $response->getStatusCode());
$this->assertNotEmpty($created_response['errors']);
$this->assertEquals('Conflict', $created_response['errors'][0]['title']);
$this->assertNotEmpty($document['errors']);
$this->assertEquals('Conflict', $document['errors'][0]['title']);
// 5. Article with wrong reference UUIDs for tags.
$body_invalid_tags = $body;
$body_invalid_tags['data']['relationships']['field_tags']['data'][0]['id'] = 'lorem';
@ -678,10 +678,10 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'Accept' => 'application/vnd.api+json',
],
]);
$created_response = Json::decode($response->getBody()->__toString());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertEquals(400, $response->getStatusCode());
$this->assertNotEmpty($created_response['errors']);
$this->assertEquals('Bad Request', $created_response['errors'][0]['title']);
$this->assertNotEmpty($document['errors']);
$this->assertEquals('Bad Request', $document['errors'][0]['title']);
// 6.1 Denormalizing error.
$response = $this->request('POST', $collection_url, [
'body' => '{"data":{"type":"something"},"valid yet nonsensical json":[]}',
@ -691,10 +691,10 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'Accept' => 'application/vnd.api+json',
],
]);
$created_response = Json::decode($response->getBody()->__toString());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertEquals(422, $response->getStatusCode());
$this->assertNotEmpty($created_response['errors']);
$this->assertStringStartsWith('Unprocessable', $created_response['errors'][0]['title']);
$this->assertNotEmpty($document['errors']);
$this->assertStringStartsWith('Unprocessable', $document['errors'][0]['title']);
// 6.2 Relationships are not included in "data".
$malformed_body = $body;
unset($malformed_body['data']['relationships']);
@ -707,11 +707,11 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'Content-Type' => 'application/vnd.api+json',
],
]);
$created_response = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame(400, $response->getStatusCode());
$this->assertNotEmpty($created_response['errors']);
$this->assertSame("Bad Request", $created_response['errors'][0]['title']);
$this->assertSame("Found \"relationships\" within the document's top level. The \"relationships\" key must be within resource object.", $created_response['errors'][0]['detail']);
$this->assertNotEmpty($document['errors']);
$this->assertSame("Bad Request", $document['errors'][0]['title']);
$this->assertSame("Found \"relationships\" within the document's top level. The \"relationships\" key must be within resource object.", $document['errors'][0]['detail']);
// 6.2 "type" not included in "data".
$missing_type = $body;
unset($missing_type['data']['type']);
@ -723,11 +723,11 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'Content-Type' => 'application/vnd.api+json',
],
]);
$created_response = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame(400, $response->getStatusCode());
$this->assertNotEmpty($created_response['errors']);
$this->assertSame("Bad Request", $created_response['errors'][0]['title']);
$this->assertSame("Resource object must include a \"type\".", $created_response['errors'][0]['detail']);
$this->assertNotEmpty($document['errors']);
$this->assertSame("Bad Request", $document['errors'][0]['title']);
$this->assertSame("Resource object must include a \"type\".", $document['errors'][0]['detail']);
// 7. Successful PATCH.
$body = [
'data' => [
@ -744,7 +744,7 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'auth' => [$this->user->getAccountName(), $this->user->pass_raw],
'headers' => ['Content-Type' => 'application/vnd.api+json'],
]);
$updated_response = Json::decode($response->getBody()->__toString());
$updated_response = $this->getDocumentFromResponse($response);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('My updated title', $updated_response['data']['attributes']['title']);
@ -782,7 +782,7 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'auth' => [$this->user->getAccountName(), $this->user->pass_raw],
'headers' => ['Content-Type' => 'application/vnd.api+json'],
]);
$updated_response = Json::decode($response->getBody()->__toString());
$updated_response = $this->getDocumentFromResponse($response, FALSE);
$this->assertEquals(403, $response->getStatusCode());
$this->assertEquals("The current user is not allowed to PATCH the selected field (status). The 'administer nodes' permission is required.",
$updated_response['errors'][0]['detail']);
@ -806,7 +806,7 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'auth' => [$this->user->getAccountName(), $this->user->pass_raw],
'headers' => ['Content-Type' => 'application/vnd.api+json'],
]);
$updated_response = Json::decode($response->getBody()->__toString());
$updated_response = $this->getDocumentFromResponse($response);
$this->assertEquals(200, $response->getStatusCode());
$this->assertCount(3, $updated_response['data']);
$this->assertEquals('taxonomy_term--tags', $updated_response['data'][2]['type']);
@ -836,7 +836,7 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'Accept' => 'application/vnd.api+json',
],
]);
$updated_response = Json::decode($response->getBody()->__toString());
$updated_response = $this->getDocumentFromResponse($response, FALSE);
$this->assertEquals(
'You need to provide a body for DELETE operations on a relationship (field_tags).',
$updated_response['errors'][0]['detail']
@ -879,7 +879,7 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'Accept' => 'application/vnd.api+json',
],
]);
$updated_response = Json::decode($response->getBody()->__toString());
$updated_response = $this->getDocumentFromResponse($response, FALSE);
$this->assertEquals(422, $response->getStatusCode());
$this->assertCount(2, $updated_response['errors']);
for ($i = 0; $i < 2; $i++) {
@ -908,7 +908,7 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
'Accept' => 'application/vnd.api+json',
],
]);
$updated_response = Json::decode($response->getBody()->__toString());
$updated_response = $this->getDocumentFromResponse($response, FALSE);
$this->assertEquals(422, $response->getStatusCode());
$this->assertEquals("The attribute field_that_does_not_exist does not exist on the node--article resource type.",
$updated_response['errors']['0']['detail']);

View File

@ -14,6 +14,7 @@ use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\field\Traits\EntityReferenceFieldCreationTrait;
use Drupal\Tests\image\Kernel\ImageFieldCreationTrait;
use Drupal\Tests\jsonapi\Traits\GetDocumentFromResponseTrait;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
use GuzzleHttp\Exception\ClientException;
@ -27,6 +28,7 @@ use GuzzleHttp\Exception\ServerException;
abstract class JsonApiFunctionalTestBase extends BrowserTestBase {
use EntityReferenceFieldCreationTrait;
use GetDocumentFromResponseTrait;
use ImageFieldCreationTrait;
const IS_MULTILINGUAL = TRUE;

View File

@ -7,7 +7,6 @@ namespace Drupal\Tests\jsonapi\Functional;
use Drupal\comment\Entity\Comment;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
@ -271,18 +270,18 @@ class JsonApiPatchRegressionTest extends JsonApiFunctionalTestBase {
];
$node_url = Url::fromUri('internal:/jsonapi/node/page/' . $page->uuid());
$response = $this->request('GET', $node_url, $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$doc = Json::decode((string) $response->getBody());
$this->assertSame('2018-12-19', $doc['data']['attributes']['when']);
$this->assertSame('2018-12-20T04:00:00+11:00', $doc['data']['attributes']['when_exactly']);
$doc['data']['attributes']['when'] = '2018-12-20';
$doc['data']['attributes']['when_exactly'] = '2018-12-19T19:00:00+01:00';
$request_options = $request_options + [RequestOptions::JSON => $doc];
$this->assertSame('2018-12-19', $document['data']['attributes']['when']);
$this->assertSame('2018-12-20T04:00:00+11:00', $document['data']['attributes']['when_exactly']);
$document['data']['attributes']['when'] = '2018-12-20';
$document['data']['attributes']['when_exactly'] = '2018-12-19T19:00:00+01:00';
$request_options = $request_options + [RequestOptions::JSON => $document];
$response = $this->request('PATCH', $node_url, $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$doc = Json::decode((string) $response->getBody());
$this->assertSame('2018-12-20', $doc['data']['attributes']['when']);
$this->assertSame('2018-12-20T05:00:00+11:00', $doc['data']['attributes']['when_exactly']);
$this->assertSame('2018-12-20', $document['data']['attributes']['when']);
$this->assertSame('2018-12-20T05:00:00+11:00', $document['data']['attributes']['when_exactly']);
}
/**
@ -325,10 +324,10 @@ class JsonApiPatchRegressionTest extends JsonApiFunctionalTestBase {
],
];
$response = $this->request('PATCH', $url, $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$doc = Json::decode((string) $response->getBody());
$this->assertArrayHasKey('included', $doc);
$this->assertSame($user->label(), $doc['included'][0]['attributes']['name']);
$this->assertArrayHasKey('included', $document);
$this->assertSame($user->label(), $document['included'][0]['attributes']['name']);
}
/**
@ -369,8 +368,8 @@ class JsonApiPatchRegressionTest extends JsonApiFunctionalTestBase {
// GET the test entity via JSON:API.
$entity_url = Url::fromUri('internal:/jsonapi/entity_test/entity_test/' . $entity->uuid());
$response = $this->request('GET', $entity_url, $request_options);
$response_document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$response_document = Json::decode($response->getBody());
// Ensure that the entity's langcode attribute is 'und'.
$this->assertSame(LanguageInterface::LANGCODE_NOT_SPECIFIED, $response_document['data']['attributes']['langcode']);
// Prepare to PATCH the entity via JSON:API.
@ -387,8 +386,8 @@ class JsonApiPatchRegressionTest extends JsonApiFunctionalTestBase {
// Issue the PATCH request and verify that the test entity was successfully
// updated.
$response = $this->request('PATCH', $entity_url, $request_options);
$response_document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode(), (string) $response->getBody());
$response_document = Json::decode($response->getBody());
// Ensure that the entity's langcode attribute is still 'und' and the name
// was successfully updated.
$this->assertSame(LanguageInterface::LANGCODE_NOT_SPECIFIED, $response_document['data']['attributes']['langcode']);
@ -450,7 +449,7 @@ class JsonApiPatchRegressionTest extends JsonApiFunctionalTestBase {
$response = $this->request('PATCH', $url, $request_options);
// Assert a helpful error response is present.
$data = Json::decode((string) $response->getBody());
$data = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame(422, $response->getStatusCode());
$this->assertNotNull($data);
// cSpell:disable-next-line
@ -483,7 +482,7 @@ class JsonApiPatchRegressionTest extends JsonApiFunctionalTestBase {
$response = $this->request('PATCH', $url, $request_options);
// Assert a helpful error response is present.
$data = Json::decode((string) $response->getBody());
$data = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame(422, $response->getStatusCode());
$this->assertNotNull($data);
// cSpell:disable-next-line

View File

@ -260,6 +260,7 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
];
$issue_node->delete();
$response = $this->request('GET', $url, $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
// Entity reference field allowing a single bundle: dangling reference's
@ -279,7 +280,7 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
],
],
],
], Json::decode((string) $response->getBody())['data']['relationships']['field_issue']['data']);
], $document['data']['relationships']['field_issue']['data']);
// Entity reference field allowing multiple bundles: dangling reference's
// resource type is NOT deduced.
@ -305,7 +306,7 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
'drupal_internal__target_id' => (int) $conference_node->id(),
],
],
], Json::decode((string) $response->getBody())['data']['relationships']['field_mentioned_in']['data']);
], $document['data']['relationships']['field_mentioned_in']['data']);
}
/**
@ -513,8 +514,8 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
$user->pass_raw,
],
]);
$doc = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$doc = Json::decode((string) $response->getBody());
$this->assertSame('2018-09-16T22:00:00+10:00', $doc['data']['attributes']['when']);
}
@ -549,8 +550,8 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
],
];
$response = $this->request('POST', $url, $request_options);
$doc = $this->getDocumentFromResponse($response);
$this->assertSame(201, $response->getStatusCode());
$doc = Json::decode((string) $response->getBody());
$this->assertArrayHasKey('included', $doc);
$this->assertSame($user->label(), $doc['included'][0]['attributes']['name']);
}
@ -586,8 +587,8 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
RequestOptions::AUTH => [$user->getAccountName(), $user->pass_raw],
];
$response = $this->request('GET', $url, $request_options);
$data = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$data = Json::decode((string) $response->getBody());
$this->assertSame([
'foo' => 'bar',
'baz' => 'qux',
@ -597,8 +598,8 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
'foo' => 'bar',
])->save();
$response = $this->request('GET', $url, $request_options);
$data = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$data = Json::decode((string) $response->getBody());
$this->assertSame(['foo' => 'bar'], $data['data'][0]['attributes']['data']);
}
@ -633,7 +634,7 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
$response = $this->request('POST', $url, $request_options);
// Assert that the response has a body.
$data = Json::decode((string) $response->getBody());
$data = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame(422, $response->getStatusCode());
$this->assertNotNull($data);
$this->assertSame(sprintf('title: This value should not be null.'), $data['errors'][0]['detail']);
@ -644,7 +645,7 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
$response = $this->request('POST', $url, $request_options);
// Assert that the response has a body.
$data = Json::decode((string) $response->getBody());
$data = $this->getDocumentFromResponse($response, FALSE);
$this->assertSame(422, $response->getStatusCode());
$this->assertNotNull($data);
$this->assertSame(sprintf('title: This value should not be null.'), $data['errors'][0]['detail']);
@ -707,8 +708,8 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
];
// Retrieve the current representation of the entity.
$response = $this->request('GET', $url, $request_options);
$doc = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$doc = Json::decode((string) $response->getBody());
// Modify the title. The @FieldType=map normalization is not changed. (The
// name of this field is confusingly also 'data'.)
$doc['data']['attributes']['name'] = 'bar';
@ -718,8 +719,9 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
];
$request_options[RequestOptions::BODY] = Json::encode($doc);
$response = $this->request('PATCH', $url, $request_options);
$patched_document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$this->assertSame($doc['data']['attributes']['data'], Json::decode((string) $response->getBody())['data']['attributes']['data']);
$this->assertSame($doc['data']['attributes']['data'], $patched_document['data']['attributes']['data']);
}
/**
@ -759,12 +761,12 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
'query' => ['include' => 'field_tags'],
]);
$response = $this->request('GET', $url, $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$response = Json::decode((string) $response->getBody());
$this->assertArrayNotHasKey('included', $response, 'JSON API response does not contain "included" taxonomy term as the latter is not published, i.e not accessible.');
$this->assertArrayNotHasKey('included', $document, 'JSON API response does not contain "included" taxonomy term as the latter is not published, i.e not accessible.');
$omitted = $response['meta']['omitted']['links'];
$omitted = $document['meta']['omitted']['links'];
unset($omitted['help']);
$omitted = reset($omitted);
$expected_url = Url::fromUri('internal:/jsonapi/' . $term->getEntityTypeId() . '/' . $term->bundle() . '/' . $term->uuid());
@ -774,8 +776,9 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
$term->setPublished();
$term->save();
$response = $this->request('GET', $url, $request_options);
$document = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$this->assertEquals($term->uuid(), Json::decode((string) $response->getBody())['included'][0]['id'], 'JSON API response contains "included" taxonomy term as it became published, i.e accessible.');
$this->assertEquals($term->uuid(), $document['included'][0]['id'], 'JSON API response contains "included" taxonomy term as it became published, i.e accessible.');
}
/**

View File

@ -223,7 +223,7 @@ class MenuLinkContentTest extends ResourceTestBase {
unset($document['data']['attributes']['link']['options']);
$request_options[RequestOptions::BODY] = Json::encode($document);
$response = $this->request('POST', $url, $request_options);
$document = Json::decode((string) $response->getBody());
$document = $this->getDocumentFromResponse($response);
$internal_id = $document['data']['attributes']['drupal_internal__id'];
// Load the created menu item and add link options to it.

View File

@ -292,7 +292,7 @@ class NodeTest extends ResourceTestBase {
// GET node's current normalization.
$response = $this->request('GET', $url, $this->getAuthenticationRequestOptions());
$normalization = Json::decode((string) $response->getBody());
$normalization = $this->getDocumentFromResponse($response);
// Change node's path alias.
$normalization['data']['attributes']['path']['alias'] .= 's-rule-the-world';
@ -311,8 +311,8 @@ class NodeTest extends ResourceTestBase {
// Repeat PATCH request: 200.
$response = $this->request('PATCH', $url, $request_options);
$updated_normalization = $this->getDocumentFromResponse($response);
$this->assertResourceResponse(200, FALSE, $response);
$updated_normalization = Json::decode((string) $response->getBody());
$this->assertSame($normalization['data']['attributes']['path']['alias'], $updated_normalization['data']['attributes']['path']['alias']);
}
@ -501,21 +501,21 @@ class NodeTest extends ResourceTestBase {
// 0 results because the node is unpublished.
$response = $this->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(0, $doc['data']);
$this->grantPermissionsToTestedRole(['view own unpublished content']);
// 1 result because the current user is the owner of the unpublished node.
$response = $this->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(1, $doc['data']);
$this->entity->setOwnerId(0)->save();
// 0 results because the current user is no longer the owner.
$response = $this->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(0, $doc['data']);
// Assert bubbling of cacheability from query alter hook.

View File

@ -43,6 +43,7 @@ use Drupal\jsonapi\ResourceResponse;
use Drupal\path\Plugin\Field\FieldType\PathItem;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
use Drupal\Tests\jsonapi\Traits\GetDocumentFromResponseTrait;
use Drupal\user\Entity\Role;
use Drupal\user\EntityOwnerInterface;
use Drupal\user\RoleInterface;
@ -58,6 +59,7 @@ abstract class ResourceTestBase extends BrowserTestBase {
use ResourceResponseTestTrait;
use ContentModerationTestTrait;
use GetDocumentFromResponseTrait;
use JsonApiRequestTestTrait;
/**
@ -728,7 +730,7 @@ abstract class ResourceTestBase extends BrowserTestBase {
else {
$this->assertSame(['application/vnd.api+json'], $response->getHeader('Content-Type'));
if ($expected_document !== FALSE) {
$response_document = Json::decode((string) $response->getBody());
$response_document = $this->getDocumentFromResponse($response, FALSE);
if ($expected_document === NULL) {
$this->assertNull($response_document);
}
@ -1627,7 +1629,8 @@ abstract class ResourceTestBase extends BrowserTestBase {
$resource->set($relationship_field_name, [$target_resource]);
$expected_document = $this->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$response = $this->request('GET', $url, $request_options);
$this->assertSameDocument($expected_document, Json::decode((string) $response->getBody()));
$document = $this->getDocumentFromResponse($response);
$this->assertSameDocument($expected_document, $document);
// Test DELETE: one existing relationship, removed.
$request_options[RequestOptions::BODY] = Json::encode(['data' => [$target_identifier]]);
@ -1636,7 +1639,8 @@ abstract class ResourceTestBase extends BrowserTestBase {
$this->assertResourceResponse(204, NULL, $response);
$expected_document = $this->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$response = $this->request('GET', $url, $request_options);
$this->assertSameDocument($expected_document, Json::decode((string) $response->getBody()));
$document = $this->getDocumentFromResponse($response);
$this->assertSameDocument($expected_document, $document);
// Test DELETE: no existing relationships, no op, success.
$request_options[RequestOptions::BODY] = Json::encode(['data' => [$target_identifier]]);
@ -1644,7 +1648,8 @@ abstract class ResourceTestBase extends BrowserTestBase {
$this->assertResourceResponse(204, NULL, $response);
$expected_document = $this->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$response = $this->request('GET', $url, $request_options);
$this->assertSameDocument($expected_document, Json::decode((string) $response->getBody()));
$document = $this->getDocumentFromResponse($response);
$this->assertSameDocument($expected_document, $document);
// Test PATCH: success, new value is different than existing value.
$request_options[RequestOptions::BODY] = Json::encode([
@ -1672,7 +1677,8 @@ abstract class ResourceTestBase extends BrowserTestBase {
$resource->set($relationship_field_name, []);
$expected_document = $this->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$response = $this->request('GET', $url, $request_options);
$this->assertSameDocument($expected_document, Json::decode((string) $response->getBody()));
$document = $this->getDocumentFromResponse($response);
$this->assertSameDocument($expected_document, $document);
}
else {
$request_options[RequestOptions::BODY] = Json::encode(['data' => [$target_identifier]]);
@ -2106,7 +2112,7 @@ abstract class ResourceTestBase extends BrowserTestBase {
// Assert that the entity was indeed created, and that the response body
// contains the serialized created entity.
$created_entity_document = $this->normalize($created_entity, $url);
$decoded_response_body = Json::decode((string) $response->getBody());
$decoded_response_body = $this->getDocumentFromResponse($response);
$this->assertEquals($created_entity_document, $decoded_response_body);
// Assert that the entity was indeed created using the POSTed values.
foreach ($this->getPostDocument()['data']['attributes'] as $field_name => $field_normalization) {
@ -2370,7 +2376,8 @@ abstract class ResourceTestBase extends BrowserTestBase {
}
}
$updated_entity_document = $this->normalize($updated_entity, $url);
$this->assertSame($updated_entity_document, Json::decode((string) $response->getBody()));
$document = $this->getDocumentFromResponse($response);
$this->assertSame($updated_entity_document, $document);
$prior_revision_id = (int) $updated_entity->getRevisionId();
// Assert that the entity was indeed created using the PATCHed values.
foreach ($this->getPatchDocument()['data']['attributes'] as $field_name => $field_normalization) {

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Drupal\Tests\jsonapi\Functional;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
@ -183,7 +182,7 @@ class ShortcutTest extends ResourceTestBase {
// No results because the current user does not have access to shortcuts
// not in the user's assigned set or the default set.
$response = $this->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(0, $doc['data']);
// Assign the alternate shortcut set to the current user.
@ -192,7 +191,7 @@ class ShortcutTest extends ResourceTestBase {
// 1 result because the alternate shortcut set is now assigned to the
// current user.
$response = $this->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(1, $doc['data']);
}

View File

@ -416,7 +416,7 @@ class TermTest extends ResourceTestBase {
// GET term's current normalization.
$response = $this->request('GET', $url, $request_options);
$normalization = Json::decode((string) $response->getBody());
$normalization = $this->getDocumentFromResponse($response);
// Change term's path alias.
$normalization['data']['attributes']['path']['alias'] .= 's-rule-the-world';
@ -426,8 +426,8 @@ class TermTest extends ResourceTestBase {
// PATCH request: 200.
$response = $this->request('PATCH', $url, $request_options);
$updated_normalization = $this->getDocumentFromResponse($response);
$this->assertResourceResponse(200, FALSE, $response);
$updated_normalization = Json::decode((string) $response->getBody());
$this->assertSame($normalization['data']['attributes']['path']['alias'], $updated_normalization['data']['attributes']['path']['alias']);
}

View File

@ -230,7 +230,7 @@ class UserTest extends ResourceTestBase {
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions());
$response = $this->request('GET', $url, $request_options);
$original_normalization = Json::decode((string) $response->getBody());
$original_normalization = $this->getDocumentFromResponse($response);
// Test case 1: changing email.
$normalization = $original_normalization;
@ -263,7 +263,7 @@ class UserTest extends ResourceTestBase {
$this->assertResourceResponse(200, FALSE, $response);
// Test case 2: changing password.
$normalization = Json::decode((string) $response->getBody());
$normalization = $this->getDocumentFromResponse($response);
$normalization['data']['attributes']['mail'] = 'new-email@example.com';
$new_password = $this->randomString();
$normalization['data']['attributes']['pass']['value'] = $new_password;
@ -291,7 +291,7 @@ class UserTest extends ResourceTestBase {
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions());
// Test case 3: changing name.
$normalization = Json::decode((string) $response->getBody());
$normalization = $this->getDocumentFromResponse($response);
$normalization['data']['attributes']['mail'] = 'new-email@example.com';
$normalization['data']['attributes']['pass']['existing'] = $new_password;
$normalization['data']['attributes']['name'] = 'Cooler Llama';
@ -405,11 +405,11 @@ class UserTest extends ResourceTestBase {
// Viewing user A as user A: "mail" field is accessible.
$response = $this->request('GET', $user_a_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertArrayHasKey('mail', $doc['data']['attributes']);
// Also when looking at the collection.
$response = $this->request('GET', $collection_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertSame($user_a->uuid(), $doc['data']['2']['id']);
$this->assertArrayHasKey('mail', $doc['data'][2]['attributes'], "Own user--user resource's 'mail' field is visible.");
$this->assertSame($user_b->uuid(), $doc['data'][count($doc['data']) - 1]['id']);
@ -420,11 +420,11 @@ class UserTest extends ResourceTestBase {
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions());
// Viewing user A as user B: "mail" field should be inaccessible.
$response = $this->request('GET', $user_a_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertArrayNotHasKey('mail', $doc['data']['attributes']);
// Also when looking at the collection.
$response = $this->request('GET', $collection_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertSame($user_a->uuid(), $doc['data']['2']['id']);
$this->assertArrayNotHasKey('mail', $doc['data'][2]['attributes']);
$this->assertSame($user_b->uuid(), $doc['data'][count($doc['data']) - 1]['id']);
@ -434,11 +434,11 @@ class UserTest extends ResourceTestBase {
$this->grantPermissionsToTestedRole(['view user email addresses']);
// Viewing user A as user B: "mail" field should be accessible.
$response = $this->request('GET', $user_a_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertArrayHasKey('mail', $doc['data']['attributes']);
// Also when looking at the collection.
$response = $this->request('GET', $collection_url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertSame($user_a->uuid(), $doc['data']['2']['id']);
$this->assertArrayHasKey('mail', $doc['data'][2]['attributes']);
}
@ -472,7 +472,7 @@ class UserTest extends ResourceTestBase {
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions());
$response = $this->request('GET', $url, $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(4, $doc['data']);
$this->assertSame(User::load(0)->uuid(), $doc['data'][0]['id']);
@ -530,58 +530,58 @@ class UserTest extends ResourceTestBase {
// ?filter[uid.id]=OWN_UUID requires no permissions: 1 result.
$response = $this->request('GET', $collection_url->setOption('query', ['filter[uid.id]' => $this->account->uuid()]), $request_options);
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.permissions');
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(1, $doc['data']);
$this->assertSame($node_auth_1->uuid(), $doc['data'][0]['id']);
// ?filter[uid.id]=ANONYMOUS_UUID: 0 results.
$response = $this->request('GET', $collection_url->setOption('query', ['filter[uid.id]' => User::load(0)->uuid()]), $request_options);
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.permissions');
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(0, $doc['data']);
// ?filter[uid.name]=A: 0 results.
$response = $this->request('GET', $collection_url->setOption('query', ['filter[uid.name]' => 'A']), $request_options);
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(0, $doc['data']);
// /jsonapi/user/user?filter[field_favorite_animal]: 0 results.
$response = $this->request('GET', $favorite_animal_test_url, $request_options);
$doc = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$doc = Json::decode((string) $response->getBody());
$this->assertCount(0, $doc['data']);
// Grant "view" permission.
$this->grantPermissionsToTestedRole(['access user profiles']);
// ?filter[uid.id]=ANONYMOUS_UUID: 0 results.
$response = $this->request('GET', $collection_url->setOption('query', ['filter[uid.id]' => User::load(0)->uuid()]), $request_options);
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.permissions');
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(0, $doc['data']);
// ?filter[uid.name]=A: 1 result since user A is active.
$response = $this->request('GET', $collection_url->setOption('query', ['filter[uid.name]' => 'A']), $request_options);
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.permissions');
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(1, $doc['data']);
$this->assertSame($node_a->uuid(), $doc['data'][0]['id']);
// ?filter[uid.name]=B: 0 results since user B is blocked.
$response = $this->request('GET', $collection_url->setOption('query', ['filter[uid.name]' => 'B']), $request_options);
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.permissions');
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(0, $doc['data']);
// /jsonapi/user/user?filter[field_favorite_animal]: 0 results.
$response = $this->request('GET', $favorite_animal_test_url, $request_options);
$doc = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$doc = Json::decode((string) $response->getBody());
$this->assertCount(0, $doc['data']);
// Grant "admin" permission.
$this->grantPermissionsToTestedRole(['administer users']);
// ?filter[uid.name]=B: 1 result.
$response = $this->request('GET', $collection_url->setOption('query', ['filter[uid.name]' => 'B']), $request_options);
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.permissions');
$doc = Json::decode((string) $response->getBody());
$doc = $this->getDocumentFromResponse($response);
$this->assertCount(1, $doc['data']);
$this->assertSame($node_b->uuid(), $doc['data'][0]['id']);
// /jsonapi/user/user?filter[field_favorite_animal]: 1 result.
$response = $this->request('GET', $favorite_animal_test_url, $request_options);
$doc = $this->getDocumentFromResponse($response);
$this->assertSame(200, $response->getStatusCode());
$doc = Json::decode((string) $response->getBody());
$this->assertCount(1, $doc['data']);
$this->assertSame($user_b->uuid(), $doc['data'][0]['id']);
}

View File

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\jsonapi\Traits;
use Drupal\Component\Serialization\Json;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
/**
* Test trait for retrieving the JSON:API document from a response.
*/
trait GetDocumentFromResponseTrait {
/**
* Retrieve document from response, with basic validation.
*
* @param \Psr\Http\Message\ResponseInterface $response
* Response to extract JSON:API document from.
* @param bool $validate
* Determines whether the data is validated or not. Defaults to TRUE.
*
* @return ?array
* JSON:API document extracted from the response, or NULL.
*
* @throws \PHPUnit\Framework\AssertionFailedError
* Thrown when the document does not pass basic validation against the spec.
*/
protected function getDocumentFromResponse(ResponseInterface $response, bool $validate = TRUE): ?array {
assert($this instanceof TestCase);
$document = Json::decode((string) $response->getBody());
if (isset($document['data']) && isset($document['errors'])) {
$this->fail('Document contains both data and errors members; only one is allowed.');
}
if ($validate === TRUE && !isset($document['data'])) {
if (isset($document['errors'])) {
$errors = [];
foreach ($document['errors'] as $error) {
$errors[] = $error['title'] . ' (' . $error['status'] . '): ' . $error['detail'];
}
$this->fail('Missing expected data member in document. Error(s): ' . PHP_EOL . ' ' . implode(' ' . PHP_EOL, $errors));
}
$this->fail('Missing both data and errors members in document; either is required. Response body: ' . PHP_EOL . ' ' . $response->getBody());
}
return $document;
}
}