LibraryDiscoveryParserTest.php 12.7 KB
Newer Older
1 2 3 4 5 6 7 8 9
<?php

/**
 * @file
 * Contains \Drupal\Tests\Core\Asset\LibraryDiscoveryTest.
 */

namespace Drupal\Tests\Core\Asset;

10
use Drupal\Core\Asset\LibraryDiscoveryParser;
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
use Drupal\Tests\UnitTestCase;

if (!defined('DRUPAL_ROOT')) {
  define('DRUPAL_ROOT', dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)))));
}

if (!defined('CSS_AGGREGATE_DEFAULT')) {
  define('CSS_AGGREGATE_DEFAULT', 0);
  define('CSS_AGGREGATE_THEME', 100);
  define('CSS_BASE', -200);
  define('CSS_LAYOUT', -100);
  define('CSS_COMPONENT', 0);
  define('CSS_STATE', 100);
  define('CSS_THEME', 200);
  define('JS_SETTING', -200);
  define('JS_LIBRARY', -100);
  define('JS_DEFAULT', 0);
  define('JS_THEME', 100);
}

/**
32
 * Tests the library discovery parser.
33
 *
34
 * @coversDefaultClass \Drupal\Core\Asset\LibraryDiscoveryParser
35
 */
36
class LibraryDiscoveryParserTest extends UnitTestCase {
37 38 39 40

  /**
   * The tested library provider.
   *
41
   * @var \Drupal\Core\Asset\LibraryDiscoveryParser|\Drupal\Tests\Core\Asset\TestLibraryDiscoveryParser
42
   */
43
  protected $libraryDiscoveryParser;
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

  /**
   * The mocked cache backend.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
   */
  protected $cache;

  /**
   * The mocked module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
   */
  protected $moduleHandler;

  /**
60
   * The mocked lock backend..
61
   *
62
   * @var \Drupal\Core\Lock\LockBackendInterface|\PHPUnit_Framework_MockObject_MockObject
63
   */
64
  protected $lock;
65 66 67 68 69 70

  /**
   * {@inheritdoc}
   */
  public static function getInfo() {
    return array(
71
      'name' => 'Tests \Drupal\Core\Asset\LibraryDiscoveryParser',
72 73 74 75 76 77 78 79 80 81
      'description' => '',
      'group' => 'Asset handling',
    );
  }

  /**
   * {@inheritdoc}
   */
  protected function setUp() {
    $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
82
    $this->libraryDiscoveryParser = new TestLibraryDiscoveryParser($this->moduleHandler);
83 84 85 86 87
  }

  /**
   * Tests that basic functionality works for getLibraryByName.
   *
88
   * @covers ::buildByExtension()
89
   */
90
  public function testBuildLibrariesByExtensionSimple() {
91 92 93 94 95 96 97
    $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('example_module')
      ->will($this->returnValue(TRUE));

    $path = __DIR__ . '/library_test_files';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
98 99 100 101
    $this->libraryDiscoveryParser->setPaths('module', 'example_module', $path);

    $libraries = $this->libraryDiscoveryParser->buildByExtension('example_module', 'example');
    $library = $libraries['example'];
102 103 104 105 106 107 108 109 110 111 112 113 114

    $this->assertCount(0, $library['js']);
    $this->assertCount(1, $library['css']);
    $this->assertCount(0, $library['dependencies']);
    $this->assertEquals($path . '/css/example.css', $library['css'][0]['data']);

    // Ensures that VERSION is replaced by the current core version.
    $this->assertEquals(\Drupal::VERSION, $library['version']);
  }

  /**
   * Tests that a theme can be used instead of a module.
   *
115
   * @covers ::buildByExtension()
116
   */
117
  public function testBuildLibrariesByExtensionWithTheme() {
118 119 120 121 122 123 124
    $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('example_theme')
      ->will($this->returnValue(FALSE));

    $path = __DIR__ . '/library_test_files';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
125 126 127 128
    $this->libraryDiscoveryParser->setPaths('theme', 'example_theme', $path);

    $libraries = $this->libraryDiscoveryParser->buildByExtension('example_theme');
    $library = $libraries['example'];
129 130 131 132 133 134 135 136 137 138

    $this->assertCount(0, $library['js']);
    $this->assertCount(1, $library['css']);
    $this->assertCount(0, $library['dependencies']);
    $this->assertEquals($path . '/css/example.css', $library['css'][0]['data']);
  }

