3 namespace Drupal\Tests\content_moderation\Kernel;
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;
13 * @coversDefaultClass \Drupal\content_moderation\Plugin\Field\ModerationStateFieldItemList
15 * @group content_moderation
17 class ModerationStateFieldItemListTest extends KernelTestBase {
19 use ContentModerationTestTrait;
24 public static $modules = [
34 * @var \Drupal\node\NodeInterface
41 protected function setUp() {
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');
51 'type' => 'unmoderated',
54 $node_type = NodeType::create([
58 $workflow = $this->createEditorialWorkflow();
59 $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
62 $this->testNode = Node::create([
64 'title' => 'Test title',
66 $this->testNode->save();
67 \Drupal::entityTypeManager()->getStorage('node')->resetCache();
68 $this->testNode = Node::load($this->testNode->id());
70 ConfigurableLanguage::createFromLangcode('de')->save();
74 * Test the field item list when accessing an index.
76 public function testArrayIndex() {
77 $this->assertFalse($this->testNode->isPublished());
78 $this->assertEquals('draft', $this->testNode->moderation_state[0]->value);
82 * Test the field item list when iterating.
84 public function testArrayIteration() {
86 foreach ($this->testNode->moderation_state as $item) {
87 $states[] = $item->value;
89 $this->assertEquals(['draft'], $states);
95 public function testGetValue() {
96 $this->assertEquals([['value' => 'draft']], $this->testNode->moderation_state->getValue());
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);
109 * Tests the item list when it is emptied and appended to.
111 public function testEmptyStateAndAppend() {
112 // This test case mimics the lifecycle of an entity that is being patched in
114 $this->testNode->moderation_state->setValue([]);
115 $this->assertTrue($this->testNode->moderation_state->isEmpty());
116 $this->assertEmptiedModerationFieldItemList();
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();
125 * Test an empty value assigned to the field item.
127 public function testEmptyFieldItem() {
128 $this->testNode->moderation_state->value = '';
129 $this->assertEquals('', $this->testNode->moderation_state->value);
130 $this->assertEmptiedModerationFieldItemList();
134 * Test an empty value assigned to the field item list.
136 public function testEmptyFieldItemList() {
137 $this->testNode->moderation_state = '';
138 $this->assertEquals('', $this->testNode->moderation_state->value);
139 $this->assertEmptiedModerationFieldItemList();
143 * Test the field item when it is unset.
145 public function testUnsetItemList() {
146 unset($this->testNode->moderation_state);
147 $this->assertEquals(NULL, $this->testNode->moderation_state->value);
148 $this->assertEmptiedModerationFieldItemList();
152 * Test the field item when it is assigned NULL.
154 public function testAssignNullItemList() {
155 $this->testNode->moderation_state = NULL;
156 $this->assertEquals(NULL, $this->testNode->moderation_state->value);
157 $this->assertEmptiedModerationFieldItemList();
161 * Assert the set of expectations when the moderation state field is emptied.
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);
176 * Test the list class with a non moderated entity.
178 public function testNonModeratedEntity() {
179 $unmoderated_node = Node::create([
180 'type' => 'unmoderated',
181 'title' => 'Test title',
183 $unmoderated_node->save();
184 $this->assertEquals(0, $unmoderated_node->moderation_state->count());
186 $unmoderated_node->moderation_state = NULL;
187 $this->assertEquals(0, $unmoderated_node->moderation_state->count());
188 $this->assertCount(0, $unmoderated_node->validate());
192 * Tests that moderation state changes also change the related entity state.
194 * @dataProvider moderationStateChangesTestCases
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();
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());
208 * Data provider for ::testModerationStateChanges
210 public function moderationStateChangesTestCases() {
212 'Draft to draft' => [
220 'Draft to published' => [
228 'Published to published' => [
236 'Published to draft' => [
248 * Test updating the state for an entity without a workflow.
250 public function testEntityWithNoWorkflow() {
251 $node_type = NodeType::create([
252 'type' => 'example_no_workflow',
255 $test_node = Node::create([
256 'type' => 'example_no_workflow',
257 'title' => 'Test node with no workflow',
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);
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());
273 * Test the moderation_state field after an entity has been serialized.
275 * @dataProvider entityUnserializeTestCases
277 public function testEntityUnserialize($state, $default, $published) {
278 $this->testNode->moderation_state->value = $state;
280 $this->assertEquals($state, $this->testNode->moderation_state->value);
281 $this->assertEquals($default, $this->testNode->isDefaultRevision());
282 $this->assertEquals($published, $this->testNode->isPublished());
284 $unserialized = unserialize(serialize($this->testNode));
286 $this->assertEquals($state, $unserialized->moderation_state->value);
287 $this->assertEquals($default, $unserialized->isDefaultRevision());
288 $this->assertEquals($published, $unserialized->isPublished());
292 * Test cases for ::testEntityUnserialize.
294 public function entityUnserializeTestCases() {
296 'Default draft state' => [
301 'Non-default published state' => [
310 * Test saving a moderated node with an existing ID.
312 * @dataProvider moderatedEntityWithExistingIdTestCases
314 public function testModeratedEntityWithExistingId($state) {
315 $node = Node::create([
316 'title' => 'Test title',
319 'moderation_state' => $state,
322 $this->assertEquals($state, $node->moderation_state->value);
326 * Test cases for ::testModeratedEntityWithExistingId.
328 public function moderatedEntityWithExistingIdTestCases() {
330 'Draft non-default state' => [
333 'Published default state' => [
340 * Test the field item list when used with existing unmoderated content.
342 public function testWithExistingUnmoderatedContent() {
343 $node = Node::create([
344 'title' => 'Test title',
345 'type' => 'unmoderated',
348 $translation = $node->addTranslation('de', $node->toArray());
349 $translation->title = 'Translated';
350 $translation->save();
352 $workflow = Workflow::load('editorial');
353 $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'unmoderated');
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);
363 // After the node has been updated, both the original node and translation
364 // should still have a value.
365 $node->title = 'Updated title';
367 $translation = $node->getTranslation('de');
368 $this->assertEquals('published', $node->moderation_state->value);
369 $this->assertEquals('published', $translation->moderation_state->value);