6304976176a7cf935a6d8395115c753104688523
[yaffs-website] / web / core / modules / taxonomy / tests / src / Functional / TermAutocompleteTest.php
1 <?php
2
3 namespace Drupal\Tests\taxonomy\Functional;
4
5 use Drupal\Component\Serialization\Json;
6 use Drupal\Core\Entity\Entity\EntityFormDisplay;
7 use Drupal\Core\Entity\Entity\EntityViewDisplay;
8 use Drupal\Core\Field\FieldStorageDefinitionInterface;
9 use Drupal\field\Entity\FieldConfig;
10 use Drupal\field\Entity\FieldStorageConfig;
11
12 /**
13  * Tests the autocomplete implementation of the taxonomy class.
14  *
15  * @group taxonomy
16  */
17 class TermAutocompleteTest extends TaxonomyTestBase {
18
19   /**
20    * Modules to enable.
21    *
22    * @var array
23    */
24   public static $modules = ['node'];
25
26   /**
27    * The vocabulary.
28    *
29    * @var \Drupal\taxonomy\Entity\Vocabulary
30    */
31   protected $vocabulary;
32
33   /**
34    * The field to add to the content type for the taxonomy terms.
35    *
36    * @var string
37    */
38   protected $fieldName;
39
40   /**
41    * The admin user.
42    *
43    * @var \Drupal\user\Entity\User
44    */
45   protected $adminUser;
46
47   /**
48    * The autocomplete URL to call.
49    *
50    * @var string
51    */
52   protected $autocompleteUrl;
53
54   /**
55    * The term IDs indexed by term names.
56    *
57    * @var array
58    */
59   protected $termIds;
60
61   /**
62    * {@inheritdoc}
63    */
64   protected function setUp() {
65     parent::setUp();
66
67     // Create a vocabulary.
68     $this->vocabulary = $this->createVocabulary();
69
70     // Create 11 terms, which have some sub-string in common, in a
71     // non-alphabetical order, so that we will have more than 10 matches later
72     // when we test the correct number of results is returned, and we can test
73     // the order of the results. The location of the sub-string to match varies
74     // also, since it should not be necessary to start with the sub-string to
75     // match it. Save term IDs to reuse later.
76     $termNames = [
77       'aaa 20 bbb',
78       'aaa 70 bbb',
79       'aaa 10 bbb',
80       'aaa 12 bbb',
81       'aaa 40 bbb',
82       'aaa 11 bbb',
83       'aaa 30 bbb',
84       'aaa 50 bbb',
85       'aaa 80',
86       'aaa 90',
87       'bbb 60 aaa',
88     ];
89     foreach ($termNames as $termName) {
90       $term = $this->createTerm($this->vocabulary, ['name' => $termName]);
91       $this->termIds[$termName] = $term->id();
92     }
93
94     // Create a taxonomy_term_reference field on the article Content Type that
95     // uses a taxonomy_autocomplete widget.
96     $this->fieldName = mb_strtolower($this->randomMachineName());
97     FieldStorageConfig::create([
98       'field_name' => $this->fieldName,
99       'entity_type' => 'node',
100       'type' => 'entity_reference',
101       'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
102       'settings' => [
103         'target_type' => 'taxonomy_term',
104       ],
105     ])->save();
106     FieldConfig::create([
107       'field_name' => $this->fieldName,
108       'bundle' => 'article',
109       'entity_type' => 'node',
110       'settings' => [
111         'handler' => 'default',
112         'handler_settings' => [
113           // Restrict selection of terms to a single vocabulary.
114           'target_bundles' => [
115             $this->vocabulary->id() => $this->vocabulary->id(),
116           ],
117         ],
118       ],
119     ])->save();
120     EntityFormDisplay::load('node.article.default')
121       ->setComponent($this->fieldName, [
122         'type' => 'entity_reference_autocomplete',
123       ])
124       ->save();
125     EntityViewDisplay::load('node.article.default')
126       ->setComponent($this->fieldName, [
127         'type' => 'entity_reference_label',
128       ])
129       ->save();
130
131     // Create a user and then login.
132     $this->adminUser = $this->drupalCreateUser(['create article content']);
133     $this->drupalLogin($this->adminUser);
134
135     // Retrieve the autocomplete url.
136     $this->drupalGet('node/add/article');
137     $result = $this->xpath('//input[@name="' . $this->fieldName . '[0][target_id]"]');
138     $this->autocompleteUrl = $this->getAbsoluteUrl($result[0]->getAttribute('data-autocomplete-path'));
139   }
140
141   /**
142    * Helper function for JSON formatted requests.
143    *
144    * @param string|\Drupal\Core\Url $path
145    *   Drupal path or URL to load into Mink controlled browser.
146    * @param array $options
147    *   (optional) Options to be forwarded to the url generator.
148    * @param string[] $headers
149    *   (optional) An array containing additional HTTP request headers.
150    *
151    * @return string[]
152    *   Array representing decoded JSON response.
153    */
154   protected function drupalGetJson($path, array $options = [], array $headers = []) {
155     $options = array_merge_recursive(['query' => ['_format' => 'json']], $options);
156     return Json::decode($this->drupalGet($path, $options, $headers));
157   }
158
159   /**
160    * Tests that the autocomplete method returns the good number of results.
161    *
162    * @see \Drupal\taxonomy\Controller\TermAutocompleteController::autocomplete()
163    */
164   public function testAutocompleteCountResults() {
165     // Test that no matching term found.
166     $data = $this->drupalGetJson(
167       $this->autocompleteUrl,
168       ['query' => ['q' => 'zzz']]
169     );
170     $this->assertTrue(empty($data), 'Autocomplete returned no results');
171
172     // Test that only one matching term found, when only one matches.
173     $data = $this->drupalGetJson(
174       $this->autocompleteUrl,
175       ['query' => ['q' => 'aaa 10']]
176     );
177     $this->assertEqual(1, count($data), 'Autocomplete returned 1 result');
178
179     // Test the correct number of matches when multiple are partial matches.
180     $data = $this->drupalGetJson(
181       $this->autocompleteUrl,
182       ['query' => ['q' => 'aaa 1']]
183     );
184     $this->assertEqual(3, count($data), 'Autocomplete returned 3 results');
185
186     // Tests that only 10 results are returned, even if there are more than 10
187     // matches.
188     $data = $this->drupalGetJson(
189       $this->autocompleteUrl,
190       ['query' => ['q' => 'aaa']]
191     );
192     $this->assertEqual(10, count($data), 'Autocomplete returned only 10 results (for over 10 matches)');
193   }
194
195   /**
196    * Tests that the autocomplete method returns properly ordered results.
197    *
198    * @see \Drupal\taxonomy\Controller\TermAutocompleteController::autocomplete()
199    */
200   public function testAutocompleteOrderedResults() {
201     $expectedResults = [
202       'aaa 10 bbb',
203       'aaa 11 bbb',
204       'aaa 12 bbb',
205       'aaa 20 bbb',
206       'aaa 30 bbb',
207       'aaa 40 bbb',
208       'aaa 50 bbb',
209       'aaa 70 bbb',
210       'bbb 60 aaa',
211     ];
212     // Build $expected to match the autocomplete results.
213     $expected = [];
214     foreach ($expectedResults as $termName) {
215       $expected[] = [
216         'value' => $termName . ' (' . $this->termIds[$termName] . ')',
217         'label' => $termName,
218       ];
219     }
220
221     $data = $this->drupalGetJson(
222       $this->autocompleteUrl,
223       ['query' => ['q' => 'bbb']]
224     );
225
226     $this->assertIdentical($expected, $data);
227   }
228
229 }