  /**
   * Tests that a module with a missing library file results in FALSE.
   *
139
   * @covers ::buildByExtension()
140
   */
141
  public function testBuildLibrariesByExtensionWithMissingLibraryFile() {
142 143 144 145 146 147 148
    $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('example_module')
      ->will($this->returnValue(TRUE));

    $path = __DIR__ . '/library_test_files_not_existing';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
149
    $this->libraryDiscoveryParser->setPaths('module', 'example_module', $path);
150

151
    $this->assertSame($this->libraryDiscoveryParser->buildByExtension('example_module'), array());
152 153 154 155 156 157 158
  }

  /**
   * Tests that an exception is thrown when a libraries file couldn't be parsed.
   *
   * @expectedException \Drupal\Core\Asset\Exception\InvalidLibraryFileException
   *
159
   * @covers ::buildByExtension()
160 161 162 163 164 165 166 167 168
   */
  public function testInvalidLibrariesFile() {
    $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('invalid_file')
      ->will($this->returnValue(TRUE));

    $path = __DIR__ . '/library_test_files';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
169
    $this->libraryDiscoveryParser->setPaths('module', 'invalid_file', $path);
170

171
    $this->libraryDiscoveryParser->buildByExtension('invalid_file');
172 173 174 175 176 177 178 179
  }

  /**
   * Tests that an exception is thrown when no CSS/JS/setting is specified.
   *
   * @expectedException \Drupal\Core\Asset\Exception\IncompleteLibraryDefinitionException
   * @expectedExceptionMessage Incomplete library definition for 'example' in core/tests/Drupal/Tests/Core/Asset/library_test_files/example_module_missing_information.libraries.yml
   *
180
   * @covers ::buildByExtension()
181
   */
182
  public function testBuildLibrariesByExtensionWithMissingInformation() {
183 184 185 186 187 188 189
    $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('example_module_missing_information')
      ->will($this->returnValue(TRUE));

    $path = __DIR__ . '/library_test_files';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
190
    $this->libraryDiscoveryParser->setPaths('module', 'example_module_missing_information', $path);
191

192
    $this->libraryDiscoveryParser->buildByExtension('example_module_missing_information');
193 194 195 196 197
  }

  /**
   * Tests that the version property of external libraries is handled.
   *
198
   * @covers ::buildByExtension()
199 200 201 202 203 204 205 206 207
   */
  public function testExternalLibraries() {
    $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('external')
      ->will($this->returnValue(TRUE));

    $path = __DIR__ . '/library_test_files';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
208 209 210 211
    $this->libraryDiscoveryParser->setPaths('module', 'external', $path);

    $libraries = $this->libraryDiscoveryParser->buildByExtension('external', 'example_external');
    $library = $libraries['example_external'];
212 213 214 215 216 217 218 219

    $this->assertEquals($path . '/css/example_external.css', $library['css'][0]['data']);
    $this->assertEquals('3.14', $library['version']);
  }

  /**
   * Ensures that CSS weights are taken into account properly.
   *
220
   * @covers ::buildByExtension()
221 222 223 224 225 226 227 228 229
   */
  public function testDefaultCssWeights() {
    $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('css_weights')
      ->will($this->returnValue(TRUE));

    $path = __DIR__ . '/library_test_files';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
230
    $this->libraryDiscoveryParser->setPaths('module', 'css_weights', $path);
231

232 233
    $libraries = $this->libraryDiscoveryParser->buildByExtension('css_weights');
    $library = $libraries['example'];
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
    $css = $library['css'];
    $this->assertCount(10, $css);

    // The following default weights are tested:
    // - CSS_BASE: -200
    // - CSS_LAYOUT: -100
    // - CSS_COMPONENT: 0
    // - CSS_STATE: 100
    // - CSS_THEME: 200
    $this->assertEquals(200, $css[0]['weight']);
    $this->assertEquals(200 + 29, $css[1]['weight']);
    $this->assertEquals(-200, $css[2]['weight']);
    $this->assertEquals(-200 + 97, $css[3]['weight']);
    $this->assertEquals(-100, $css[4]['weight']);
    $this->assertEquals(-100 + 92, $css[5]['weight']);
    $this->assertEquals(0, $css[6]['weight']);
    $this->assertEquals(45, $css[7]['weight']);
    $this->assertEquals(100, $css[8]['weight']);
    $this->assertEquals(100 + 8, $css[9]['weight']);
  }

