Pull merge.
[yaffs-website] / web / core / modules / content_moderation / tests / src / Kernel / ModerationStateFieldItemListTest.php
1 <?php
2
3 namespace Drupal\Tests\content_moderation\Kernel;
4
5 use Drupal\KernelTests\KernelTestBase;
6 use Drupal\language\Entity\ConfigurableLanguage;
7 use Drupal\node\Entity\Node;
8 use Drupal\node\Entity\NodeType;
9 use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
10 use Drupal\workflows\Entity\Workflow;
11
12 /**
13  * @coversDefaultClass \Drupal\content_moderation\Plugin\Field\ModerationStateFieldItemList
14  *
15  * @group content_moderation
16  */
17 class ModerationStateFieldItemListTest extends KernelTestBase {
18
19   use ContentModerationTestTrait;
20
21   /**
22    * {@inheritdoc}
23    */
24   public static $modules = [
25     'node',
26     'content_moderation',
27     'user',
28     'system',
29     'language',
30     'workflows',
31   ];
32
33   /**
34    * @var \Drupal\node\NodeInterface
35    */
36   protected $testNode;
37
38   /**
39    * {@inheritdoc}
40    */
41   protected function setUp() {
42     parent::setUp();
43
44     $this->installSchema('node', 'node_access');
45     $this->installEntitySchema('node');
46     $this->installEntitySchema('user');
47     $this->installEntitySchema('content_moderation_state');
48     $this->installConfig('content_moderation');
49
50     NodeType::create([
51       'type' => 'unmoderated',
52     ])->save();
53
54     $node_type = NodeType::create([
55       'type' => 'example',
56     ]);
57     $node_type->save();
58     $workflow = $this->createEditorialWorkflow();
59     $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
60     $workflow->save();
61
62     $this->testNode = Node::create([
63       'type' => 'example',
64       'title' => 'Test title',
65     ]);
66     $this->testNode->save();
67     \Drupal::entityTypeManager()->getStorage('node')->resetCache();
68     $this->testNode = Node::load($this->testNode->id());
69
70     ConfigurableLanguage::createFromLangcode('de')->save();
71   }
72
73   /**
74    * Test the field item list when accessing an index.
75    */
76   public function testArrayIndex() {
77     $this->assertFalse($this->testNode->isPublished());
78     $this->assertEquals('draft', $this->testNode->moderation_state[0]->value);
79   }
80
81   /**
82    * Test the field item list when iterating.
83    */
84   public function testArrayIteration() {
85     $states = [];
86     foreach ($this->testNode->moderation_state as $item) {
87       $states[] = $item->value;
88     }
89     $this->assertEquals(['draft'], $states);
90   }
91
92   /**
93    * @covers ::getValue
94    */
95   public function testGetValue() {
96     $this->assertEquals([['value' => 'draft']], $this->testNode->moderation_state->getValue());
97   }
98
99   /**
100    * @covers ::get
101    */
102   public function testGet() {
103     $this->assertEquals('draft', $this->testNode->moderation_state->get(0)->value);
104     $this->setExpectedException(\InvalidArgumentException::class);
105     $this->testNode->moderation_state->get(2);
106   }
107
108   /**
109    * Tests the item list when it is emptied and appended to.
110    */
111   public function testEmptyStateAndAppend() {
112     // This test case mimics the lifecycle of an entity that is being patched in
113     // a rest resource.
114     $this->testNode->moderation_state->setValue([]);
115     $this->assertTrue($this->testNode->moderation_state->isEmpty());
116     $this->assertEmptiedModerationFieldItemList();
117
118     $this->testNode->moderation_state->appendItem();
119     $this->assertEquals(1, $this->testNode->moderation_state->count());
120     $this->assertEquals(NULL, $this->testNode->moderation_state->value);
121     $this->assertEmptiedModerationFieldItemList();
122   }
123
124   /**
125    * Test an empty value assigned to the field item.
126    */
127   public function testEmptyFieldItem() {
128     $this->testNode->moderation_state->value = '';
129     $this->assertEquals('', $this->testNode->moderation_state->value);
130     $this->assertEmptiedModerationFieldItemList();
131   }
132
133   /**
134    * Test an empty value assigned to the field item list.
135    */
136   public function testEmptyFieldItemList() {
137     $this->testNode->moderation_state = '';
138     $this->assertEquals('', $this->testNode->moderation_state->value);
139     $this->assertEmptiedModerationFieldItemList();
140   }
141
142   /**
143    * Test the field item when it is unset.
144    */
145   public function testUnsetItemList() {
146     unset($this->testNode->moderation_state);
147     $this->assertEquals(NULL, $this->testNode->moderation_state->value);
148     $this->assertEmptiedModerationFieldItemList();
149   }
150
151   /**
152    * Test the field item when it is assigned NULL.
153    */
154   public function testAssignNullItemList() {
155     $this->testNode->moderation_state = NULL;
156     $this->assertEquals(NULL, $this->testNode->moderation_state->value);
157     $this->assertEmptiedModerationFieldItemList();
158   }
159
160   /**
161    * Assert the set of expectations when the moderation state field is emptied.
162    */
163   protected function assertEmptiedModerationFieldItemList() {
164     $this->assertTrue($this->testNode->moderation_state->isEmpty());
165     // Test the empty value causes a violation in the entity.
166     $violations = $this->testNode->validate();
167     $this->assertCount(1, $violations);
168     $this->assertEquals('This value should not be null.', $violations->get(0)->getMessage());
169     // Test that incorrectly saving the entity regardless will not produce a
170     // change in the moderation state.
171     $this->testNode->save();
172     $this->assertEquals('draft', Node::load($this->testNode->id())->moderation_state->value);
173   }
174
175   /**
176    * Test the list class with a non moderated entity.
177    */
178   public function testNonModeratedEntity() {
179     $unmoderated_node = Node::create([
180       'type' => 'unmoderated',
181       'title' => 'Test title',
182     ]);
183     $unmoderated_node->save();
184     $this->assertEquals(0, $unmoderated_node->moderation_state->count());
185
186     $unmoderated_node->moderation_state = NULL;
187     $this->assertEquals(0, $unmoderated_node->moderation_state->count());
188     $this->assertCount(0, $unmoderated_node->validate());
189   }
190
191   /**
192    * Tests that moderation state changes also change the related entity state.
193    *
194    * @dataProvider moderationStateChangesTestCases
195    */
196   public function testModerationStateChanges($initial_state, $final_state, $first_published, $first_is_default, $second_published, $second_is_default) {
197     $this->testNode->moderation_state->value = $initial_state;
198     $this->assertEquals($first_published, $this->testNode->isPublished());
199     $this->assertEquals($first_is_default, $this->testNode->isDefaultRevision());
200     $this->testNode->save();
201
202     $this->testNode->moderation_state->value = $final_state;
203     $this->assertEquals($second_published, $this->testNode->isPublished());
204     $this->assertEquals($second_is_default, $this->testNode->isDefaultRevision());
205   }
206
207   /**
208    * Data provider for ::testModerationStateChanges
209    */
210   public function moderationStateChangesTestCases() {
211     return [
212       'Draft to draft' => [
213         'draft',
214         'draft',
215         FALSE,
216         TRUE,
217         FALSE,
218         TRUE,
219       ],
220       'Draft to published' => [
221         'draft',
222         'published',
223         FALSE,
224         TRUE,
225         TRUE,
226         TRUE,
227       ],
228       'Published to published' => [
229         'published',
230         'published',
231         TRUE,
232         TRUE,
233         TRUE,
234         TRUE,
235       ],
236       'Published to draft' => [
237         'published',
238         'draft',
239         TRUE,
240         TRUE,
241         FALSE,
242         FALSE,
243       ],
244     ];
245   }
246
247   /**
248    * Test updating the state for an entity without a workflow.
249    */
250   public function testEntityWithNoWorkflow() {
251     $node_type = NodeType::create([
252       'type' => 'example_no_workflow',
253     ]);
254     $node_type->save();
255     $test_node = Node::create([
256       'type' => 'example_no_workflow',
257       'title' => 'Test node with no workflow',
258     ]);
259     $test_node->save();
260
261     /** @var \Drupal\content_moderation\ModerationInformationInterface $content_moderation_info */
262     $content_moderation_info = \Drupal::service('content_moderation.moderation_information');
263     $workflow = $content_moderation_info->getWorkflowForEntity($test_node);
264     $this->assertNull($workflow);
265
266     $this->assertTrue($test_node->isPublished());
267     $test_node->moderation_state->setValue('draft');
268     // The entity is still published because there is not a workflow.
269     $this->assertTrue($test_node->isPublished());
270   }
271
272   /**
273    * Test the moderation_state field after an entity has been serialized.
274    *
275    * @dataProvider entityUnserializeTestCases
276    */
277   public function testEntityUnserialize($state, $default, $published) {
278     $this->testNode->moderation_state->value = $state;
279
280     $this->assertEquals($state, $this->testNode->moderation_state->value);
281     $this->assertEquals($default, $this->testNode->isDefaultRevision());
282     $this->assertEquals($published, $this->testNode->isPublished());
283
284     $unserialized = unserialize(serialize($this->testNode));
285
286     $this->assertEquals($state, $unserialized->moderation_state->value);
287     $this->assertEquals($default, $unserialized->isDefaultRevision());
288     $this->assertEquals($published, $unserialized->isPublished());
289   }
290
291   /**
292    * Test cases for ::testEntityUnserialize.
293    */
294   public function entityUnserializeTestCases() {
295     return [
296       'Default draft state' => [
297         'draft',
298         TRUE,
299         FALSE,
300       ],
301       'Non-default published state' => [
302         'published',
303         TRUE,
304         TRUE,
305       ],
306     ];
307   }
308
309   /**
310    * Test saving a moderated node with an existing ID.
311    *
312    * @dataProvider moderatedEntityWithExistingIdTestCases
313    */
314   public function testModeratedEntityWithExistingId($state) {
315     $node = Node::create([
316       'title' => 'Test title',
317       'type' => 'example',
318       'nid' => 999,
319       'moderation_state' => $state,
320     ]);
321     $node->save();
322     $this->assertEquals($state, $node->moderation_state->value);
323   }
324
325   /**
326    * Test cases for ::testModeratedEntityWithExistingId.
327    */
328   public function moderatedEntityWithExistingIdTestCases() {
329     return [
330       'Draft non-default state' => [
331         'draft',
332       ],
333       'Published default state' => [
334         'published',
335       ],
336     ];
337   }
338
339   /**
340    * Test the field item list when used with existing unmoderated content.
341    */
342   public function testWithExistingUnmoderatedContent() {
343     $node = Node::create([
344       'title' => 'Test title',
345       'type' => 'unmoderated',
346     ]);
347     $node->save();
348     $translation = $node->addTranslation('de', $node->toArray());
349     $translation->title = 'Translated';
350     $translation->save();
351
352     $workflow = Workflow::load('editorial');
353     $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'unmoderated');
354     $workflow->save();
355
356     // After enabling moderation, both the original node and translation should
357     // have a published moderation state.
358     $node = Node::load($node->id());
359     $translation = $node->getTranslation('de');
360     $this->assertEquals('published', $node->moderation_state->value);
361     $this->assertEquals('published', $translation->moderation_state->value);
362
363     // After the node has been updated, both the original node and translation
364     // should still have a value.
365     $node->title = 'Updated title';
366     $node->save();
367     $translation = $node->getTranslation('de');
368     $this->assertEquals('published', $node->moderation_state->value);
369     $this->assertEquals('published', $translation->moderation_state->value);
370   }
371
372 }