Make WordPress Core


Ignore:
Timestamp:
09/25/2023 09:03:19 PM (3 years ago)
Author:
westonruter
Message:

Script Loader: Use wp_get_script_tag() and wp_get_inline_script_tag()/wp_print_inline_script_tag() helper functions to output scripts on the frontend and login screen.

Using script tag helper functions allows plugins to employ the wp_script_attributes and wp_inline_script_attributes filters to inject the nonce attribute to apply Content Security Policy (e.g. Strict CSP). Use of helper functions also simplifies logic in WP_Scripts.

  • Update wp_get_inline_script_tag() to wrap inline script in CDATA blocks for XHTML-compatibility when not using HTML5.
  • Ensure the type attribute is printed first in wp_get_inline_script_tag() for back-compat.
  • Wrap existing <script> tags in output buffering to retain IDE supports.
  • In wp_get_inline_script_tag(), append the newline to $javascript before it is passed into the wp_inline_script_attributes filter so that the CSP hash can be computed properly.
  • In the_block_template_skip_link(), opt to enqueue the inline script rather than print it.
  • Add ext-php to composer.json under suggest as previously it was an undeclared dependency for running PHPUnit tests.
  • Update tests to rely on DOMDocument to compare script markup, normalizing unsemantic differences.

Props westonruter, spacedmonkey, flixos90, 10upsimon, dmsnell, mukesh27, joemcgill, swissspidy, azaozz.
Fixes #58664.
See #39941.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/dependencies/scripts.php

    r56559 r56687  
    4343                $this->wp_scripts_print_translations_output  = <<<JS
    4444<script type='text/javascript' id='__HANDLE__-js-translations'>
     45/* <![CDATA[ */
    4546( function( domain, translations ) {
    4647        var localeData = translations.locale_data[ domain ] || translations.locale_data.messages;
    … …  
    4849        wp.i18n.setLocaleData( localeData, domain );
    4950} )( "__DOMAIN__", __JSON_TRANSLATIONS__ );
     51/* ]]> */
    5052</script>
    5153JS;
    … …  
    7880                $expected .= "<script type='text/javascript' src='http://example.com' id='empty-deps-null-version-js'></script>\n";
    7981
    80                 $this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
     82                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    8183
    8284                // No scripts left to print.
    … …  
    119121                $expected  = "<script type='text/javascript' src='http://example.org/ms-isa-1.js' id='ms-isa-1-js' data-wp-strategy='{$strategy}'></script>\n";
    120122                $expected .= wp_get_inline_script_tag(
    121                         "console.log(\"after one\");\n",
     123                        'console.log("after one");',
    122124                        array(
    123125                                'id' => 'ms-isa-1-js-after',
    124126                        )
    125127                );
    126                 $this->assertSame( $expected, $output, 'Inline scripts in the "after" position, that are attached to a deferred main script, are failing to print/execute.' );
     128                $this->assertEqualMarkup( $expected, $output, 'Inline scripts in the "after" position, that are attached to a deferred main script, are failing to print/execute.' );
    127129        }
    128130
    … …  
    147149                $expected  = "<script type='text/javascript' src='http://example.org/ms-insa-3.js' id='ms-insa-3-js'></script>\n";
    148150                $expected .= wp_get_inline_script_tag(
    149                         "console.log(\"after one\");\n",
     151                        'console.log("after one");',
    150152                        array(
    151153                                'id' => 'ms-insa-3-js-after',
    … …  
    153155                );
    154156
    155                 $this->assertSame( $expected, $output, 'Inline scripts in the "after" position, that are attached to a blocking main script, are failing to print/execute.' );
     157                $this->assertEqualMarkup( $expected, $output, 'Inline scripts in the "after" position, that are attached to a blocking main script, are failing to print/execute.' );
    156158        }
    157159
    … …  
    181183
    182184                $expected  = wp_get_inline_script_tag(
    183                         "console.log(\"before first\");\n",
     185                        'console.log("before first");',
    184186                        array(
    185187                                'id' => 'ds-i1-1-js-before',
    … …  
    190192                $expected .= "<script type='text/javascript' src='http://example.org/ds-i1-3.js' id='ds-i1-3-js' $strategy data-wp-strategy='{$strategy}'></script>\n";
    191193                $expected .= wp_get_inline_script_tag(
    192                         "console.log(\"before last\");\n",
     194                        'console.log("before last");',
    193195                        array(
    194196                                'id'   => 'ms-i1-1-js-before',
    … …  
    198200                $expected .= "<script type='text/javascript' src='http://example.org/ms-i1-1.js' id='ms-i1-1-js' {$strategy} data-wp-strategy='{$strategy}'></script>\n";
    199201
    200                 $this->assertSame( $expected, $output, 'Inline scripts in the "before" position, that are attached to a deferred main script, are failing to print/execute.' );
     202                $this->assertEqualMarkup( $expected, $output, 'Inline scripts in the "before" position, that are attached to a deferred main script, are failing to print/execute.' );
    201203        }
    202204
    … …  
    216218                $output   = get_echo( 'wp_print_scripts' );
    217219                $expected = "<script type='text/javascript' src='/main-script-a1.js' id='main-script-a1-js' async data-wp-strategy='async'></script>\n";
    218                 $this->assertSame( $expected, $output, 'Scripts enqueued with an async loading strategy are failing to have the async attribute applied to the script handle when being printed.' );
     220                $this->assertEqualMarkup( $expected, $output, 'Scripts enqueued with an async loading strategy are failing to have the async attribute applied to the script handle when being printed.' );
    219221        }
    220222
    … …  
    236238                wp_enqueue_script( 'dependency-script-a2', '/dependency-script-a2.js', array(), null );
    237239                wp_enqueue_script( 'main-script-a2', '/main-script-a2.js', array( 'dependency-script-a2' ), null, compact( 'strategy' ) );
    238                 $output   = get_echo( 'wp_print_scripts' );
    239                 $expected = "<script type='text/javascript' src='/main-script-a2.js' id='main-script-a2-js' {$strategy} data-wp-strategy='{$strategy}'></script>";
    240                 $this->assertStringContainsString( $expected, $output, 'Dependents of a blocking dependency are free to have any strategy.' );
     240                $output    = get_echo( 'wp_print_scripts' );
     241                $expected  = "<script id='dependency-script-a2-js' src='/dependency-script-a2.js'></script>\n";
     242                $expected .= "<script type='text/javascript' src='/main-script-a2.js' id='main-script-a2-js' {$strategy} data-wp-strategy='{$strategy}'></script>";
     243                $this->assertEqualMarkup( $expected, $output, 'Dependents of a blocking dependency are free to have any strategy.' );
    241244        }
    242245
    … …  
    258261                wp_enqueue_script( 'dependent-script-a3', '/dependent-script-a3.js', array( 'main-script-a3' ), null );
    259262                $output   = get_echo( 'wp_print_scripts' );
    260                 $expected = "<script type='text/javascript' src='/main-script-a3.js' id='main-script-a3-js' data-wp-strategy='{$strategy}'></script>";
     263                $expected = str_replace( "'", '"', "<script type='text/javascript' src='/main-script-a3.js' id='main-script-a3-js' data-wp-strategy='{$strategy}'></script>" );
    261264                $this->assertStringContainsString( $expected, $output, 'Blocking dependents must force delayed dependencies to become blocking.' );
    262265        }
    … …  
    276279         */
    277280        public function test_delayed_dependent_with_blocking_dependency_not_enqueued( $strategy ) {
     281                $this->add_html5_script_theme_support();
    278282                wp_enqueue_script( 'main-script-a4', '/main-script-a4.js', array(), null, compact( 'strategy' ) );
    279283                // This dependent is registered but not enqueued, so it should not factor into the eligible loading strategy.
    280284                wp_register_script( 'dependent-script-a4', '/dependent-script-a4.js', array( 'main-script-a4' ), null );
    281285                $output   = get_echo( 'wp_print_scripts' );
    282                 $expected = "<script type='text/javascript' src='/main-script-a4.js' id='main-script-a4-js' {$strategy} data-wp-strategy='{$strategy}'></script>";
     286                $expected = str_replace( "'", '"', "<script src='/main-script-a4.js' id='main-script-a4-js' {$strategy} data-wp-strategy='{$strategy}'></script>" );
    283287                $this->assertStringContainsString( $expected, $output, 'Only enqueued dependents should affect the eligible strategy.' );
    284288        }
    … …  
    965969         */
    966970        public function test_loading_strategy_with_defer_having_no_dependents_nor_dependencies() {
     971                $this->add_html5_script_theme_support();
    967972                wp_enqueue_script( 'main-script-d1', 'http://example.com/main-script-d1.js', array(), null, array( 'strategy' => 'defer' ) );
    968973                $output   = get_echo( 'wp_print_scripts' );
    969                 $expected = "<script type='text/javascript' src='http://example.com/main-script-d1.js' id='main-script-d1-js' defer data-wp-strategy='defer'></script>\n";
     974                $expected = str_replace( "'", '"', "<script src='http://example.com/main-script-d1.js' id='main-script-d1-js' defer data-wp-strategy='defer'></script>\n" );
    970975                $this->assertStringContainsString( $expected, $output, 'Expected defer, as there is no dependent or dependency' );
    971976        }
    … …  
    981986         */
    982987        public function test_loading_strategy_with_defer_dependent_and_varied_dependencies() {
     988                $this->add_html5_script_theme_support();
    983989                wp_enqueue_script( 'dependency-script-d2-1', 'http://example.com/dependency-script-d2-1.js', array(), null, array( 'strategy' => 'defer' ) );
    984990                wp_enqueue_script( 'dependency-script-d2-2', 'http://example.com/dependency-script-d2-2.js', array(), null );
    … …  
    986992                wp_enqueue_script( 'main-script-d2', 'http://example.com/main-script-d2.js', array( 'dependency-script-d2-1', 'dependency-script-d2-3' ), null, array( 'strategy' => 'defer' ) );
    987993                $output   = get_echo( 'wp_print_scripts' );
    988                 $expected = "<script type='text/javascript' src='http://example.com/main-script-d2.js' id='main-script-d2-js' defer data-wp-strategy='defer'></script>\n";
     994                $expected = '<script src="http://example.com/main-script-d2.js" id="main-script-d2-js" defer data-wp-strategy="defer"></script>';
    989995                $this->assertStringContainsString( $expected, $output, 'Expected defer, as all dependencies are either deferred or blocking' );
    990996        }
    … …  
    10001006         */
    10011007        public function test_loading_strategy_with_all_defer_dependencies() {
     1008                $this->add_html5_script_theme_support();
    10021009                wp_enqueue_script( 'main-script-d3', 'http://example.com/main-script-d3.js', array(), null, array( 'strategy' => 'defer' ) );
    10031010                wp_enqueue_script( 'dependent-script-d3-1', 'http://example.com/dependent-script-d3-1.js', array( 'main-script-d3' ), null, array( 'strategy' => 'defer' ) );
    … …  
    10051012                wp_enqueue_script( 'dependent-script-d3-3', 'http://example.com/dependent-script-d3-3.js', array( 'dependent-script-d3-2' ), null, array( 'strategy' => 'defer' ) );
    10061013                $output   = get_echo( 'wp_print_scripts' );
    1007                 $expected = "<script type='text/javascript' src='http://example.com/main-script-d3.js' id='main-script-d3-js' defer data-wp-strategy='defer'></script>\n";
     1014                $expected = '<script src="http://example.com/main-script-d3.js" id="main-script-d3-js" defer data-wp-strategy="defer"></script>';
    10081015                $this->assertStringContainsString( $expected, $output, 'Expected defer, as all dependents have defer loading strategy' );
    10091016        }
    … …  
    10301037                $expected .= "<script type='text/javascript' src='/dependent-script-d4-3.js' id='dependent-script-d4-3-js' defer data-wp-strategy='defer'></script>\n";
    10311038
    1032                 $this->assertSame( $expected, $output, 'Scripts registered as defer but that have dependents that are async are expected to have said dependents deferred.' );
     1039                $this->assertEqualMarkup( $expected, $output, 'Scripts registered as defer but that have dependents that are async are expected to have said dependents deferred.' );
    10331040        }
    10341041
    … …  
    10501057                wp_enqueue_script( 'dependent-script-d4-3', '/dependent-script-d4-3.js', array( 'dependent-script-d4-2' ), null, array( 'strategy' => 'defer' ) );
    10511058                $output   = get_echo( 'wp_print_scripts' );
    1052                 $expected = "<script type='text/javascript' src='/main-script-d4.js' id='main-script-d4-js' data-wp-strategy='defer'></script>\n";
     1059                $expected = str_replace( "'", '"', "<script type='text/javascript' src='/main-script-d4.js' id='main-script-d4-js' data-wp-strategy='defer'></script>\n" );
    10531060                $this->assertStringContainsString( $expected, $output, 'Scripts registered as defer but that have all dependents with no strategy, should become blocking (no strategy).' );
    10541061        }
    … …  
    10681075                $output   = get_echo( 'wp_print_scripts' );
    10691076                $expected = "<script type='text/javascript' src='/main-script-b1.js' id='main-script-b1-js'></script>\n";
     1077                $expected = str_replace( "'", '"', $expected );
    10701078                $this->assertSame( $expected, $output, 'Scripts registered with a "blocking" strategy, and who have no dependencies, should have no loading strategy attributes printed.' );
    10711079
    … …  
    10741082                $output   = get_echo( 'wp_print_scripts' );
    10751083                $expected = "<script type='text/javascript' src='/main-script-b2.js' id='main-script-b2-js'></script>\n";
     1084                $expected = str_replace( "'", '"', $expected );
    10761085                $this->assertSame( $expected, $output, 'Scripts registered with no strategy assigned, and who have no dependencies, should have no loading strategy attributes printed.' );
    10771086        }
    … …  
    11001109                $expected_header .= "<script type='text/javascript' src='/enqueue-header-new.js' id='enqueue-header-new-js'></script>\n";
    11011110
    1102                 $this->assertSame( $expected_header, $actual_header, 'Scripts registered/enqueued using the older $in_footer parameter or the newer $args parameter should have the same outcome.' );
     1111                $this->assertEqualMarkup( $expected_header, $actual_header, 'Scripts registered/enqueued using the older $in_footer parameter or the newer $args parameter should have the same outcome.' );
    11031112                $this->assertEmpty( $actual_footer, 'Expected footer to be empty since all scripts were for head.' );
    11041113        }
    … …  
    11281137
    11291138                $this->assertEmpty( $actual_header, 'Expected header to be empty since all scripts targeted footer.' );
    1130                 $this->assertSame( $expected_footer, $actual_footer, 'Scripts registered/enqueued using the older $in_footer parameter or the newer $args parameter should have the same outcome.' );
     1139                $this->assertEqualMarkup( $expected_footer, $actual_footer, 'Scripts registered/enqueued using the older $in_footer parameter or the newer $args parameter should have the same outcome.' );
    11311140        }
    11321141
    … …  
    12471256                wp_enqueue_script( 'invalid-strategy' );
    12481257
    1249                 $this->assertSame(
     1258                $this->assertEqualMarkup(
    12501259                        "<script type='text/javascript' src='/defaults.js' id='invalid-strategy-js'></script>\n",
    12511260                        get_echo( 'wp_print_scripts' )
    … …  
    12721281                wp_enqueue_script( 'invalid-strategy' );
    12731282
    1274                 $this->assertSame(
     1283                $this->assertEqualMarkup(
    12751284                        "<script type='text/javascript' src='/defaults.js' id='invalid-strategy-js'></script>\n",
    12761285                        get_echo( 'wp_print_scripts' )
    … …  
    12931302                wp_enqueue_script( 'invalid-strategy', '/defaults.js', array(), null, array( 'strategy' => 'random-strategy' ) );
    12941303
    1295                 $this->assertSame(
     1304                $this->assertEqualMarkup(
    12961305                        "<script type='text/javascript' src='/defaults.js' id='invalid-strategy-js'></script>\n",
    12971306                        get_echo( 'wp_print_scripts' )
    … …  
    13311340                $expected .= "<script type='text/javascript' src='/main-script.js' id='main-defer-script-js' defer data-wp-strategy='defer'></script>\n";
    13321341
    1333                 $this->assertSame( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered with a "defer" loading strategy. Deferred scripts should not be part of the script concat loading query.' );
     1342                $this->assertEqualMarkup( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered with a "defer" loading strategy. Deferred scripts should not be part of the script concat loading query.' );
    13341343        }
    13351344
    … …  
    13661375                $expected .= "<script type='text/javascript' src='/main-script.js' id='main-async-script-1-js' async data-wp-strategy='async'></script>\n";
    13671376
    1368                 $this->assertSame( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered with an "async" loading strategy. Async scripts should not be part of the script concat loading query.' );
     1377                $this->assertEqualMarkup( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered with an "async" loading strategy. Async scripts should not be part of the script concat loading query.' );
    13691378        }
    13701379
    … …  
    14051414                $expected .= "<script type='text/javascript' src='/main-script.js' id='deferred-script-2-js' defer data-wp-strategy='defer'></script>\n";
    14061415
    1407                 $this->assertSame( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered as deferred after other blocking scripts are registered. Deferred scripts should not be part of the script concat loader query string. ' );
     1416                $this->assertEqualMarkup( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered as deferred after other blocking scripts are registered. Deferred scripts should not be part of the script concat loader query string. ' );
    14081417        }
    14091418
    … …  
    14131422        public function test_wp_enqueue_script_with_html5_support_does_not_contain_type_attribute() {
    14141423                global $wp_version;
    1415                 add_theme_support( 'html5', array( 'script' ) );
    14161424
    14171425                $GLOBALS['wp_scripts']                  = new WP_Scripts();
    … …  
    14221430                $expected = "<script src='http://example.com?ver={$wp_version}' id='empty-deps-no-version-js'></script>\n";
    14231431
    1424                 $this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
     1432                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    14251433        }
    14261434
    … …  
    14611469
    14621470                // Go!
    1463                 $this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
     1471                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    14641472
    14651473                // No scripts left to print.
    … …  
    15041512
    15051513                // Go!
    1506                 $this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
     1514                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    15071515
    15081516                // No scripts left to print.
    … …  
    15221530
    15231531                // Go!
    1524                 $this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
     1532                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    15251533
    15261534                // No scripts left to print.
    … …  
    15401548                $expected  = "<!--[if lt IE 9]>\n<script type='text/javascript' id='test-conditional-with-data-js-extra'>\n/* <![CDATA[ */\ntesting\n/* ]]> */\n</script>\n<![endif]-->\n";
    15411549                $expected .= "<!--[if lt IE 9]>\n<script type='text/javascript' src='http://example.com' id='test-conditional-with-data-js'></script>\n<![endif]-->\n";
     1550                $expected  = str_replace( "'", '"', $expected );
    15421551
    15431552                // Go!
    1544                 $this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
     1553                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    15451554
    15461555                // No scripts left to print.
    … …  
    15601569
    15611570                // Go!
    1562                 $this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
     1571                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    15631572
    15641573                // No scripts left to print.
    1565                 $this->assertSame( '', get_echo( 'wp_print_scripts' ) );
     1574                $this->assertEqualMarkup( '', get_echo( 'wp_print_scripts' ) );
    15661575        }
    15671576
    … …  
    15891598                wp_enqueue_script( 'handle-three' );
    15901599
    1591                 $this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
     1600                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    15921601        }
    15931602
    … …  
    16771686                $expected_footer  = "<script type='text/javascript' src='/parent.js' id='parent-js'></script>\n";
    16781687
    1679                 $this->assertSame( $expected_header, $header, 'Expected same header markup.' );
    1680                 $this->assertSame( $expected_footer, $footer, 'Expected same footer markup.' );
     1688                $this->assertEqualMarkup( $expected_header, $header, 'Expected same header markup.' );
     1689                $this->assertEqualMarkup( $expected_footer, $footer, 'Expected same footer markup.' );
    16811690        }
    16821691
    … …  
    16981707                $expected_footer .= "<script type='text/javascript' src='/parent.js' id='parent-js'></script>\n";
    16991708
    1700                 $this->assertSame( $expected_header, $header, 'Expected same header markup.' );
    1701                 $this->assertSame( $expected_footer, $footer, 'Expected same footer markup.' );
     1709                $this->assertEqualMarkup( $expected_header, $header, 'Expected same header markup.' );
     1710                $this->assertEqualMarkup( $expected_footer, $footer, 'Expected same footer markup.' );
    17021711        }
    17031712
    … …  
    17291738                $expected_footer .= "<script type='text/javascript' src='/parent-footer.js' id='parent-footer-js'></script>\n";
    17301739
    1731                 $this->assertSame( $expected_header, $header, 'Expected same header markup.' );
    1732                 $this->assertSame( $expected_footer, $footer, 'Expected same footer markup.' );
     1740                $this->assertEqualMarkup( $expected_header, $header, 'Expected same header markup.' );
     1741                $this->assertEqualMarkup( $expected_footer, $footer, 'Expected same footer markup.' );
    17331742        }
    17341743
    … …  
    19531962                $expected_localized .= "<script type='text/javascript' id='test-example-js-extra'>\n/* <![CDATA[ */\nvar testExample = {\"foo\":\"bar\"};\n/* ]]> */\n</script>\n";
    19541963                $expected_localized .= "<![endif]-->\n";
     1964                $expected_localized  = str_replace( "'", '"', $expected_localized );
    19551965
    19561966                $expected  = "<!--[if gte IE 9]>\n";
    … …  
    19591969                $expected .= "<script type='text/javascript' id='test-example-js-after'>\nconsole.log(\"after\");\n</script>\n";
    19601970                $expected .= "<![endif]-->\n";
     1971                $expected  = str_replace( "'", '"', $expected );
    19611972
    19621973                wp_enqueue_script( 'test-example', 'example.com', array(), null );
    … …  
    21252136                $print_scripts = $this->getActualOutput();
    21262137
    2127                 $tail = substr( $print_scripts, strrpos( $print_scripts, "<script type='text/javascript' src='/customize-dependency.js' id='customize-dependency-js'>" ) );
     2138                $tail = substr( $print_scripts, strrpos( $print_scripts, '<script type="text/javascript" src="/customize-dependency.js" id="customize-dependency-js">' ) );
     2139
    21282140                $this->assertEqualMarkup( $expected_tail, $tail );
    21292141        }
    … …  
    23052317                $expected .= "<script type='text/javascript' src='/wp-includes/js/script.js' id='test-example-js'></script>\n";
    23062318
    2307                 $this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
     2319                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    23082320        }
    23092321
    … …  
    23322344                $expected .= "<script type='text/javascript' src='/wp-content/plugins/my-plugin/js/script.js' id='plugin-example-js'></script>\n";
    23332345
    2334                 $this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
     2346                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    23352347        }
    23362348
    … …  
    23592371                $expected .= "<script type='text/javascript' src='/wp-content/themes/my-theme/js/script.js' id='theme-example-js'></script>\n";
    23602372
    2361                 $this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
     2373                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    23622374        }
    23632375
    … …  
    23862398                $expected .= "<script type='text/javascript' src='/wp-admin/js/script.js' id='script-handle-js'></script>\n";
    23872399
    2388                 $this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
     2400                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    23892401        }
    23902402
    … …  
    24162428                $expected .= "<script type='text/javascript' src='/wp-admin/js/script.js' id='test-example-js'></script>\n";
    24172429
    2418                 $this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
     2430                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    24192431        }
    24202432
    … …  
    24452457                $expected .= "<script type='text/javascript' src='/wp-includes/js/script.js' id='test-example-js'></script>\n";
    24462458
    2447                 $this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
     2459                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    24482460        }
    24492461
    … …  
    24752487                $expected .= "<script type='text/javascript' src='/wp-includes/js/script2.js' id='test-example-js'></script>\n";
    24762488
    2477                 $this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
     2489                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    24782490        }
    24792491
    … …  
    28642876                $expected .= "<script type='text/javascript' src='http://example.com' id='test-example-js'></script>\n";
    28652877
    2866                 $this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
     2878                $this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
    28672879        }
    28682880
    … …  
    29292941                $expected .= "<script type='text/javascript' src='/default/common.js' id='common-js'></script>\n";
    29302942
    2931                 $this->assertSame( $expected, $print_scripts );
     2943                $this->assertEqualMarkup( $expected, $print_scripts );
    29322944        }
    29332945
    … …  
    29682980         *
    29692981         * @param string $markup Markup.
    2970          * @return DOMElement Body element wrapping supplied markup fragment.
     2982         * @return DOMDocument Document containing the normalized markup fragment.
    29712983         */
    29722984        protected function parse_markup_fragment( $markup ) {
    … …  
    29862998                }
    29872999
    2988                 return $body;
    2989         }
    2990 
    2991         /**
    2992          * Assert markup is equal.
     3000                return $dom;
     3001        }
     3002
     3003        /**
     3004         * Assert markup is equal after normalizing script tags.
    29933005         *
    29943006         * @param string $expected Expected markup.
    … …  
    29973009         */
    29983010        protected function assertEqualMarkup( $expected, $actual, $message = '' ) {
     3011                $expected_dom = $this->parse_markup_fragment( $expected );
     3012                $actual_dom   = $this->parse_markup_fragment( $actual );
     3013                foreach ( array( $expected_dom, $actual_dom ) as $dom ) {
     3014                        $xpath = new DOMXPath( $dom );
     3015                        /** @var DOMElement $script */
     3016
     3017                        // Normalize type attribute. When missing, it defaults to text/javascript.
     3018                        foreach ( $xpath->query( '//script[ not( @type ) ]' ) as $script ) {
     3019                                $script->setAttribute( 'type', 'text/javascript' );
     3020                        }
     3021
     3022                        // Normalize script contents to remove CDATA wrapper.
     3023                        foreach ( $xpath->query( '//script[ contains( text(), "<![CDATA[" ) ]' ) as $script ) {
     3024                                $script->textContent = str_replace(
     3025                                        array(
     3026                                                "/* <![CDATA[ */\n",
     3027                                                "\n/* ]]> */",
     3028                                        ),
     3029                                        '',
     3030                                        $script->textContent
     3031                                );
     3032                        }
     3033
     3034                        // Normalize XHTML-compatible boolean attributes to HTML5 ones.
     3035                        foreach ( array( 'async', 'defer' ) as $attribute ) {
     3036                                foreach ( iterator_to_array( $xpath->query( "//script[ @{$attribute} = '{$attribute}' ]" ) ) as $script ) {
     3037                                        $script->removeAttribute( $attribute );
     3038                                        $script->setAttributeNode( $dom->createAttribute( $attribute ) );
     3039                                }
     3040                        }
     3041                }
     3042
    29993043                $this->assertEquals(
    3000                         $this->parse_markup_fragment( $expected ),
    3001                         $this->parse_markup_fragment( $actual ),
     3044                        $expected_dom->getElementsByTagName( 'body' )->item( 0 ),
     3045                        $actual_dom->getElementsByTagName( 'body' )->item( 0 ),
    30023046                        $message
    30033047                );
    30043048        }
     3049
     3050        /**
     3051         * Adds html5 script theme support.
     3052         */
     3053        protected function add_html5_script_theme_support() {
     3054                add_theme_support( 'html5', array( 'script' ) );
     3055        }
    30053056}
Note: See TracChangeset for help on using the changeset viewer.