Updated to Drupal 8.6.4, which is PHP 7.3 friendly. Also updated HTMLaw library....
[yaffs-website] / web / core / modules / content_moderation / tests / src / Kernel / ContentModerationStateTest.php
1 <?php
2
3 namespace Drupal\Tests\content_moderation\Kernel;
4
5 use Drupal\content_moderation\Entity\ContentModerationState;
6 use Drupal\Core\Entity\EntityInterface;
7 use Drupal\Core\Entity\EntityPublishedInterface;
8 use Drupal\Core\Entity\EntityStorageException;
9 use Drupal\Core\Language\LanguageInterface;
10 use Drupal\entity_test\Entity\EntityTestRev;
11 use Drupal\KernelTests\KernelTestBase;
12 use Drupal\language\Entity\ConfigurableLanguage;
13 use Drupal\node\Entity\Node;
14 use Drupal\node\Entity\NodeType;
15 use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
16 use Drupal\workflows\Entity\Workflow;
17
18 /**
19  * Tests links between a content entity and a content_moderation_state entity.
20  *
21  * @group content_moderation
22  */
23 class ContentModerationStateTest extends KernelTestBase {
24
25   use ContentModerationTestTrait;
26
27   /**
28    * {@inheritdoc}
29    */
30   public static $modules = [
31     'entity_test',
32     'node',
33     'block',
34     'block_content',
35     'media',
36     'media_test_source',
37     'image',
38     'file',
39     'field',
40     'content_moderation',
41     'user',
42     'system',
43     'language',
44     'content_translation',
45     'text',
46     'workflows',
47   ];
48
49   /**
50    * @var \Drupal\Core\Entity\EntityTypeManager
51    */
52   protected $entityTypeManager;
53
54   /**
55    * {@inheritdoc}
56    */
57   protected function setUp() {
58     parent::setUp();
59
60     $this->installSchema('node', 'node_access');
61     $this->installEntitySchema('node');
62     $this->installEntitySchema('user');
63     $this->installEntitySchema('entity_test_rev');
64     $this->installEntitySchema('entity_test_no_bundle');
65     $this->installEntitySchema('entity_test_mulrevpub');
66     $this->installEntitySchema('block_content');
67     $this->installEntitySchema('media');
68     $this->installEntitySchema('file');
69     $this->installEntitySchema('content_moderation_state');
70     $this->installConfig('content_moderation');
71     $this->installSchema('file', 'file_usage');
72     $this->installConfig(['field', 'system', 'image', 'file', 'media']);
73
74     $this->entityTypeManager = $this->container->get('entity_type.manager');
75   }
76
77   /**
78    * Tests basic monolingual content moderation through the API.
79    *
80    * @dataProvider basicModerationTestCases
81    */
82   public function testBasicModeration($entity_type_id) {
83     $entity = $this->createEntity($entity_type_id);
84     if ($entity instanceof EntityPublishedInterface) {
85       $entity->setUnpublished();
86     }
87     $entity->save();
88     $entity = $this->reloadEntity($entity);
89     $this->assertEquals('draft', $entity->moderation_state->value);
90
91     $entity->moderation_state->value = 'published';
92     $entity->save();
93
94     $entity = $this->reloadEntity($entity);
95     $this->assertEquals('published', $entity->moderation_state->value);
96
97     // Change the state without saving the node.
98     $content_moderation_state = ContentModerationState::load(1);
99     $content_moderation_state->set('moderation_state', 'draft');
100     $content_moderation_state->setNewRevision(TRUE);
101     $content_moderation_state->save();
102
103     $entity = $this->reloadEntity($entity, 3);
104     $this->assertEquals('draft', $entity->moderation_state->value);
105     if ($entity instanceof EntityPublishedInterface) {
106       $this->assertFalse($entity->isPublished());
107     }
108
109     // Get the default revision.
110     $entity = $this->reloadEntity($entity);
111     if ($entity instanceof EntityPublishedInterface) {
112       $this->assertTrue((bool) $entity->isPublished());
113     }
114     $this->assertEquals(2, $entity->getRevisionId());
115
116     $entity->moderation_state->value = 'published';
117     $entity->save();
118
119     $entity = $this->reloadEntity($entity, 4);
120     $this->assertEquals('published', $entity->moderation_state->value);
121
122     // Get the default revision.
123     $entity = $this->reloadEntity($entity);
124     if ($entity instanceof EntityPublishedInterface) {
125       $this->assertTrue((bool) $entity->isPublished());
126     }
127     $this->assertEquals(4, $entity->getRevisionId());
128
129     // Update the node to archived which will then be the default revision.
130     $entity->moderation_state->value = 'archived';
131     $entity->save();
132
133     // Revert to the previous (published) revision.
134     $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
135     $previous_revision = $entity_storage->loadRevision(4);
136     $previous_revision->isDefaultRevision(TRUE);
137     $previous_revision->setNewRevision(TRUE);
138     $previous_revision->save();
139
140     // Get the default revision.
141     $entity = $this->reloadEntity($entity);
142     $this->assertEquals('published', $entity->moderation_state->value);
143     if ($entity instanceof EntityPublishedInterface) {
144       $this->assertTrue($entity->isPublished());
145     }
146
147     // Set an invalid moderation state.
148     $this->setExpectedException(EntityStorageException::class);
149     $entity->moderation_state->value = 'foobar';
150     $entity->save();
151   }
152
153   /**
154    * Test cases for basic moderation test.
155    */
156   public function basicModerationTestCases() {
157     return [
158       'Nodes' => [
159         'node',
160       ],
161       'Block content' => [
162         'block_content',
163       ],
164       'Media' => [
165         'media',
166       ],
167       'Test entity - revisions, data table, and published interface' => [
168         'entity_test_mulrevpub',
169       ],
170       'Entity Test with revisions' => [
171         'entity_test_rev',
172       ],
173       'Entity without bundle' => [
174         'entity_test_no_bundle',
175       ],
176     ];
177   }
178
179   /**
180    * Tests removal of content moderation state entity.
181    *
182    * @dataProvider basicModerationTestCases
183    */
184   public function testContentModerationStateDataRemoval($entity_type_id) {
185     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
186     $entity = $this->createEntity($entity_type_id);
187     $entity->save();
188     $entity = $this->reloadEntity($entity);
189     $entity->delete();
190     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
191     $this->assertFalse($content_moderation_state);
192   }
193
194   /**
195    * Tests removal of content moderation state entity revisions.
196    *
197    * @dataProvider basicModerationTestCases
198    */
199   public function testContentModerationStateRevisionDataRemoval($entity_type_id) {
200     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
201     $entity = $this->createEntity($entity_type_id);
202     $entity->save();
203     $revision = clone $entity;
204     $revision->isDefaultRevision(FALSE);
205     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($revision);
206     $this->assertTrue($content_moderation_state);
207     $entity = $this->reloadEntity($entity);
208     $entity->setNewRevision(TRUE);
209     $entity->save();
210     $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
211     $entity_storage->deleteRevision($revision->getRevisionId());
212     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($revision);
213     $this->assertFalse($content_moderation_state);
214     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
215     $this->assertTrue($content_moderation_state);
216   }
217
218   /**
219    * Tests removal of content moderation state pending entity revisions.
220    *
221    * @dataProvider basicModerationTestCases
222    */
223   public function testContentModerationStatePendingRevisionDataRemoval($entity_type_id) {
224     $entity = $this->createEntity($entity_type_id);
225     $entity->moderation_state = 'published';
226     $entity->save();
227     $entity->setNewRevision(TRUE);
228     $entity->moderation_state = 'draft';
229     $entity->save();
230
231     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
232     $this->assertTrue($content_moderation_state);
233
234     $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
235     $entity_storage->deleteRevision($entity->getRevisionId());
236
237     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
238     $this->assertFalse($content_moderation_state);
239   }
240
241   /**
242    * Tests removal of content moderation state translations.
243    *
244    * @dataProvider basicModerationTestCases
245    */
246   public function testContentModerationStateTranslationDataRemoval($entity_type_id) {
247     // Test content moderation state translation deletion.
248     if ($this->entityTypeManager->getDefinition($entity_type_id)->isTranslatable()) {
249       /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
250       $entity = $this->createEntity($entity_type_id);
251       $langcode = 'it';
252       ConfigurableLanguage::createFromLangcode($langcode)
253         ->save();
254       $entity->save();
255       $translation = $entity->addTranslation($langcode, ['title' => 'Titolo test']);
256       // Make sure we add values for all of the required fields.
257       if ($entity_type_id == 'block_content') {
258         $translation->info = $this->randomString();
259       }
260       $translation->save();
261       $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
262       $this->assertTrue($content_moderation_state->hasTranslation($langcode));
263       $entity->removeTranslation($langcode);
264       $entity->save();
265       $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
266       $this->assertFalse($content_moderation_state->hasTranslation($langcode));
267     }
268   }
269
270   /**
271    * Tests basic multilingual content moderation through the API.
272    */
273   public function testMultilingualModeration() {
274     // Enable French.
275     ConfigurableLanguage::createFromLangcode('fr')->save();
276     $node_type = NodeType::create([
277       'type' => 'example',
278     ]);
279     $node_type->save();
280
281     $workflow = $this->createEditorialWorkflow();
282     $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
283     $workflow->save();
284
285     $english_node = Node::create([
286       'type' => 'example',
287       'title' => 'Test title',
288     ]);
289     // Revision 1 (en).
290     $english_node
291       ->setUnpublished()
292       ->save();
293     $this->assertEquals('draft', $english_node->moderation_state->value);
294     $this->assertFalse($english_node->isPublished());
295
296     // Create a French translation.
297     $french_node = $english_node->addTranslation('fr', ['title' => 'French title']);
298     $french_node->setUnpublished();
299     // Revision 1 (fr).
300     $french_node->save();
301     $french_node = $this->reloadEntity($english_node)->getTranslation('fr');
302     $this->assertEquals('draft', $french_node->moderation_state->value);
303     $this->assertFalse($french_node->isPublished());
304
305     // Move English node to create another draft.
306     $english_node = $this->reloadEntity($english_node);
307     $english_node->moderation_state->value = 'draft';
308     // Revision 2 (en, fr).
309     $english_node->save();
310     $english_node = $this->reloadEntity($english_node);
311     $this->assertEquals('draft', $english_node->moderation_state->value);
312
313     // French node should still be in draft.
314     $french_node = $this->reloadEntity($english_node)->getTranslation('fr');
315     $this->assertEquals('draft', $french_node->moderation_state->value);
316
317     // Publish the French node.
318     $french_node->moderation_state->value = 'published';
319     // Revision 3 (en, fr).
320     $french_node->save();
321     $french_node = $this->reloadEntity($french_node)->getTranslation('fr');
322     $this->assertTrue($french_node->isPublished());
323     $this->assertEquals('published', $french_node->moderation_state->value);
324     $this->assertTrue($french_node->isPublished());
325     $english_node = $french_node->getTranslation('en');
326     $this->assertEquals('draft', $english_node->moderation_state->value);
327
328     // Publish the English node.
329     $english_node->moderation_state->value = 'published';
330     // Revision 4 (en, fr).
331     $english_node->save();
332     $english_node = $this->reloadEntity($english_node);
333     $this->assertTrue($english_node->isPublished());
334
335     // Move the French node back to draft.
336     $french_node = $this->reloadEntity($english_node)->getTranslation('fr');
337     $this->assertTrue($french_node->isPublished());
338     $french_node->moderation_state->value = 'draft';
339     // Revision 5 (en, fr).
340     $french_node->save();
341     $french_node = $this->reloadEntity($english_node, 5)->getTranslation('fr');
342     $this->assertFalse($french_node->isPublished());
343     $this->assertTrue($french_node->getTranslation('en')->isPublished());
344
345     // Republish the French node.
346     $french_node->moderation_state->value = 'published';
347     // Revision 6 (en, fr).
348     $french_node->save();
349     $french_node = $this->reloadEntity($english_node)->getTranslation('fr');
350     $this->assertTrue($french_node->isPublished());
351
352     // Change the EN state without saving the node.
353     $content_moderation_state = ContentModerationState::load(1);
354     $content_moderation_state->set('moderation_state', 'draft');
355     $content_moderation_state->setNewRevision(TRUE);
356     // Revision 7 (en, fr).
357     $content_moderation_state->save();
358     $english_node = $this->reloadEntity($french_node, $french_node->getRevisionId() + 1);
359
360     $this->assertEquals('draft', $english_node->moderation_state->value);
361     $french_node = $this->reloadEntity($english_node)->getTranslation('fr');
362     $this->assertEquals('published', $french_node->moderation_state->value);
363
364     // This should unpublish the French node.
365     $content_moderation_state = ContentModerationState::load(1);
366     $content_moderation_state = $content_moderation_state->getTranslation('fr');
367     $content_moderation_state->set('moderation_state', 'draft');
368     $content_moderation_state->setNewRevision(TRUE);
369     // Revision 8 (en, fr).
370     $content_moderation_state->save();
371
372     $english_node = $this->reloadEntity($english_node, $english_node->getRevisionId());
373     $this->assertEquals('draft', $english_node->moderation_state->value);
374     $french_node = $this->reloadEntity($english_node, '8')->getTranslation('fr');
375     $this->assertEquals('draft', $french_node->moderation_state->value);
376     // Switching the moderation state to an unpublished state should update the
377     // entity.
378     $this->assertFalse($french_node->isPublished());
379
380     // Get the default english node.
381     $english_node = $this->reloadEntity($english_node);
382     $this->assertTrue($english_node->isPublished());
383     $this->assertEquals(6, $english_node->getRevisionId());
384   }
385
386   /**
387    * Tests moderation when the moderation_state field has a config override.
388    */
389   public function testModerationWithFieldConfigOverride() {
390     NodeType::create([
391       'type' => 'test_type',
392     ])->save();
393
394     $workflow = $this->createEditorialWorkflow();
395     $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'test_type');
396     $workflow->save();
397
398     $fields = $this->container->get('entity_field.manager')->getFieldDefinitions('node', 'test_type');
399     $field_config = $fields['moderation_state']->getConfig('test_type');
400     $field_config->setLabel('Field Override!');
401     $field_config->save();
402
403     $node = Node::create([
404       'title' => 'Test node',
405       'type' => 'test_type',
406     ]);
407     $node->save();
408     $this->assertFalse($node->isPublished());
409     $this->assertEquals('draft', $node->moderation_state->value);
410
411     $node->moderation_state = 'published';
412     $node->save();
413     $this->assertTrue($node->isPublished());
414     $this->assertEquals('published', $node->moderation_state->value);
415   }
416
417   /**
418    * Tests that entities with special languages can be moderated.
419    */
420   public function testModerationWithSpecialLanguages() {
421     $workflow = $this->createEditorialWorkflow();
422     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
423     $workflow->save();
424
425     // Create a test entity.
426     $entity = EntityTestRev::create([
427       'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
428     ]);
429     $entity->save();
430     $this->assertEquals('draft', $entity->moderation_state->value);
431
432     $entity->moderation_state->value = 'published';
433     $entity->save();
434
435     $this->assertEquals('published', EntityTestRev::load($entity->id())->moderation_state->value);
436   }
437
438   /**
439    * Tests that a non-translatable entity type with a langcode can be moderated.
440    */
441   public function testNonTranslatableEntityTypeModeration() {
442     $workflow = $this->createEditorialWorkflow();
443     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
444     $workflow->save();
445
446     // Check that the tested entity type is not translatable.
447     $entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_rev');
448     $this->assertFalse($entity_type->isTranslatable(), 'The test entity type is not translatable.');
449
450     // Create a test entity.
451     $entity = EntityTestRev::create();
452     $entity->save();
453     $this->assertEquals('draft', $entity->moderation_state->value);
454
455     $entity->moderation_state->value = 'published';
456     $entity->save();
457
458     $this->assertEquals('published', EntityTestRev::load($entity->id())->moderation_state->value);
459   }
460
461   /**
462    * Tests that a non-translatable entity type without a langcode can be
463    * moderated.
464    */
465   public function testNonLangcodeEntityTypeModeration() {
466     // Unset the langcode entity key for 'entity_test_rev'.
467     $entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_rev');
468     $keys = $entity_type->getKeys();
469     unset($keys['langcode']);
470     $entity_type->set('entity_keys', $keys);
471     \Drupal::state()->set('entity_test_rev.entity_type', $entity_type);
472
473     // Update the entity type in order to remove the 'langcode' field.
474     \Drupal::entityDefinitionUpdateManager()->applyUpdates();
475
476     $workflow = $this->createEditorialWorkflow();
477     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
478     $workflow->save();
479
480     // Check that the tested entity type is not translatable and does not have a
481     // 'langcode' entity key.
482     $entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_rev');
483     $this->assertFalse($entity_type->isTranslatable(), 'The test entity type is not translatable.');
484     $this->assertFalse($entity_type->getKey('langcode'), "The test entity type does not have a 'langcode' entity key.");
485
486     // Create a test entity.
487     $entity = EntityTestRev::create();
488     $entity->save();
489     $this->assertEquals('draft', $entity->moderation_state->value);
490
491     $entity->moderation_state->value = 'published';
492     $entity->save();
493
494     $this->assertEquals('published', EntityTestRev::load($entity->id())->moderation_state->value);
495   }
496
497   /**
498    * Tests the dependencies of the workflow when using content moderation.
499    */
500   public function testWorkflowDependencies() {
501     $node_type = NodeType::create([
502       'type' => 'example',
503     ]);
504     $node_type->save();
505
506     $workflow = $this->createEditorialWorkflow();
507     // Test both a config and non-config based bundle and entity type.
508     $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
509     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
510     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_no_bundle', 'entity_test_no_bundle');
511     $workflow->save();
512
513     $this->assertEquals([
514       'module' => [
515         'content_moderation',
516         'entity_test',
517       ],
518       'config' => [
519         'node.type.example',
520       ],
521     ], $workflow->getDependencies());
522
523     $this->assertEquals([
524       'entity_test_no_bundle',
525       'entity_test_rev',
526       'node',
527     ], $workflow->getTypePlugin()->getEntityTypes());
528
529     // Delete the node type and ensure it is removed from the workflow.
530     $node_type->delete();
531     $workflow = Workflow::load('editorial');
532     $entity_types = $workflow->getTypePlugin()->getEntityTypes();
533     $this->assertFalse(in_array('node', $entity_types));
534
535     // Uninstall entity test and ensure it's removed from the workflow.
536     $this->container->get('config.manager')->uninstall('module', 'entity_test');
537     $workflow = Workflow::load('editorial');
538     $entity_types = $workflow->getTypePlugin()->getEntityTypes();
539     $this->assertEquals([], $entity_types);
540   }
541
542   /**
543    * Test the content moderation workflow dependencies for non-config bundles.
544    */
545   public function testWorkflowNonConfigBundleDependencies() {
546     // Create a bundle not based on any particular configuration.
547     entity_test_create_bundle('test_bundle');
548
549     $workflow = $this->createEditorialWorkflow();
550     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test', 'test_bundle');
551     $workflow->save();
552
553     // Ensure the bundle is correctly added to the workflow.
554     $this->assertEquals([
555       'module' => [
556         'content_moderation',
557         'entity_test',
558       ],
559     ], $workflow->getDependencies());
560     $this->assertEquals([
561       'test_bundle',
562     ], $workflow->getTypePlugin()->getBundlesForEntityType('entity_test'));
563
564     // Delete the test bundle to ensure the workflow entity responds
565     // appropriately.
566     entity_test_delete_bundle('test_bundle');
567
568     $workflow = Workflow::load('editorial');
569     $this->assertEquals([], $workflow->getTypePlugin()->getBundlesForEntityType('entity_test'));
570     $this->assertEquals([
571       'module' => [
572         'content_moderation',
573       ],
574     ], $workflow->getDependencies());
575   }
576
577   /**
578    * Test the revision default state of the moderation state entity revisions.
579    *
580    * @param string $entity_type_id
581    *   The ID of entity type to be tested.
582    *
583    * @dataProvider basicModerationTestCases
584    */
585   public function testRevisionDefaultState($entity_type_id) {
586     // Check that the revision default state of the moderated entity and the
587     // content moderation state entity always match.
588     /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
589     $storage = $this->entityTypeManager->getStorage($entity_type_id);
590     /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $cms_storage */
591     $cms_storage = $this->entityTypeManager->getStorage('content_moderation_state');
592
593     $entity = $this->createEntity($entity_type_id);
594     $entity->get('moderation_state')->value = 'published';
595     $storage->save($entity);
596     /** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
597     $cms_entity = $cms_storage->loadUnchanged(1);
598     $this->assertEquals($entity->getLoadedRevisionId(), $cms_entity->get('content_entity_revision_id')->value);
599
600     $entity->get('moderation_state')->value = 'published';
601     $storage->save($entity);
602     /** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
603     $cms_entity = $cms_storage->loadUnchanged(1);
604     $this->assertEquals($entity->getLoadedRevisionId(), $cms_entity->get('content_entity_revision_id')->value);
605
606     $entity->get('moderation_state')->value = 'draft';
607     $storage->save($entity);
608     /** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
609     $cms_entity = $cms_storage->loadUnchanged(1);
610     $this->assertEquals($entity->getLoadedRevisionId() - 1, $cms_entity->get('content_entity_revision_id')->value);
611
612     $entity->get('moderation_state')->value = 'published';
613     $storage->save($entity);
614     /** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
615     $cms_entity = $cms_storage->loadUnchanged(1);
616     $this->assertEquals($entity->getLoadedRevisionId(), $cms_entity->get('content_entity_revision_id')->value);
617   }
618
619   /**
620    * Creates an entity.
621    *
622    * The entity will have required fields populated and the corresponding bundle
623    * will be enabled for content moderation.
624    *
625    * @param string $entity_type_id
626    *   The entity type ID.
627    *
628    * @return \Drupal\Core\Entity\ContentEntityInterface
629    *   The created entity.
630    */
631   protected function createEntity($entity_type_id) {
632     $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
633
634     $bundle_id = $entity_type_id;
635     // Set up a bundle entity type for the specified entity type, if needed.
636     if ($bundle_entity_type_id = $entity_type->getBundleEntityType()) {
637       $bundle_entity_type = $this->entityTypeManager->getDefinition($bundle_entity_type_id);
638       $bundle_entity_storage = $this->entityTypeManager->getStorage($bundle_entity_type_id);
639
640       $bundle_id = 'example';
641       if (!$bundle_entity_storage->load($bundle_id)) {
642         $bundle_entity = $bundle_entity_storage->create([
643           $bundle_entity_type->getKey('id') => 'example',
644         ]);
645         if ($entity_type_id == 'media') {
646           $bundle_entity->set('source', 'test');
647           $bundle_entity->save();
648           $source_field = $bundle_entity->getSource()->createSourceField($bundle_entity);
649           $source_field->getFieldStorageDefinition()->save();
650           $source_field->save();
651           $bundle_entity->set('source_configuration', [
652             'source_field' => $source_field->getName(),
653           ]);
654         }
655         $bundle_entity->save();
656       }
657     }
658
659     $workflow = $this->createEditorialWorkflow();
660     $workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle_id);
661     $workflow->save();
662
663     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
664     $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
665     $entity = $entity_storage->create([
666       $entity_type->getKey('label') => 'Test title',
667       $entity_type->getKey('bundle') => $bundle_id,
668     ]);
669     // Make sure we add values for all of the required fields.
670     if ($entity_type_id == 'block_content') {
671       $entity->info = $this->randomString();
672     }
673     return $entity;
674   }
675
676   /**
677    * Reloads the entity after clearing the static cache.
678    *
679    * @param \Drupal\Core\Entity\EntityInterface $entity
680    *   The entity to reload.
681    * @param int|bool $revision_id
682    *   The specific revision ID to load. Defaults FALSE and just loads the
683    *   default revision.
684    *
685    * @return \Drupal\Core\Entity\EntityInterface
686    *   The reloaded entity.
687    */
688   protected function reloadEntity(EntityInterface $entity, $revision_id = FALSE) {
689     $storage = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId());
690     $storage->resetCache([$entity->id()]);
691     if ($revision_id) {
692       return $storage->loadRevision($revision_id);
693     }
694     return $storage->load($entity->id());
695   }
696
697 }