You are here

public function ThemeNotUsingClassyLibraryTest::testThemeNotUsingClassyLibraries in Drupal 8

Ensures that a theme is decoupled from Classy libraries.

This confirms that none of the libraries defined in classy.libraries.yml are loaded by the current theme. For this to happen, the current theme must override the Classy library so no assets from Classy are loaded.

@dataProvider providerTestThemeNotUsingClassyLibraries

Parameters

string $theme: The theme being tested.

string[] $libraries_to_skip: Libraries excluded from the test.

File

core/tests/Drupal/KernelTests/Core/Theme/ThemeNotUsingClassyLibraryTest.php, line 95

Class

ThemeNotUsingClassyLibraryTest
Tests that themes do not depend on Classy libraries.

Namespace

Drupal\KernelTests\Core\Theme

Code

public function testThemeNotUsingClassyLibraries($theme, array $libraries_to_skip) {

  // In some cases an overridden Classy library does not use any copied assets
  // from Classy. This array collects those so this test knows to skip
  // assertions specific to those copied assets.
  $skip_asset_matching_assertions = [];
  $theme_path = $this->themeHandler
    ->getTheme($theme)
    ->getPath();

  // A list of all libraries that the current theme is overriding. In a
  // theme's info.yml file, these are the libraries listed in
  // `libraries-override:`, and are libraries altered by the current theme.
  // This will be used for confirming that all of Classy's libraries are
  // overridden.
  $theme_library_overrides = $this->themeInitialization
    ->getActiveThemeByName($theme)
    ->getLibrariesOverride()[$theme_path] ?? [];

  // A list of all libraries created by the current theme.
  $theme_libraries = $this->libraryDiscovery
    ->getLibrariesByExtension($theme);
  $this
    ->assertNotEmpty($theme_libraries);

  // Loop through all libraries overridden by the theme. For those that are
  // Classy libraries, confirm that the overrides prevent the loading of any
  // Classy asset.
  foreach ($theme_library_overrides as $library_name => $library_definition) {
    $in_skip_list = in_array(str_replace('classy/', '', $library_name), $libraries_to_skip);

    // If the library name does not begin with `classy/`, it's not a Classy
    // library.
    $not_classy_library = substr($library_name, 0, 7) !== 'classy/';

    // If $library_definition is false or a string, the override is preventing
    // the Classy library from loading altogether.
    $library_fully_replaced = $library_definition === FALSE || gettype($library_definition) === 'string';

    // If the library is fully replaced, it may need to be added to the
    // $skip_asset_matching_assertions array.
    if ($library_fully_replaced) {

      // Libraries with names that begin with `$theme/classy.` are copies of
      // Classy libraries.
      $not_copied_from_classy = gettype($library_definition) === 'string' && substr($library_definition, 0, 8 + strlen($theme)) !== "{$theme}/classy.";

      // If the overridden library is not copied from Classy or is FALSE (i.e.
      // not loaded at all), it is customized and should skip the tests that
      // check for a 1:1 asset match between the Classy library and its
      // override in the current theme.
      if ($library_definition === FALSE || $not_copied_from_classy) {
        $skip_asset_matching_assertions[] = $library_name;
      }
    }

    // If any of these three conditions are true, there's no need for the
    // remaining asset-specific assertions in this loop.
    if ($in_skip_list || $not_classy_library || $library_fully_replaced) {
      continue;
    }

    // If the library override has a 'css' key, some Classy CSS files may
    // still be loading. Confirm this is not the case.
    if (isset($library_definition['css'])) {
      $this
        ->confirmNoClassyAssets($library_name, $library_definition, 'css');

      // If the override has no JS and all Classy CSS is accounted for, add it
      // to the list of libraries already fully overridden. It won't be
      // necessary to copy the library from Classy.
      if (!isset($library_definition['js'])) {
        $skip_asset_matching_assertions[] = $library_name;
      }
    }
    if (isset($library_definition['js'])) {
      $this
        ->confirmNoClassyAssets($library_name, $library_definition, 'js');

      // CSS has already been checked. So, if all JS in the library is
      // accounted for, add it to the list of libraries already fully
      // overridden. It won't be necessary to copy the library from Classy.
      $skip_asset_matching_assertions[] = $library_name;
    }
  }

  // Confirm that every Classy library is copied or fully overridden by the
  // current theme.
  foreach ($this->classyLibraries as $classy_library_name => $classy_library) {

    // If a Classy library is in the $skip_asset_matching_assertions
    // array, it does not use any assets copied from Classy and can skip the
    // tests in this loop.
    $fully_overridden = in_array("classy/{$classy_library_name}", $skip_asset_matching_assertions);
    $skip = in_array($classy_library_name, $libraries_to_skip);
    if ($skip || $fully_overridden) {
      continue;
    }

    // Confirm the Classy Library is overridden so assets aren't loaded twice.
    $this
      ->assertArrayHasKey("classy/{$classy_library_name}", $theme_library_overrides, "The classy/{$classy_library_name} library is not overridden in {$theme}");

    // Confirm there is a theme-specific version of the Classy library.
    $this
      ->assertArrayHasKey("classy.{$classy_library_name}", $theme_libraries, "There is not a {$theme} equivalent for classy/{$classy_library_name}");
    $theme_copy_of_classy_library = $theme_libraries["classy.{$classy_library_name}"];

    // If the Classy library includes CSS, confirm the theme's copy has the
    // same CSS with the same properties.
    if (!empty($classy_library['css'])) {
      $this
        ->confirmMatchingAssets($classy_library_name, $classy_library, $theme_copy_of_classy_library, $theme_path, 'css');
    }

    // If the Classy library includes JavaScript, confirm the theme's copy has
    // the same JavaScript with the same properties.
    if (!empty($classy_library['js'])) {
      $this
        ->confirmMatchingAssets($classy_library_name, $classy_library, $theme_copy_of_classy_library, $theme_path, 'js');
    }
  }
}