protected function ResourceTestBase::doTestRelationshipPost in JSON:API 8
Performs one round of relationship POST, PATCH and DELETE route testing.
Parameters
array $request_options: Request options to apply.
See also
\GuzzleHttp\ClientInterface::request()
::testRelationships
2 calls to ResourceTestBase::doTestRelationshipPost()
- MediaTest::doTestRelationshipPost in tests/
src/ Functional/ MediaTest.php  - @todo Remove this in https://www.drupal.org/node/2824851.
 - ResourceTestBase::testRelationships in tests/
src/ Functional/ ResourceTestBase.php  - Tests CRUD of individual resource relationship data.
 
1 method overrides ResourceTestBase::doTestRelationshipPost()
- MediaTest::doTestRelationshipPost in tests/
src/ Functional/ MediaTest.php  - @todo Remove this in https://www.drupal.org/node/2824851.
 
File
- tests/
src/ Functional/ ResourceTestBase.php, line 1384  
Class
- ResourceTestBase
 - Subclass this for every JSON API resource type.
 
Namespace
Drupal\Tests\jsonapi\FunctionalCode
protected function doTestRelationshipPost(array $request_options) {
  /* @var \Drupal\Core\Entity\FieldableEntityInterface $resource */
  $resource = $this
    ->createAnotherEntity('dupe');
  $resource
    ->set('field_jsonapi_test_entity_ref', NULL);
  $violations = $resource
    ->validate();
  assert($violations
    ->count() === 0, (string) $violations);
  $resource
    ->save();
  $target_resource = $this
    ->createUser();
  $violations = $target_resource
    ->validate();
  assert($violations
    ->count() === 0, (string) $violations);
  $target_resource
    ->save();
  $target_identifier = static::toResourceIdentifier($target_resource);
  $resource_identifier = static::toResourceIdentifier($resource);
  $relationship_field_name = 'field_jsonapi_test_entity_ref';
  /* @var \Drupal\Core\Access\AccessResultReasonInterface $update_access */
  $update_access = static::entityAccess($resource, 'update', $this->account)
    ->andIf(static::entityFieldAccess($resource, $relationship_field_name, 'update', $this->account));
  $url = Url::fromRoute(sprintf("jsonapi.{$resource_identifier['type']}.relationship"), [
    'related' => $relationship_field_name,
    $resource
      ->getEntityTypeId() => $resource
      ->uuid(),
  ]);
  if ($update_access
    ->isAllowed()) {
    // Test POST: empty body.
    $response = $this
      ->request('POST', $url, $request_options);
    $this
      ->assertResourceErrorResponse(400, 'Empty request body.', $response);
    // Test PATCH: empty body.
    $response = $this
      ->request('PATCH', $url, $request_options);
    $this
      ->assertResourceErrorResponse(400, 'Empty request body.', $response);
    // Test POST: empty data.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => [],
    ]);
    $response = $this
      ->request('POST', $url, $request_options);
    $this
      ->assertResourceResponse(204, NULL, $response);
    // Test PATCH: empty data.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => [],
    ]);
    $response = $this
      ->request('PATCH', $url, $request_options);
    $this
      ->assertResourceResponse(204, NULL, $response);
    // Test POST: data as resource identifier, not array of identifiers.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => $target_identifier,
    ]);
    $response = $this
      ->request('POST', $url, $request_options);
    $this
      ->assertResourceErrorResponse(400, 'Invalid body payload for the relationship.', $response);
    // Test PATCH: data as resource identifier, not array of identifiers.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => $target_identifier,
    ]);
    $response = $this
      ->request('PATCH', $url, $request_options);
    $this
      ->assertResourceErrorResponse(400, 'Invalid body payload for the relationship.', $response);
    // Test POST: missing the 'type' field.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => array_intersect_key($target_identifier, [
        'id' => 'id',
      ]),
    ]);
    $response = $this
      ->request('POST', $url, $request_options);
    $this
      ->assertResourceErrorResponse(400, 'Invalid body payload for the relationship.', $response);
    // Test PATCH: missing the 'type' field.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => array_intersect_key($target_identifier, [
        'id' => 'id',
      ]),
    ]);
    $response = $this
      ->request('PATCH', $url, $request_options);
    $this
      ->assertResourceErrorResponse(400, 'Invalid body payload for the relationship.', $response);
    // If the base resource type is the same as that of the target's (as it
    // will be for `user--user`), then the validity error will not be
    // triggered, needlessly failing this assertion.
    if (static::$resourceTypeName !== $target_identifier['type']) {
      // Test POST: invalid target.
      $request_options[RequestOptions::BODY] = Json::encode([
        'data' => [
          $resource_identifier,
        ],
      ]);
      $response = $this
        ->request('POST', $url, $request_options);
      $this
        ->assertResourceErrorResponse(400, sprintf('The provided type (%s) does not mach the destination resource types (%s).', $resource_identifier['type'], $target_identifier['type']), $response);
      // Test PATCH: invalid target.
      $request_options[RequestOptions::BODY] = Json::encode([
        'data' => [
          $resource_identifier,
        ],
      ]);
      $response = $this
        ->request('POST', $url, $request_options);
      $this
        ->assertResourceErrorResponse(400, sprintf('The provided type (%s) does not mach the destination resource types (%s).', $resource_identifier['type'], $target_identifier['type']), $response);
    }
    // Test POST: success.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => [
        $target_identifier,
      ],
    ]);
    $response = $this
      ->request('POST', $url, $request_options);
    $resource
      ->set($relationship_field_name, [
      $target_resource,
    ]);
    $this
      ->assertResourceResponse(204, NULL, $response);
    // @todo: Uncomment the following two assertions in https://www.drupal.org/project/jsonapi/issues/2977659.
    // Test POST: success, relationship already exists, no arity.
    // @codingStandardsIgnoreStart
    /*
    $response = $this->request('POST', $url, $request_options);
    $this->assertResourceResponse(204, NULL, $response);
    */
    // @codingStandardsIgnoreEnd
    // Test PATCH: success, new value is the same as existing value.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => [
        $target_identifier,
      ],
    ]);
    $response = $this
      ->request('PATCH', $url, $request_options);
    $resource
      ->set($relationship_field_name, [
      $target_resource,
    ]);
    $this
      ->assertResourceResponse(204, NULL, $response);
    // Test POST: success, relationship already exists, with unique arity.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => [
        $target_identifier + [
          'meta' => [
            'arity' => 1,
          ],
        ],
      ],
    ]);
    $response = $this
      ->request('POST', $url, $request_options);
    $resource
      ->set($relationship_field_name, [
      $target_resource,
      $target_resource,
    ]);
    $expected_document = $this
      ->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
    $expected_document['data'][0] += [
      'meta' => [
        'arity' => 0,
      ],
    ];
    $expected_document['data'][1] += [
      'meta' => [
        'arity' => 1,
      ],
    ];
    // 200 with response body because the request did not include the
    // existing relationship resource identifier object.
    $this
      ->assertResourceResponse(200, $expected_document, $response);
    // @todo: Uncomment the following block in https://www.drupal.org/project/jsonapi/issues/2977659.
    // @codingStandardsIgnoreStart
    //// Test DELETE: two existing relationships, one removed.
    //$request_options[RequestOptions::BODY] = Json::encode(['data' => [
    //  $target_identifier + ['meta' => ['arity' => 0]],
    //]]);
    //$response = $this->request('DELETE', $url, $request_options);
    //// @todo Remove 3 lines below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2977653.
    //$resource->set($relationship_field_name, [$target_resource]);
    //$expected_document = $this->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
    //$this->assertResourceResponse(201, $expected_document, $response);
    //// $this->assertResourceResponse(204, NULL, $response);
    //$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()));
    // @codingStandardsIgnoreEnd
    // Test DELETE: one existing relationship, removed.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => [
        $target_identifier,
      ],
    ]);
    $response = $this
      ->request('DELETE', $url, $request_options);
    $resource
      ->set($relationship_field_name, []);
    $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()));
    // Test DELETE: no existing relationships, no op, success.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => [
        $target_identifier,
      ],
    ]);
    $response = $this
      ->request('DELETE', $url, $request_options);
    $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()));
    // Test PATCH: success, new value is different than existing value.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => [
        $target_identifier,
        $target_identifier,
      ],
    ]);
    $response = $this
      ->request('PATCH', $url, $request_options);
    $resource
      ->set($relationship_field_name, [
      $target_resource,
      $target_resource,
    ]);
    $expected_document = $this
      ->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
    $expected_document['data'][0] += [
      'meta' => [
        'arity' => 0,
      ],
    ];
    $expected_document['data'][1] += [
      'meta' => [
        'arity' => 1,
      ],
    ];
    $this
      ->assertResourceResponse(204, NULL, $response);
    // Test DELETE: two existing relationships, both removed because no arity
    // was specified.
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => [
        $target_identifier,
      ],
    ]);
    $response = $this
      ->request('DELETE', $url, $request_options);
    $resource
      ->set($relationship_field_name, []);
    $this
      ->assertResourceResponse(204, NULL, $response);
    $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()));
  }
  else {
    $request_options[RequestOptions::BODY] = Json::encode([
      'data' => [
        $target_identifier,
      ],
    ]);
    $response = $this
      ->request('POST', $url, $request_options);
    $message = 'The current user is not allowed to update this relationship.';
    $message .= ($reason = $update_access
      ->getReason()) ? ' ' . $reason : '';
    $this
      ->assertResourceErrorResponse(403, $message, $response, $relationship_field_name);
    $response = $this
      ->request('PATCH', $url, $request_options);
    $this
      ->assertResourceErrorResponse(403, $message, $response, $relationship_field_name);
    $response = $this
      ->request('DELETE', $url, $request_options);
    $this
      ->assertResourceErrorResponse(403, $message, $response, $relationship_field_name);
  }
  // Remove the test entities that were created.
  $resource
    ->delete();
  $target_resource
    ->delete();
}