annotate core/modules/jsonapi/tests/src/Functional/JsonApiFunctionalTestBase.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@18 1 <?php
Chris@18 2
Chris@18 3 namespace Drupal\Tests\jsonapi\Functional;
Chris@18 4
Chris@18 5 use Drupal\Core\Field\FieldStorageDefinitionInterface;
Chris@18 6 use Drupal\Core\Url;
Chris@18 7 use Drupal\field\Entity\FieldConfig;
Chris@18 8 use Drupal\field\Entity\FieldStorageConfig;
Chris@18 9 use Drupal\file\Entity\File;
Chris@18 10 use Drupal\taxonomy\Entity\Term;
Chris@18 11 use Drupal\taxonomy\Entity\Vocabulary;
Chris@18 12 use Drupal\Tests\BrowserTestBase;
Chris@18 13 use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
Chris@18 14 use Drupal\Tests\image\Kernel\ImageFieldCreationTrait;
Chris@18 15 use Drupal\user\Entity\Role;
Chris@18 16 use Drupal\user\RoleInterface;
Chris@18 17 use GuzzleHttp\Exception\ClientException;
Chris@18 18 use GuzzleHttp\Exception\ServerException;
Chris@18 19
Chris@18 20 /**
Chris@18 21 * Provides helper methods for the JSON:API module's functional tests.
Chris@18 22 *
Chris@18 23 * @internal
Chris@18 24 */
Chris@18 25 abstract class JsonApiFunctionalTestBase extends BrowserTestBase {
Chris@18 26
Chris@18 27 use EntityReferenceTestTrait;
Chris@18 28 use ImageFieldCreationTrait;
Chris@18 29
Chris@18 30 const IS_MULTILINGUAL = TRUE;
Chris@18 31 const IS_NOT_MULTILINGUAL = FALSE;
Chris@18 32
Chris@18 33 /**
Chris@18 34 * {@inheritdoc}
Chris@18 35 */
Chris@18 36 public static $modules = [
Chris@18 37 'jsonapi',
Chris@18 38 'serialization',
Chris@18 39 'node',
Chris@18 40 'image',
Chris@18 41 'taxonomy',
Chris@18 42 'link',
Chris@18 43 ];
Chris@18 44
Chris@18 45 /**
Chris@18 46 * Test user.
Chris@18 47 *
Chris@18 48 * @var \Drupal\user\Entity\User
Chris@18 49 */
Chris@18 50 protected $user;
Chris@18 51
Chris@18 52 /**
Chris@18 53 * Test user with access to view profiles.
Chris@18 54 *
Chris@18 55 * @var \Drupal\user\Entity\User
Chris@18 56 */
Chris@18 57 protected $userCanViewProfiles;
Chris@18 58
Chris@18 59 /**
Chris@18 60 * Test nodes.
Chris@18 61 *
Chris@18 62 * @var \Drupal\node\Entity\Node[]
Chris@18 63 */
Chris@18 64 protected $nodes = [];
Chris@18 65
Chris@18 66 /**
Chris@18 67 * Test taxonomy terms.
Chris@18 68 *
Chris@18 69 * @var \Drupal\taxonomy\Entity\Term[]
Chris@18 70 */
Chris@18 71 protected $tags = [];
Chris@18 72
Chris@18 73 /**
Chris@18 74 * Test files.
Chris@18 75 *
Chris@18 76 * @var \Drupal\file\Entity\File[]
Chris@18 77 */
Chris@18 78 protected $files = [];
Chris@18 79
Chris@18 80 /**
Chris@18 81 * The HTTP client.
Chris@18 82 *
Chris@18 83 * @var \GuzzleHttp\ClientInterface
Chris@18 84 */
Chris@18 85 protected $httpClient;
Chris@18 86
Chris@18 87 /**
Chris@18 88 * {@inheritdoc}
Chris@18 89 */
Chris@18 90 protected function setUp() {
Chris@18 91 parent::setUp();
Chris@18 92
Chris@18 93 // Set up a HTTP client that accepts relative URLs.
Chris@18 94 $this->httpClient = $this->container->get('http_client_factory')
Chris@18 95 ->fromOptions(['base_uri' => $this->baseUrl]);
Chris@18 96
Chris@18 97 // Create Basic page and Article node types.
Chris@18 98 if ($this->profile != 'standard') {
Chris@18 99 $this->drupalCreateContentType([
Chris@18 100 'type' => 'article',
Chris@18 101 'name' => 'Article',
Chris@18 102 ]);
Chris@18 103
Chris@18 104 // Setup vocabulary.
Chris@18 105 Vocabulary::create([
Chris@18 106 'vid' => 'tags',
Chris@18 107 'name' => 'Tags',
Chris@18 108 ])->save();
Chris@18 109
Chris@18 110 // Add tags and field_image to the article.
Chris@18 111 $this->createEntityReferenceField(
Chris@18 112 'node',
Chris@18 113 'article',
Chris@18 114 'field_tags',
Chris@18 115 'Tags',
Chris@18 116 'taxonomy_term',
Chris@18 117 'default',
Chris@18 118 [
Chris@18 119 'target_bundles' => [
Chris@18 120 'tags' => 'tags',
Chris@18 121 ],
Chris@18 122 'auto_create' => TRUE,
Chris@18 123 ],
Chris@18 124 FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED
Chris@18 125 );
Chris@18 126 $this->createImageField('field_image', 'article');
Chris@18 127 $this->createImageField('field_heroless', 'article');
Chris@18 128 }
Chris@18 129
Chris@18 130 FieldStorageConfig::create([
Chris@18 131 'field_name' => 'field_link',
Chris@18 132 'entity_type' => 'node',
Chris@18 133 'type' => 'link',
Chris@18 134 'settings' => [],
Chris@18 135 'cardinality' => 1,
Chris@18 136 ])->save();
Chris@18 137
Chris@18 138 $field_config = FieldConfig::create([
Chris@18 139 'field_name' => 'field_link',
Chris@18 140 'label' => 'Link',
Chris@18 141 'entity_type' => 'node',
Chris@18 142 'bundle' => 'article',
Chris@18 143 'required' => FALSE,
Chris@18 144 'settings' => [],
Chris@18 145 'description' => '',
Chris@18 146 ]);
Chris@18 147 $field_config->save();
Chris@18 148
Chris@18 149 // Field for testing sorting.
Chris@18 150 FieldStorageConfig::create([
Chris@18 151 'field_name' => 'field_sort1',
Chris@18 152 'entity_type' => 'node',
Chris@18 153 'type' => 'integer',
Chris@18 154 ])->save();
Chris@18 155 FieldConfig::create([
Chris@18 156 'field_name' => 'field_sort1',
Chris@18 157 'entity_type' => 'node',
Chris@18 158 'bundle' => 'article',
Chris@18 159 ])->save();
Chris@18 160
Chris@18 161 // Another field for testing sorting.
Chris@18 162 FieldStorageConfig::create([
Chris@18 163 'field_name' => 'field_sort2',
Chris@18 164 'entity_type' => 'node',
Chris@18 165 'type' => 'integer',
Chris@18 166 ])->save();
Chris@18 167 FieldConfig::create([
Chris@18 168 'field_name' => 'field_sort2',
Chris@18 169 'entity_type' => 'node',
Chris@18 170 'bundle' => 'article',
Chris@18 171 ])->save();
Chris@18 172
Chris@18 173 $this->user = $this->drupalCreateUser([
Chris@18 174 'create article content',
Chris@18 175 'edit any article content',
Chris@18 176 'delete any article content',
Chris@18 177 ]);
Chris@18 178
Chris@18 179 // Create a user that can.
Chris@18 180 $this->userCanViewProfiles = $this->drupalCreateUser([
Chris@18 181 'access user profiles',
Chris@18 182 ]);
Chris@18 183
Chris@18 184 $this->grantPermissions(Role::load(RoleInterface::ANONYMOUS_ID), [
Chris@18 185 'access user profiles',
Chris@18 186 'administer taxonomy',
Chris@18 187 ]);
Chris@18 188
Chris@18 189 drupal_flush_all_caches();
Chris@18 190 }
Chris@18 191
Chris@18 192 /**
Chris@18 193 * Performs a HTTP request. Wraps the Guzzle HTTP client.
Chris@18 194 *
Chris@18 195 * Why wrap the Guzzle HTTP client? Because any error response is returned via
Chris@18 196 * an exception, which would make the tests unnecessarily complex to read.
Chris@18 197 *
Chris@18 198 * @param string $method
Chris@18 199 * HTTP method.
Chris@18 200 * @param \Drupal\Core\Url $url
Chris@18 201 * URL to request.
Chris@18 202 * @param array $request_options
Chris@18 203 * Request options to apply.
Chris@18 204 *
Chris@18 205 * @return \Psr\Http\Message\ResponseInterface
Chris@18 206 * The request response.
Chris@18 207 *
Chris@18 208 * @throws \GuzzleHttp\Exception\GuzzleException
Chris@18 209 *
Chris@18 210 * @see \GuzzleHttp\ClientInterface::request
Chris@18 211 */
Chris@18 212 protected function request($method, Url $url, array $request_options) {
Chris@18 213 try {
Chris@18 214 $response = $this->httpClient->request($method, $url->toString(), $request_options);
Chris@18 215 }
Chris@18 216 catch (ClientException $e) {
Chris@18 217 $response = $e->getResponse();
Chris@18 218 }
Chris@18 219 catch (ServerException $e) {
Chris@18 220 $response = $e->getResponse();
Chris@18 221 }
Chris@18 222
Chris@18 223 return $response;
Chris@18 224 }
Chris@18 225
Chris@18 226 /**
Chris@18 227 * Creates default content to test the API.
Chris@18 228 *
Chris@18 229 * @param int $num_articles
Chris@18 230 * Number of articles to create.
Chris@18 231 * @param int $num_tags
Chris@18 232 * Number of tags to create.
Chris@18 233 * @param bool $article_has_image
Chris@18 234 * Set to TRUE if you want to add an image to the generated articles.
Chris@18 235 * @param bool $article_has_link
Chris@18 236 * Set to TRUE if you want to add a link to the generated articles.
Chris@18 237 * @param bool $is_multilingual
Chris@18 238 * (optional) Set to TRUE if you want to enable multilingual content.
Chris@18 239 * @param bool $referencing_twice
Chris@18 240 * (optional) Set to TRUE if you want articles to reference the same tag
Chris@18 241 * twice.
Chris@18 242 */
Chris@18 243 protected function createDefaultContent($num_articles, $num_tags, $article_has_image, $article_has_link, $is_multilingual, $referencing_twice = FALSE) {
Chris@18 244 $random = $this->getRandomGenerator();
Chris@18 245 for ($created_tags = 0; $created_tags < $num_tags; $created_tags++) {
Chris@18 246 $term = Term::create([
Chris@18 247 'vid' => 'tags',
Chris@18 248 'name' => $random->name(),
Chris@18 249 ]);
Chris@18 250
Chris@18 251 if ($is_multilingual) {
Chris@18 252 $term->addTranslation('ca', ['name' => $term->getName() . ' (ca)']);
Chris@18 253 }
Chris@18 254
Chris@18 255 $term->save();
Chris@18 256 $this->tags[] = $term;
Chris@18 257 }
Chris@18 258 for ($created_nodes = 0; $created_nodes < $num_articles; $created_nodes++) {
Chris@18 259 $values = [
Chris@18 260 'uid' => ['target_id' => $this->user->id()],
Chris@18 261 'type' => 'article',
Chris@18 262 ];
Chris@18 263
Chris@18 264 if ($referencing_twice) {
Chris@18 265 $values['field_tags'] = [
Chris@18 266 ['target_id' => 1],
Chris@18 267 ['target_id' => 1],
Chris@18 268 ];
Chris@18 269 }
Chris@18 270 else {
Chris@18 271 // Get N random tags.
Chris@18 272 $selected_tags = mt_rand(1, $num_tags);
Chris@18 273 $tags = [];
Chris@18 274 while (count($tags) < $selected_tags) {
Chris@18 275 $tags[] = mt_rand(1, $num_tags);
Chris@18 276 $tags = array_unique($tags);
Chris@18 277 }
Chris@18 278 $values['field_tags'] = array_map(function ($tag) {
Chris@18 279 return ['target_id' => $tag];
Chris@18 280 }, $tags);
Chris@18 281 }
Chris@18 282 if ($article_has_image) {
Chris@18 283 $file = File::create([
Chris@18 284 'uri' => 'vfs://' . $random->name() . '.png',
Chris@18 285 ]);
Chris@18 286 $file->setPermanent();
Chris@18 287 $file->save();
Chris@18 288 $this->files[] = $file;
Chris@18 289 $values['field_image'] = ['target_id' => $file->id(), 'alt' => 'alt text'];
Chris@18 290 }
Chris@18 291 if ($article_has_link) {
Chris@18 292 $values['field_link'] = [
Chris@18 293 'title' => $this->getRandomGenerator()->name(),
Chris@18 294 'uri' => sprintf(
Chris@18 295 '%s://%s.%s',
Chris@18 296 'http' . (mt_rand(0, 2) > 1 ? '' : 's'),
Chris@18 297 $this->getRandomGenerator()->name(),
Chris@18 298 'org'
Chris@18 299 ),
Chris@18 300 ];
Chris@18 301 }
Chris@18 302
Chris@18 303 // Create values for the sort fields, to allow for testing complex
Chris@18 304 // sorting:
Chris@18 305 // - field_sort1 increments every 5 articles, starting at zero
Chris@18 306 // - field_sort2 decreases every article, ending at zero.
Chris@18 307 $values['field_sort1'] = ['value' => floor($created_nodes / 5)];
Chris@18 308 $values['field_sort2'] = ['value' => $num_articles - $created_nodes];
Chris@18 309
Chris@18 310 $node = $this->createNode($values);
Chris@18 311
Chris@18 312 if ($is_multilingual === static::IS_MULTILINGUAL) {
Chris@18 313 $values['title'] = $node->getTitle() . ' (ca)';
Chris@18 314 $values['field_image']['alt'] = 'alt text (ca)';
Chris@18 315 $node->addTranslation('ca', $values);
Chris@18 316 }
Chris@18 317 $node->save();
Chris@18 318
Chris@18 319 $this->nodes[] = $node;
Chris@18 320 }
Chris@18 321 if ($article_has_link) {
Chris@18 322 // Make sure that there is at least 1 https link for ::testRead() #19.
Chris@18 323 $this->nodes[0]->field_link = [
Chris@18 324 'title' => 'Drupal',
Chris@18 325 'uri' => 'https://drupal.org',
Chris@18 326 ];
Chris@18 327 $this->nodes[0]->save();
Chris@18 328 }
Chris@18 329 }
Chris@18 330
Chris@18 331 }