  /**
   * Ensures that you cannot provide positive weights for JavaScript libraries.
   *
   * @expectedException \UnexpectedValueException
   *
260
   * @covers ::buildByExtension()
261 262 263 264 265 266 267 268 269
   */
  public function testJsWithPositiveWeight() {
    $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('js_positive_weight')
      ->will($this->returnValue(TRUE));

    $path = __DIR__ . '/library_test_files';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
270
    $this->libraryDiscoveryParser->setPaths('module', 'js_positive_weight', $path);
271

272
    $this->libraryDiscoveryParser->buildByExtension('js_positive_weight');
273 274 275 276 277
  }

  /**
   * Tests a library with CSS/JavaScript and a setting.
   *
278
   * @covers ::buildByExtension()
279 280 281 282 283 284 285 286 287
   */
  public function testLibraryWithCssJsSetting() {
    $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('css_js_settings')
      ->will($this->returnValue(TRUE));

    $path = __DIR__ . '/library_test_files';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
288
    $this->libraryDiscoveryParser->setPaths('module', 'css_js_settings', $path);
289

290 291
    $libraries = $this->libraryDiscoveryParser->buildByExtension('css_js_settings');
    $library = $libraries['example'];
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

    // Ensures that the group and type are set automatically.
    $this->assertEquals(-100, $library['js'][0]['group']);
    $this->assertEquals('file', $library['js'][0]['type']);
    $this->assertEquals($path . '/js/example.js', $library['js'][0]['data']);

    $this->assertEquals(0, $library['css'][0]['group']);
    $this->assertEquals('file', $library['css'][0]['type']);
    $this->assertEquals($path . '/css/base.css', $library['css'][0]['data']);

    $this->assertEquals('setting', $library['js'][1]['type']);
    $this->assertEquals(array('key' => 'value'), $library['js'][1]['data']);
  }

  /**
   * Tests a library with dependencies.
   *
309
   * @covers ::buildByExtension()
310 311 312 313 314 315 316 317 318
   */
  public function testLibraryWithDependencies() {
     $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('dependencies')
      ->will($this->returnValue(TRUE));

    $path = __DIR__ . '/library_test_files';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
319 320 321 322
    $this->libraryDiscoveryParser->setPaths('module', 'dependencies', $path);

    $libraries = $this->libraryDiscoveryParser->buildByExtension('dependencies');
    $library = $libraries['example'];
323 324 325 326 327 328 329 330 331

    $this->assertCount(2, $library['dependencies']);
    $this->assertEquals('external/example_external', $library['dependencies'][0]);
    $this->assertEquals('example_module/example', $library['dependencies'][1]);
  }

  /**
   * Tests a library with a couple of data formats like full URL.
   *
332
   * @covers ::buildByExtension()
333 334 335 336 337 338 339 340 341
   */
  public function testLibraryWithDataTypes() {
    $this->moduleHandler->expects($this->atLeastOnce())
      ->method('moduleExists')
      ->with('data_types')
      ->will($this->returnValue(TRUE));

    $path = __DIR__ . '/library_test_files';
    $path = substr($path, strlen(DRUPAL_ROOT) + 1);
342
    $this->libraryDiscoveryParser->setPaths('module', 'data_types', $path);
343

344 345 346 347 348
    $this->libraryDiscoveryParser->setFileValidUri('public://test.css', TRUE);
    $this->libraryDiscoveryParser->setFileValidUri('public://test2.css', FALSE);

    $libraries = $this->libraryDiscoveryParser->buildByExtension('data_types');
    $library = $libraries['example'];
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365

    $this->assertCount(5, $library['css']);
    $this->assertEquals('external', $library['css'][0]['type']);
    $this->assertEquals('http://example.com/test.css', $library['css'][0]['data']);
    $this->assertEquals('file', $library['css'][1]['type']);
    $this->assertEquals('tmp/test.css', $library['css'][1]['data']);
    $this->assertEquals('external', $library['css'][2]['type']);
    $this->assertEquals('//cdn.com/test.css', $library['css'][2]['data']);
    $this->assertEquals('file', $library['css'][3]['type']);
    $this->assertEquals('public://test.css', $library['css'][3]['data']);
  }

}

/**
 * Wraps the tested class to mock the external dependencies.
 */
366
class TestLibraryDiscoveryParser extends LibraryDiscoveryParser {
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388

  protected $paths;

  protected $validUris;

  protected function drupalGetPath($type, $name) {
    return isset($this->paths[$type][$name]) ? $this->paths[$type][$name] : NULL;
  }

  public function setPaths($type, $name, $path) {
    $this->paths[$type][$name] = $path;
  }

  protected function fileValidUri($source) {
    return isset($this->validUris[$source]) ? $this->validUris[$source] : FALSE;
  }

  public function setFileValidUri($source, $valid) {
    $this->validUris[$source] = $valid;
  }

}