comparison core/modules/responsive_image/src/Tests/ResponsiveImageFieldDisplayTest.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
1 <?php
2
3 namespace Drupal\responsive_image\Tests;
4
5 use Drupal\Component\Utility\Unicode;
6 use Drupal\image\Tests\ImageFieldTestBase;
7 use Drupal\image\Entity\ImageStyle;
8 use Drupal\node\Entity\Node;
9 use Drupal\file\Entity\File;
10 use Drupal\responsive_image\Plugin\Field\FieldFormatter\ResponsiveImageFormatter;
11 use Drupal\responsive_image\Entity\ResponsiveImageStyle;
12 use Drupal\user\RoleInterface;
13
14 /**
15 * Tests responsive image display formatter.
16 *
17 * @group responsive_image
18 */
19 class ResponsiveImageFieldDisplayTest extends ImageFieldTestBase {
20
21 protected $dumpHeaders = TRUE;
22
23 /**
24 * Responsive image style entity instance we test with.
25 *
26 * @var \Drupal\responsive_image\Entity\ResponsiveImageStyle
27 */
28 protected $responsiveImgStyle;
29
30 /**
31 * Modules to enable.
32 *
33 * @var array
34 */
35 public static $modules = ['field_ui', 'responsive_image', 'responsive_image_test_module'];
36
37 /**
38 * Drupal\simpletest\WebTestBase\setUp().
39 */
40 protected function setUp() {
41 parent::setUp();
42
43 // Create user.
44 $this->adminUser = $this->drupalCreateUser([
45 'administer responsive images',
46 'access content',
47 'access administration pages',
48 'administer site configuration',
49 'administer content types',
50 'administer node display',
51 'administer nodes',
52 'create article content',
53 'edit any article content',
54 'delete any article content',
55 'administer image styles'
56 ]);
57 $this->drupalLogin($this->adminUser);
58 // Add responsive image style.
59 $this->responsiveImgStyle = ResponsiveImageStyle::create([
60 'id' => 'style_one',
61 'label' => 'Style One',
62 'breakpoint_group' => 'responsive_image_test_module',
63 'fallback_image_style' => 'large',
64 ]);
65 }
66
67 /**
68 * Tests responsive image formatters on node display for public files.
69 */
70 public function testResponsiveImageFieldFormattersPublic() {
71 $this->addTestImageStyleMappings();
72 $this->doTestResponsiveImageFieldFormatters('public');
73 }
74
75 /**
76 * Tests responsive image formatters on node display for private files.
77 */
78 public function testResponsiveImageFieldFormattersPrivate() {
79 $this->addTestImageStyleMappings();
80 // Remove access content permission from anonymous users.
81 user_role_change_permissions(RoleInterface::ANONYMOUS_ID, ['access content' => FALSE]);
82 $this->doTestResponsiveImageFieldFormatters('private');
83 }
84
85 /**
86 * Test responsive image formatters when image style is empty.
87 */
88 public function testResponsiveImageFieldFormattersEmptyStyle() {
89 $this->addTestImageStyleMappings(TRUE);
90 $this->doTestResponsiveImageFieldFormatters('public', TRUE);
91 }
92
93 /**
94 * Add image style mappings to the responsive image style entity.
95 *
96 * @param bool $empty_styles
97 * If true, the image style mappings will get empty image styles.
98 */
99 protected function addTestImageStyleMappings($empty_styles = FALSE) {
100 if ($empty_styles) {
101 $this->responsiveImgStyle
102 ->addImageStyleMapping('responsive_image_test_module.mobile', '1x', [
103 'image_mapping_type' => 'image_style',
104 'image_mapping' => '',
105 ])
106 ->addImageStyleMapping('responsive_image_test_module.narrow', '1x', [
107 'image_mapping_type' => 'sizes',
108 'image_mapping' => [
109 'sizes' => '(min-width: 700px) 700px, 100vw',
110 'sizes_image_styles' => [],
111 ],
112 ])
113 ->addImageStyleMapping('responsive_image_test_module.wide', '1x', [
114 'image_mapping_type' => 'image_style',
115 'image_mapping' => '',
116 ])
117 ->save();
118 }
119 else {
120 $this->responsiveImgStyle
121 // Test the output of an empty image.
122 ->addImageStyleMapping('responsive_image_test_module.mobile', '1x', [
123 'image_mapping_type' => 'image_style',
124 'image_mapping' => RESPONSIVE_IMAGE_EMPTY_IMAGE,
125 ])
126 // Test the output with a 1.5x multiplier.
127 ->addImageStyleMapping('responsive_image_test_module.mobile', '1.5x', [
128 'image_mapping_type' => 'image_style',
129 'image_mapping' => 'thumbnail',
130 ])
131 // Test the output of the 'sizes' attribute.
132 ->addImageStyleMapping('responsive_image_test_module.narrow', '1x', [
133 'image_mapping_type' => 'sizes',
134 'image_mapping' => [
135 'sizes' => '(min-width: 700px) 700px, 100vw',
136 'sizes_image_styles' => [
137 'large',
138 'medium',
139 ],
140 ],
141 ])
142 // Test the normal output of mapping to an image style.
143 ->addImageStyleMapping('responsive_image_test_module.wide', '1x', [
144 'image_mapping_type' => 'image_style',
145 'image_mapping' => 'large',
146 ])
147 // Test the output of the original image.
148 ->addImageStyleMapping('responsive_image_test_module.wide', '3x', [
149 'image_mapping_type' => 'image_style',
150 'image_mapping' => RESPONSIVE_IMAGE_ORIGINAL_IMAGE,
151 ])
152 ->save();
153 }
154 }
155 /**
156 * Test responsive image formatters on node display.
157 *
158 * If the empty styles param is set, then the function only tests for the
159 * fallback image style (large).
160 *
161 * @param string $scheme
162 * File scheme to use.
163 * @param bool $empty_styles
164 * If true, use an empty string for image style names.
165 * Defaults to false.
166 */
167 protected function doTestResponsiveImageFieldFormatters($scheme, $empty_styles = FALSE) {
168 /** @var \Drupal\Core\Render\RendererInterface $renderer */
169 $renderer = $this->container->get('renderer');
170 $node_storage = $this->container->get('entity.manager')->getStorage('node');
171 $field_name = Unicode::strtolower($this->randomMachineName());
172 $this->createImageField($field_name, 'article', ['uri_scheme' => $scheme]);
173 // Create a new node with an image attached. Make sure we use a large image
174 // so the scale effects of the image styles always have an effect.
175 $test_image = current($this->drupalGetTestFiles('image', 39325));
176
177 // Create alt text for the image.
178 $alt = $this->randomMachineName();
179
180 $nid = $this->uploadNodeImage($test_image, $field_name, 'article', $alt);
181 $node_storage->resetCache([$nid]);
182 $node = $node_storage->load($nid);
183
184 // Test that the default formatter is being used.
185 $image_uri = File::load($node->{$field_name}->target_id)->getFileUri();
186 $image = [
187 '#theme' => 'image',
188 '#uri' => $image_uri,
189 '#width' => 360,
190 '#height' => 240,
191 '#alt' => $alt,
192 ];
193 $default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
194 $this->assertRaw($default_output, 'Default formatter displaying correctly on full node view.');
195
196 // Test field not being configured. This should not cause a fatal error.
197 $display_options = [
198 'type' => 'responsive_image_test',
199 'settings' => ResponsiveImageFormatter::defaultSettings(),
200 ];
201 $display = $this->container->get('entity.manager')
202 ->getStorage('entity_view_display')
203 ->load('node.article.default');
204 if (!$display) {
205 $values = [
206 'targetEntityType' => 'node',
207 'bundle' => 'article',
208 'mode' => 'default',
209 'status' => TRUE,
210 ];
211 $display = $this->container->get('entity.manager')->getStorage('entity_view_display')->create($values);
212 }
213 $display->setComponent($field_name, $display_options)->save();
214
215 $this->drupalGet('node/' . $nid);
216
217 // Test theme function for responsive image, but using the test formatter.
218 $display_options = [
219 'type' => 'responsive_image_test',
220 'settings' => [
221 'image_link' => 'file',
222 'responsive_image_style' => 'style_one',
223 ],
224 ];
225 $display = entity_get_display('node', 'article', 'default');
226 $display->setComponent($field_name, $display_options)
227 ->save();
228
229 $this->drupalGet('node/' . $nid);
230
231 // Use the responsive image formatter linked to file formatter.
232 $display_options = [
233 'type' => 'responsive_image',
234 'settings' => [
235 'image_link' => 'file',
236 'responsive_image_style' => 'style_one',
237 ],
238 ];
239 $display = entity_get_display('node', 'article', 'default');
240 $display->setComponent($field_name, $display_options)
241 ->save();
242
243 $default_output = '<a href="' . file_url_transform_relative(file_create_url($image_uri)) . '"><picture';
244 $this->drupalGet('node/' . $nid);
245 $cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
246 $this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
247
248 $this->removeWhiteSpace();
249 $this->assertRaw($default_output, 'Image linked to file formatter displaying correctly on full node view.');
250 // Verify that the image can be downloaded.
251 $this->assertEqual(file_get_contents($test_image->uri), $this->drupalGet(file_create_url($image_uri)), 'File was downloaded successfully.');
252 if ($scheme == 'private') {
253 // Only verify HTTP headers when using private scheme and the headers are
254 // sent by Drupal.
255 $this->assertEqual($this->drupalGetHeader('Content-Type'), 'image/png', 'Content-Type header was sent.');
256 $this->assertTrue(strstr($this->drupalGetHeader('Cache-Control'), 'private') !== FALSE, 'Cache-Control header was sent.');
257
258 // Log out and try to access the file.
259 $this->drupalLogout();
260 $this->drupalGet(file_create_url($image_uri));
261 $this->assertResponse('403', 'Access denied to original image as anonymous user.');
262
263 // Log in again.
264 $this->drupalLogin($this->adminUser);
265 }
266
267 // Use the responsive image formatter with a responsive image style.
268 $display_options['settings']['responsive_image_style'] = 'style_one';
269 $display_options['settings']['image_link'] = '';
270 $display->setComponent($field_name, $display_options)
271 ->save();
272
273 // Create a derivative so at least one MIME type will be known.
274 $large_style = ImageStyle::load('large');
275 $large_style->createDerivative($image_uri, $large_style->buildUri($image_uri));
276
277 // Output should contain all image styles and all breakpoints.
278 $this->drupalGet('node/' . $nid);
279 if (!$empty_styles) {
280 $this->assertRaw('/styles/medium/');
281 // Make sure the IE9 workaround is present.
282 $this->assertRaw('<!--[if IE 9]><video style="display: none;"><![endif]-->');
283 $this->assertRaw('<!--[if IE 9]></video><![endif]-->');
284 // Assert the empty image is present.
285 $this->assertRaw('data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==');
286 $thumbnail_style = ImageStyle::load('thumbnail');
287 // Assert the output of the 'srcset' attribute (small multipliers first).
288 $this->assertRaw('data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 1x, ' . file_url_transform_relative($thumbnail_style->buildUrl($image_uri)) . ' 1.5x');
289 $this->assertRaw('/styles/medium/');
290 // Assert the output of the original image.
291 $this->assertRaw(file_url_transform_relative(file_create_url($image_uri)) . ' 3x');
292 // Assert the output of the breakpoints.
293 $this->assertRaw('media="(min-width: 0px)"');
294 $this->assertRaw('media="(min-width: 560px)"');
295 // Assert the output of the 'sizes' attribute.
296 $this->assertRaw('sizes="(min-width: 700px) 700px, 100vw"');
297 $this->assertPattern('/media="\(min-width: 560px\)".+?sizes="\(min-width: 700px\) 700px, 100vw"/');
298 // Assert the output of the 'srcset' attribute (small images first).
299 $medium_style = ImageStyle::load('medium');
300 $this->assertRaw(file_url_transform_relative($medium_style->buildUrl($image_uri)) . ' 220w, ' . file_url_transform_relative($large_style->buildUrl($image_uri)) . ' 360w');
301 $this->assertRaw('media="(min-width: 851px)"');
302 }
303 $this->assertRaw('/styles/large/');
304 $cache_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags'));
305 $this->assertTrue(in_array('config:responsive_image.styles.style_one', $cache_tags));
306 if (!$empty_styles) {
307 $this->assertTrue(in_array('config:image.style.medium', $cache_tags));
308 $this->assertTrue(in_array('config:image.style.thumbnail', $cache_tags));
309 $this->assertRaw('type="image/png"');
310 }
311 $this->assertTrue(in_array('config:image.style.large', $cache_tags));
312
313 // Test the fallback image style.
314 $image = \Drupal::service('image.factory')->get($image_uri);
315 $fallback_image = [
316 '#theme' => 'image',
317 '#alt' => $alt,
318 '#uri' => file_url_transform_relative($large_style->buildUrl($image->getSource())),
319 ];
320 // The image.html.twig template has a newline after the <img> tag but
321 // responsive-image.html.twig doesn't have one after the fallback image, so
322 // we remove it here.
323 $default_output = trim($renderer->renderRoot($fallback_image));
324 $this->assertRaw($default_output, 'Image style large formatter displaying correctly on full node view.');
325
326 if ($scheme == 'private') {
327 // Log out and try to access the file.
328 $this->drupalLogout();
329 $this->drupalGet($large_style->buildUrl($image_uri));
330 $this->assertResponse('403', 'Access denied to image style large as anonymous user.');
331 $cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
332 $this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
333 }
334 }
335
336 /**
337 * Tests responsive image formatters on node display linked to the file.
338 */
339 public function testResponsiveImageFieldFormattersLinkToFile() {
340 $this->addTestImageStyleMappings();
341 $this->assertResponsiveImageFieldFormattersLink('file');
342 }
343
344 /**
345 * Tests responsive image formatters on node display linked to the node.
346 */
347 public function testResponsiveImageFieldFormattersLinkToNode() {
348 $this->addTestImageStyleMappings();
349 $this->assertResponsiveImageFieldFormattersLink('content');
350 }
351
352 /**
353 * Tests responsive image formatter on node display with an empty media query.
354 */
355 public function testResponsiveImageFieldFormattersEmptyMediaQuery() {
356 $this->responsiveImgStyle
357 // Test the output of an empty media query.
358 ->addImageStyleMapping('responsive_image_test_module.empty', '1x', [
359 'image_mapping_type' => 'image_style',
360 'image_mapping' => RESPONSIVE_IMAGE_EMPTY_IMAGE,
361 ])
362 // Test the output with a 1.5x multiplier.
363 ->addImageStyleMapping('responsive_image_test_module.mobile', '1x', [
364 'image_mapping_type' => 'image_style',
365 'image_mapping' => 'thumbnail',
366 ])
367 ->save();
368 $node_storage = $this->container->get('entity.manager')->getStorage('node');
369 $field_name = Unicode::strtolower($this->randomMachineName());
370 $this->createImageField($field_name, 'article', ['uri_scheme' => 'public']);
371 // Create a new node with an image attached.
372 $test_image = current($this->drupalGetTestFiles('image'));
373 $nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
374 $node_storage->resetCache([$nid]);
375
376 // Use the responsive image formatter linked to file formatter.
377 $display_options = [
378 'type' => 'responsive_image',
379 'settings' => [
380 'image_link' => '',
381 'responsive_image_style' => 'style_one',
382 ],
383 ];
384 $display = entity_get_display('node', 'article', 'default');
385 $display->setComponent($field_name, $display_options)
386 ->save();
387
388 // View the node.
389 $this->drupalGet('node/' . $nid);
390
391 // Assert an empty media attribute is not output.
392 $this->assertNoPattern('@srcset="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 1x".+?media=".+?/><source@');
393
394 // Assert the media attribute is present if it has a value.
395 $thumbnail_style = ImageStyle::load('thumbnail');
396 $node = $node_storage->load($nid);
397 $image_uri = File::load($node->{$field_name}->target_id)->getFileUri();
398 $this->assertPattern('/srcset="' . preg_quote(file_url_transform_relative($thumbnail_style->buildUrl($image_uri)), '/') . ' 1x".+?media="\(min-width: 0px\)"/');
399 }
400
401 /**
402 * Tests responsive image formatter on node display with one source.
403 */
404 public function testResponsiveImageFieldFormattersOneSource() {
405 $this->responsiveImgStyle
406 // Test the output of an empty media query.
407 ->addImageStyleMapping('responsive_image_test_module.empty', '1x', [
408 'image_mapping_type' => 'image_style',
409 'image_mapping' => 'medium',
410 ])
411 ->addImageStyleMapping('responsive_image_test_module.empty', '2x', [
412 'image_mapping_type' => 'image_style',
413 'image_mapping' => 'large',
414 ])
415 ->save();
416 $node_storage = $this->container->get('entity.manager')->getStorage('node');
417 $field_name = Unicode::strtolower($this->randomMachineName());
418 $this->createImageField($field_name, 'article', ['uri_scheme' => 'public']);
419 // Create a new node with an image attached.
420 $test_image = current($this->drupalGetTestFiles('image'));
421 $nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
422 $node_storage->resetCache([$nid]);
423
424 // Use the responsive image formatter linked to file formatter.
425 $display_options = [
426 'type' => 'responsive_image',
427 'settings' => [
428 'image_link' => '',
429 'responsive_image_style' => 'style_one',
430 ],
431 ];
432 $display = entity_get_display('node', 'article', 'default');
433 $display->setComponent($field_name, $display_options)
434 ->save();
435
436 // View the node.
437 $this->drupalGet('node/' . $nid);
438
439 // Assert the media attribute is present if it has a value.
440 $large_style = ImageStyle::load('large');
441 $medium_style = ImageStyle::load('medium');
442 $node = $node_storage->load($nid);
443 $image_uri = File::load($node->{$field_name}->target_id)->getFileUri();
444 $this->assertRaw('<img srcset="' . file_url_transform_relative($medium_style->buildUrl($image_uri)) . ' 1x, ' . file_url_transform_relative($large_style->buildUrl($image_uri)) . ' 2x"');
445 }
446
447 /**
448 * Tests responsive image formatters linked to the file or node.
449 *
450 * @param string $link_type
451 * The link type to test. Either 'file' or 'content'.
452 */
453 private function assertResponsiveImageFieldFormattersLink($link_type) {
454 $field_name = Unicode::strtolower($this->randomMachineName());
455 $field_settings = ['alt_field_required' => 0];
456 $this->createImageField($field_name, 'article', ['uri_scheme' => 'public'], $field_settings);
457 // Create a new node with an image attached.
458 $test_image = current($this->drupalGetTestFiles('image'));
459
460 // Test the image linked to file formatter.
461 $display_options = [
462 'type' => 'responsive_image',
463 'settings' => [
464 'image_link' => $link_type,
465 'responsive_image_style' => 'style_one',
466 ],
467 ];
468 entity_get_display('node', 'article', 'default')
469 ->setComponent($field_name, $display_options)
470 ->save();
471 // Ensure that preview works.
472 $this->previewNodeImage($test_image, $field_name, 'article');
473
474 // Look for a picture tag in the preview output
475 $this->assertPattern('/picture/');
476
477 $nid = $this->uploadNodeImage($test_image, $field_name, 'article');
478 $this->container->get('entity.manager')->getStorage('node')->resetCache([$nid]);
479 $node = Node::load($nid);
480
481 // Use the responsive image formatter linked to file formatter.
482 $display_options = [
483 'type' => 'responsive_image',
484 'settings' => [
485 'image_link' => $link_type,
486 'responsive_image_style' => 'style_one',
487 ],
488 ];
489 entity_get_display('node', 'article', 'default')
490 ->setComponent($field_name, $display_options)
491 ->save();
492
493 // Create a derivative so at least one MIME type will be known.
494 $large_style = ImageStyle::load('large');
495 $image_uri = File::load($node->{$field_name}->target_id)->getFileUri();
496 $large_style->createDerivative($image_uri, $large_style->buildUri($image_uri));
497
498 // Output should contain all image styles and all breakpoints.
499 $this->drupalGet('node/' . $nid);
500 $this->removeWhiteSpace();
501 switch ($link_type) {
502 case 'file':
503 // Make sure the link to the file is present.
504 $this->assertPattern('/<a(.*?)href="' . preg_quote(file_url_transform_relative(file_create_url($image_uri)), '/') . '"(.*?)><picture/');
505 break;
506
507 case 'content':
508 // Make sure the link to the node is present.
509 $this->assertPattern('/<a(.*?)href="' . preg_quote($node->url(), '/') . '"(.*?)><picture/');
510 break;
511 }
512 }
513
514 }