diff --git a/core/modules/jsonapi/tests/src/Functional/CommentTest.php b/core/modules/jsonapi/tests/src/Functional/CommentTest.php index 9a0e0eff57f..e972aca15f4 100644 --- a/core/modules/jsonapi/tests/src/Functional/CommentTest.php +++ b/core/modules/jsonapi/tests/src/Functional/CommentTest.php @@ -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']); } diff --git a/core/modules/jsonapi/tests/src/Functional/ConfigurableLanguageTest.php b/core/modules/jsonapi/tests/src/Functional/ConfigurableLanguageTest.php index d9b1dedee07..f6ec17d1f2e 100644 --- a/core/modules/jsonapi/tests/src/Functional/ConfigurableLanguageTest.php +++ b/core/modules/jsonapi/tests/src/Functional/ConfigurableLanguageTest.php @@ -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']); } diff --git a/core/modules/jsonapi/tests/src/Functional/EntryPointTest.php b/core/modules/jsonapi/tests/src/Functional/EntryPointTest.php index 1e8360234cd..b4334085035 100644 --- a/core/modules/jsonapi/tests/src/Functional/EntryPointTest.php +++ b/core/modules/jsonapi/tests/src/Functional/EntryPointTest.php @@ -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']); } diff --git a/core/modules/jsonapi/tests/src/Functional/ExternalNormalizersTest.php b/core/modules/jsonapi/tests/src/Functional/ExternalNormalizersTest.php index 3efaea6791f..c0b9131aff6 100644 --- a/core/modules/jsonapi/tests/src/Functional/ExternalNormalizersTest.php +++ b/core/modules/jsonapi/tests/src/Functional/ExternalNormalizersTest.php @@ -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'); diff --git a/core/modules/jsonapi/tests/src/Functional/FileTest.php b/core/modules/jsonapi/tests/src/Functional/FileTest.php index b24dbc73f06..b4a7b71676f 100644 --- a/core/modules/jsonapi/tests/src/Functional/FileTest.php +++ b/core/modules/jsonapi/tests/src/Functional/FileTest.php @@ -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']); } diff --git a/core/modules/jsonapi/tests/src/Functional/FileUploadTest.php b/core/modules/jsonapi/tests/src/Functional/FileUploadTest.php index bc566701d7a..127dd9e73a2 100644 --- a/core/modules/jsonapi/tests/src/Functional/FileUploadTest.php +++ b/core/modules/jsonapi/tests/src/Functional/FileUploadTest.php @@ -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); diff --git a/core/modules/jsonapi/tests/src/Functional/JsonApiFilterRegressionTest.php b/core/modules/jsonapi/tests/src/Functional/JsonApiFilterRegressionTest.php index 442a43b6fb0..9a0faaac582 100644 --- a/core/modules/jsonapi/tests/src/Functional/JsonApiFilterRegressionTest.php +++ b/core/modules/jsonapi/tests/src/Functional/JsonApiFilterRegressionTest.php @@ -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']); diff --git a/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalMultilingualTest.php b/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalMultilingualTest.php index e305a74803f..d60a0e3df15 100644 --- a/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalMultilingualTest.php +++ b/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalMultilingualTest.php @@ -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()), []); diff --git a/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalTest.php b/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalTest.php index 71daad24ffc..211eae28377 100644 --- a/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalTest.php +++ b/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalTest.php @@ -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']); diff --git a/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalTestBase.php b/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalTestBase.php index 239e8b9014d..1ed47faa06a 100644 --- a/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalTestBase.php +++ b/core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalTestBase.php @@ -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; diff --git a/core/modules/jsonapi/tests/src/Functional/JsonApiPatchRegressionTest.php b/core/modules/jsonapi/tests/src/Functional/JsonApiPatchRegressionTest.php index 8b3aa4a3b53..c2cd0d9e6cf 100644 --- a/core/modules/jsonapi/tests/src/Functional/JsonApiPatchRegressionTest.php +++ b/core/modules/jsonapi/tests/src/Functional/JsonApiPatchRegressionTest.php @@ -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 diff --git a/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php b/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php index c6b4259ea65..d40774144c3 100644 --- a/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php +++ b/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php @@ -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.'); } /** diff --git a/core/modules/jsonapi/tests/src/Functional/MenuLinkContentTest.php b/core/modules/jsonapi/tests/src/Functional/MenuLinkContentTest.php index 779a4ca7865..b1130951263 100644 --- a/core/modules/jsonapi/tests/src/Functional/MenuLinkContentTest.php +++ b/core/modules/jsonapi/tests/src/Functional/MenuLinkContentTest.php @@ -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. diff --git a/core/modules/jsonapi/tests/src/Functional/NodeTest.php b/core/modules/jsonapi/tests/src/Functional/NodeTest.php index 7d5ec952390..3e4a4d7dacd 100644 --- a/core/modules/jsonapi/tests/src/Functional/NodeTest.php +++ b/core/modules/jsonapi/tests/src/Functional/NodeTest.php @@ -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. diff --git a/core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php b/core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php index ff14e5a3722..9586bc1accc 100644 --- a/core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php +++ b/core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php @@ -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) { diff --git a/core/modules/jsonapi/tests/src/Functional/ShortcutTest.php b/core/modules/jsonapi/tests/src/Functional/ShortcutTest.php index fdb64885ee6..20dd4b5f4ed 100644 --- a/core/modules/jsonapi/tests/src/Functional/ShortcutTest.php +++ b/core/modules/jsonapi/tests/src/Functional/ShortcutTest.php @@ -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']); } diff --git a/core/modules/jsonapi/tests/src/Functional/TermTest.php b/core/modules/jsonapi/tests/src/Functional/TermTest.php index 649237d997a..05d9212fdef 100644 --- a/core/modules/jsonapi/tests/src/Functional/TermTest.php +++ b/core/modules/jsonapi/tests/src/Functional/TermTest.php @@ -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']); } diff --git a/core/modules/jsonapi/tests/src/Functional/UserTest.php b/core/modules/jsonapi/tests/src/Functional/UserTest.php index 49eca5f48b4..a281a743c7f 100644 --- a/core/modules/jsonapi/tests/src/Functional/UserTest.php +++ b/core/modules/jsonapi/tests/src/Functional/UserTest.php @@ -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']); } diff --git a/core/modules/jsonapi/tests/src/Traits/GetDocumentFromResponseTrait.php b/core/modules/jsonapi/tests/src/Traits/GetDocumentFromResponseTrait.php new file mode 100644 index 00000000000..955d24c922f --- /dev/null +++ b/core/modules/jsonapi/tests/src/Traits/GetDocumentFromResponseTrait.php @@ -0,0 +1,52 @@ +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; + } + +}