3 namespace Drupal\Tests\content_moderation\Kernel;
5 use Drupal\entity_test\Entity\EntityTestNoBundle;
6 use Drupal\language\Entity\ConfigurableLanguage;
7 use Drupal\node\Entity\Node;
8 use Drupal\node\Entity\NodeType;
9 use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
10 use Drupal\views\Views;
11 use Drupal\workflows\Entity\Workflow;
14 * Tests the views 'moderation_state_filter' filter plugin.
16 * @coversDefaultClass \Drupal\content_moderation\Plugin\views\filter\ModerationStateFilter
18 * @group content_moderation
20 class ViewsModerationStateFilterTest extends ViewsKernelTestBase {
25 public static $modules = [
26 'content_moderation_test_views',
33 'content_translation',
39 protected function setUp($import_test_views = TRUE) {
42 $this->installEntitySchema('user');
43 $this->installEntitySchema('node');
44 $this->installEntitySchema('content_moderation_state');
45 $this->installEntitySchema('entity_test_no_bundle');
46 $this->installSchema('node', 'node_access');
47 $this->installConfig('content_moderation_test_views');
48 $this->installConfig('content_moderation');
50 $node_type = NodeType::create([
55 $node_type = NodeType::create([
56 'type' => 'another_example',
60 $node_type = NodeType::create([
61 'type' => 'example_non_moderated',
65 ConfigurableLanguage::createFromLangcode('fr')->save();
69 * Tests the content moderation state filter.
71 public function testStateFilterViewsRelationship() {
72 $workflow = Workflow::load('editorial');
73 $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
74 $workflow->getTypePlugin()->addState('translated_draft', 'Bar');
75 $configuration = $workflow->getTypePlugin()->getConfiguration();
76 $configuration['states']['translated_draft'] += [
78 'default_revision' => FALSE,
80 $workflow->getTypePlugin()->setConfiguration($configuration);
83 // Create a published default revision and one forward draft revision.
84 $node = Node::create([
86 'title' => 'Test Node',
87 'moderation_state' => 'published',
90 $node->setNewRevision();
91 $node->moderation_state = 'draft';
94 // Create a draft default revision.
95 $second_node = Node::create([
97 'title' => 'Second Node',
98 'moderation_state' => 'draft',
100 $second_node->save();
102 // Create a published default revision.
103 $third_node = Node::create([
105 'title' => 'Third node',
106 'moderation_state' => 'published',
110 // Add a non-moderated node.
111 $fourth_node = Node::create([
112 'type' => 'example_non_moderated',
113 'title' => 'Fourth node',
115 $fourth_node->save();
117 // Create a translated published revision.
118 $translated_forward_revision = $third_node->addTranslation('fr');
119 $translated_forward_revision->title = 'Translated Node';
120 $translated_forward_revision->setNewRevision(TRUE);
121 $translated_forward_revision->moderation_state = 'translated_draft';
122 $translated_forward_revision->save();
124 // The three default revisions are listed when no filter is specified.
125 $this->assertNodesWithFilters([$node, $second_node, $third_node], []);
127 // The default revision of node one and three are published.
128 $this->assertNodesWithFilters([$node, $third_node], [
129 'default_revision_state' => 'editorial-published',
132 // The default revision of node two is draft.
133 $this->assertNodesWithFilters([$second_node], [
134 'default_revision_state' => 'editorial-draft',
137 // Test the same three revisions on a view displaying content revisions.
138 // Both nodes have one draft revision.
139 $this->assertNodesWithFilters([$node, $second_node], [
140 'moderation_state' => 'editorial-draft',
141 ], 'test_content_moderation_state_filter_revision_table');
142 // Creating a new forward revision of node three, creates a second published
143 // revision of of the original language, hence there are two published
144 // revisions of node three.
145 $this->assertNodesWithFilters([$node, $third_node, $third_node], [
146 'moderation_state' => 'editorial-published',
147 ], 'test_content_moderation_state_filter_revision_table');
148 // There is a single forward translated revision with a new state, which is
150 $this->assertNodesWithFilters([$translated_forward_revision], [
151 'moderation_state' => 'editorial-translated_draft',
152 ], 'test_content_moderation_state_filter_revision_table');
156 * Test the moderation filter with a non-translatable entity type.
158 public function testNonTranslatableEntityType() {
159 $workflow = Workflow::load('editorial');
160 $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_no_bundle', 'entity_test_no_bundle');
163 $test_entity = EntityTestNoBundle::create([
164 'moderation_state' => 'draft',
166 $test_entity->save();
168 $view = Views::getView('test_content_moderation_state_filter_entity_test');
169 $view->setExposedInput([
170 'moderation_state' => 'editorial-draft',
173 $this->assertIdenticalResultset($view, [['id' => $test_entity->id()]], ['id' => 'id']);
177 * Tests the list of states in the filter plugin.
179 public function testStateFilterStatesList() {
180 // By default a view of nodes will not have states to filter.
181 $this->assertPluginStates([]);
183 // Adding a content type to the editorial workflow will enable all of the
185 $workflow = Workflow::load('editorial');
186 $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
188 $this->assertPluginStates([
190 'editorial-draft' => 'Draft',
191 'editorial-published' => 'Published',
192 'editorial-archived' => 'Archived',
196 // Adding a workflow which is not content moderation will not add any
197 // additional states to the views filter.
198 $workflow = Workflow::create(['id' => 'test', 'type' => 'workflow_type_complex_test']);
199 $workflow->getTypePlugin()->addState('draft', 'Draft');
201 $this->assertPluginStates([
203 'editorial-draft' => 'Draft',
204 'editorial-published' => 'Published',
205 'editorial-archived' => 'Archived',
209 // Adding a new content moderation workflow will add additional states to
211 $workflow = Workflow::create(['id' => 'moderation_test', 'type' => 'content_moderation', 'label' => 'Moderation test']);
212 $workflow->getTypePlugin()->addState('foo', 'Foo State');
213 $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
215 $this->assertPluginStates([
217 'editorial-draft' => 'Draft',
218 'editorial-published' => 'Published',
219 'editorial-archived' => 'Archived',
221 'Moderation test' => [
222 'moderation_test-foo' => 'Foo State',
223 'moderation_test-draft' => 'Draft',
224 'moderation_test-published' => 'Published',
228 // Deleting a workflow will remove the states from the filter.
229 $workflow = Workflow::load('moderation_test');
231 $this->assertPluginStates([
233 'editorial-draft' => 'Draft',
234 'editorial-published' => 'Published',
235 'editorial-archived' => 'Archived',
239 // Deleting a state from a workflow will remove the state from the filter.
240 $workflow = Workflow::load('editorial');
241 $workflow->getTypePlugin()->deleteState('archived');
243 $this->assertPluginStates([
245 'editorial-draft' => 'Draft',
246 'editorial-published' => 'Published',
252 * Assert the plugin states.
254 * @param string[] $states
255 * The states which should appear in the filter.
257 protected function assertPluginStates($states) {
258 $plugin = Views::pluginManager('filter')->createInstance('moderation_state_filter', []);
259 $view = Views::getView('test_content_moderation_state_filter_base_table');
260 $plugin->init($view, $view->getDisplay());
261 $this->assertEquals($states, $plugin->getValueOptions());
265 * Assert the nodes appear when the test view is executed.
267 * @param \Drupal\node\NodeInterface[] $nodes
268 * Nodes to assert are in the views result.
269 * @param array $filters
270 * An array of filters to apply to the view.
271 * @param string $view_id
272 * The view to execute for the results.
274 protected function assertNodesWithFilters(array $nodes, array $filters, $view_id = 'test_content_moderation_state_filter_base_table') {
275 $view = Views::getView($view_id);
276 $view->setExposedInput($filters);
279 // Verify the join configuration.
280 $query = $view->getQuery();
281 $join = $query->getTableInfo('content_moderation_state')['join'];
282 $configuration = $join->configuration;
283 $this->assertEquals('content_moderation_state_field_revision', $configuration['table']);
284 $this->assertEquals('content_entity_revision_id', $configuration['field']);
285 $this->assertEquals('vid', $configuration['left_field']);
286 $this->assertEquals('content_entity_type_id', $configuration['extra'][0]['field']);
287 $this->assertEquals('node', $configuration['extra'][0]['value']);
288 $this->assertEquals('langcode', $configuration['extra'][1]['field']);
289 $this->assertEquals('langcode', $configuration['extra'][1]['left_field']);
291 $expected_result = [];
292 foreach ($nodes as $node) {
293 $expected_result[] = ['nid' => $node->id()];
295 $this->assertIdenticalResultset($view, $expected_result, ['nid' => 'nid']);