3 namespace Drupal\Tests\views_ui\FunctionalJavascript;
5 use Behat\Mink\Element\NodeElement;
6 use Drupal\Core\Database\Database;
7 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
8 use Drupal\views\Tests\ViewTestData;
11 * Tests the UI preview functionality.
15 class PreviewTest extends WebDriverTestBase {
18 * Views used by this test.
22 public static $testViews = ['test_preview', 'test_pager_full_ajax', 'test_mini_pager_ajax', 'test_click_sort_ajax'];
27 public static $modules = [
37 public function setUp() {
40 ViewTestData::createTestViews(self::class, ['views_test_config']);
42 $this->enableViewsTestModule();
44 $admin_user = $this->drupalCreateUser([
45 'administer site configuration',
48 'access content overview',
51 // Disable automatic live preview to make the sequence of calls clearer.
52 \Drupal::configFactory()->getEditable('views.settings')->set('ui.always_live_preview', FALSE)->save();
53 $this->drupalLogin($admin_user);
57 * Sets up the views_test_data.module.
59 * Because the schema of views_test_data.module is dependent on the test
60 * using it, it cannot be enabled normally.
62 protected function enableViewsTestModule() {
63 // Define the schema and views data variable before enabling the test module.
64 \Drupal::state()->set('views_test_data_schema', $this->schemaDefinition());
65 \Drupal::state()->set('views_test_data_views_data', $this->viewsData());
67 \Drupal::service('module_installer')->install(['views_test_data']);
69 $this->rebuildContainer();
70 $this->container->get('module_handler')->reload();
72 // Load the test dataset.
73 $data_set = $this->dataSet();
74 $query = Database::getConnection()->insert('views_test_data')
75 ->fields(array_keys($data_set[0]));
76 foreach ($data_set as $record) {
77 $query->values($record);
83 * Returns the schema definition.
87 protected function schemaDefinition() {
88 return ViewTestData::schemaDefinition();
92 * Returns the views data definition.
94 protected function viewsData() {
95 return ViewTestData::viewsData();
99 * Returns a very simple test dataset.
101 protected function dataSet() {
102 return ViewTestData::dataSet();
106 * Tests the taxonomy term preview AJAX.
108 * This tests a specific regression in the taxonomy term view preview.
110 * @see https://www.drupal.org/node/2452659
112 public function testTaxonomyAJAX() {
113 \Drupal::service('module_installer')->install(['taxonomy']);
114 $this->getPreviewAJAX('taxonomy_term', 'page_1', 0);
118 * Tests pagers in the preview form.
120 public function testPreviewWithPagersUI() {
121 // Create 11 nodes and make sure that everyone is returned.
122 $this->drupalCreateContentType(['type' => 'page']);
123 for ($i = 0; $i < 11; $i++) {
124 $this->drupalCreateNode();
128 $this->getPreviewAJAX('test_pager_full_ajax', 'default', 5);
130 // Test that the pager is present and rendered.
131 $elements = $this->xpath('//ul[contains(@class, :class)]/li', [':class' => 'pager__items']);
132 $this->assertTrue(!empty($elements), 'Full pager found.');
134 // Verify elements and links to pages.
135 // We expect to find 5 elements: current page == 1, links to pages 2 and
136 // and 3, links to 'next >' and 'last >>' pages.
137 $this->assertClass($elements[0], 'is-active', 'Element for current page has .is-active class.');
138 $this->assertTrue($elements[0]->find('css', 'a'), 'Element for current page has link.');
140 $this->assertClass($elements[1], 'pager__item', 'Element for page 2 has .pager__item class.');
141 $this->assertTrue($elements[1]->find('css', 'a'), 'Link to page 2 found.');
143 $this->assertClass($elements[2], 'pager__item', 'Element for page 3 has .pager__item class.');
144 $this->assertTrue($elements[2]->find('css', 'a'), 'Link to page 3 found.');
146 $this->assertClass($elements[3], 'pager__item--next', 'Element for next page has .pager__item--next class.');
147 $this->assertTrue($elements[3]->find('css', 'a'), 'Link to next page found.');
149 $this->assertClass($elements[4], 'pager__item--last', 'Element for last page has .pager__item--last class.');
150 $this->assertTrue($elements[4]->find('css', 'a'), 'Link to last page found.');
152 // Navigate to next page.
153 $elements = $this->xpath('//li[contains(@class, :class)]/a', [':class' => 'pager__item--next']);
154 $this->clickPreviewLinkAJAX($elements[0], 5);
156 // Test that the pager is present and rendered.
157 $elements = $this->xpath('//ul[contains(@class, :class)]/li', [':class' => 'pager__items']);
158 $this->assertTrue(!empty($elements), 'Full pager found.');
160 // Verify elements and links to pages.
161 // We expect to find 7 elements: links to '<< first' and '< previous'
162 // pages, link to page 1, current page == 2, link to page 3 and links
163 // to 'next >' and 'last >>' pages.
164 $this->assertClass($elements[0], 'pager__item--first', 'Element for first page has .pager__item--first class.');
165 $this->assertTrue($elements[0]->find('css', 'a'), 'Link to first page found.');
167 $this->assertClass($elements[1], 'pager__item--previous', 'Element for previous page has .pager__item--previous class.');
168 $this->assertTrue($elements[1]->find('css', 'a'), 'Link to previous page found.');
170 $this->assertClass($elements[2], 'pager__item', 'Element for page 1 has .pager__item class.');
171 $this->assertTrue($elements[2]->find('css', 'a'), 'Link to page 1 found.');
173 $this->assertClass($elements[3], 'is-active', 'Element for current page has .is-active class.');
174 $this->assertTrue($elements[3]->find('css', 'a'), 'Element for current page has link.');
176 $this->assertClass($elements[4], 'pager__item', 'Element for page 3 has .pager__item class.');
177 $this->assertTrue($elements[4]->find('css', 'a'), 'Link to page 3 found.');
179 $this->assertClass($elements[5], 'pager__item--next', 'Element for next page has .pager__item--next class.');
180 $this->assertTrue($elements[5]->find('css', 'a'), 'Link to next page found.');
182 $this->assertClass($elements[6], 'pager__item--last', 'Element for last page has .pager__item--last class.');
183 $this->assertTrue($elements[6]->find('css', 'a'), 'Link to last page found.');
186 $this->getPreviewAJAX('test_mini_pager_ajax', 'default', 3);
188 // Test that the pager is present and rendered.
189 $elements = $this->xpath('//ul[contains(@class, :class)]/li', [':class' => 'pager__items']);
190 $this->assertTrue(!empty($elements), 'Mini pager found.');
192 // Verify elements and links to pages.
193 // We expect to find current pages element with no link, next page element
194 // with a link, and not to find previous page element.
195 $this->assertClass($elements[0], 'is-active', 'Element for current page has .is-active class.');
197 $this->assertClass($elements[1], 'pager__item--next', 'Element for next page has .pager__item--next class.');
198 $this->assertTrue($elements[1]->find('css', 'a'), 'Link to next page found.');
200 // Navigate to next page.
201 $elements = $this->xpath('//li[contains(@class, :class)]/a', [':class' => 'pager__item--next']);
202 $this->clickPreviewLinkAJAX($elements[0], 3);
204 // Test that the pager is present and rendered.
205 $elements = $this->xpath('//ul[contains(@class, :class)]/li', [':class' => 'pager__items']);
206 $this->assertTrue(!empty($elements), 'Mini pager found.');
208 // Verify elements and links to pages.
209 // We expect to find 3 elements: previous page with a link, current
210 // page with no link, and next page with a link.
211 $this->assertClass($elements[0], 'pager__item--previous', 'Element for previous page has .pager__item--previous class.');
212 $this->assertTrue($elements[0]->find('css', 'a'), 'Link to previous page found.');
214 $this->assertClass($elements[1], 'is-active', 'Element for current page has .is-active class.');
215 $this->assertEmpty($elements[1]->find('css', 'a'), 'Element for current page has no link.');
217 $this->assertClass($elements[2], 'pager__item--next', 'Element for next page has .pager__item--next class.');
218 $this->assertTrue($elements[2]->find('css', 'a'), 'Link to next page found.');
222 * Tests the link to sort in the preview form.
224 public function testPreviewSortLink() {
226 $this->getPreviewAJAX('test_click_sort_ajax', 'page_1', 0);
228 // Test that the header label is present.
229 $elements = $this->xpath('//th[contains(@class, :class)]/a', [':class' => 'views-field views-field-name']);
230 $this->assertTrue(!empty($elements), 'The header label is present.');
233 $this->assertLinkByHref('preview/page_1?_wrapper_format=drupal_ajax&order=name&sort=desc', 0, 'The output URL is as expected.');
235 // Click link to sort.
236 $elements[0]->click();
237 $sort_link = $this->assertSession()->waitForElement('xpath', '//th[contains(@class, \'views-field views-field-name is-active\')]/a');
239 $this->assertNotEmpty($sort_link);
242 $this->assertLinkByHref('preview/page_1?_wrapper_format=drupal_ajax&order=name&sort=asc', 0, 'The output URL is as expected.');
246 * Get the preview form and force an AJAX preview update.
248 * @param string $view_name
250 * @param string $panel_id
251 * The view panel to test.
252 * @param int $row_count
253 * The expected number of rows in the preview.
255 protected function getPreviewAJAX($view_name, $panel_id, $row_count) {
256 $this->drupalGet('admin/structure/views/view/' . $view_name . '/edit/' . $panel_id);
257 $this->getSession()->getPage()->pressButton('Update preview');
258 $this->assertSession()->assertWaitOnAjaxRequest();
259 $this->assertPreviewAJAX($row_count);
263 * Click on a preview link.
265 * @param \Behat\Mink\Element\NodeElement $element
266 * The element to click.
267 * @param int $row_count
268 * The expected number of rows in the preview.
270 protected function clickPreviewLinkAJAX(NodeElement $element, $row_count) {
272 $this->assertSession()->assertWaitOnAjaxRequest();
273 $this->assertPreviewAJAX($row_count);
277 * Assert that the preview contains expected data.
279 * @param int $row_count
280 * The expected number of rows in the preview.
282 protected function assertPreviewAJAX($row_count) {
283 $elements = $this->getSession()->getPage()->findAll('css', '.view-content .views-row');
284 $this->assertCount($row_count, $elements, 'Expected items found on page.');
288 * Asserts that an element has a given class.
290 * @param \Behat\Mink\Element\NodeElement $element
291 * The element to test.
292 * @param string $class
293 * The class to assert.
294 * @param string $message
295 * (optional) A verbose message to output.
297 protected function assertClass(NodeElement $element, $class, $message = NULL) {
298 if (!isset($message)) {
299 $message = "Class .$class found.";
301 $this->assertTrue(strpos($element->getAttribute('class'), $class) !== FALSE, $message);