Build: Make Karma work in AMD mode

Also, run such a suite in CI to make sure modules are working as expected
when used directly.

(partially cherry picked from 341c6d1b5a)
(partially cherry picked from 437f389a24)

Closes gh-4595
Ref gh-4550
Ref gh-4574
This commit is contained in:
Michał Gołębiowski-Owczarek 2020-01-21 13:26:47 +01:00 committed by GitHub
parent d72faced11
commit 46c284b12b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 183 additions and 125 deletions

View File

@ -17,6 +17,13 @@ matrix:
addons:
chrome: stable
firefox: latest
# Run AMD tests.
- node_js: "12"
env:
- NPM_SCRIPT="test:amd"
- BROWSERS="ChromeHeadless"
addons:
chrome: stable
# Run tests on Firefox ESR as well.
- node_js: "12"
env:

View File

@ -165,6 +165,14 @@ module.exports = function( grunt ) {
]
}
],
client: {
qunit: {
// We're running `QUnit.start()` ourselves via `loadTests()`
// in test/jquery.js
autostart: false
}
},
files: [
"test/data/jquery-1.9.1.js",
"external/sinon/sinon.js",
@ -174,39 +182,30 @@ module.exports = function( grunt ) {
"test/jquery.js",
// Replacement for testinit.js#loadTests()
"test/data/testrunner.js",
"test/unit/basic.js",
"test/unit/core.js",
"test/unit/callbacks.js",
"test/unit/deferred.js",
"test/unit/deprecated.js",
"test/unit/support.js",
"test/unit/data.js",
"test/unit/queue.js",
"test/unit/attributes.js",
"test/unit/event.js",
"test/unit/selector.js",
"test/unit/traversing.js",
"test/unit/manipulation.js",
"test/unit/wrap.js",
"test/unit/css.js",
"test/unit/serialize.js",
"test/unit/ajax.js",
"test/unit/effects.js",
"test/unit/offset.js",
"test/unit/dimensions.js",
"test/unit/animation.js",
"test/unit/tween.js",
"test/unit/ready.js",
{ pattern: "dist/jquery.*", included: false, served: true },
{ pattern: "src/**", included: false, served: true },
{ pattern: "external/**", included: false, served: true },
{
pattern: "dist/jquery.*",
included: false,
served: true,
nocache: true
},
{
pattern: "src/**",
included: false,
served: true,
nocache: true
},
{
pattern: "external/**",
included: false,
served: true,
nocache: true
},
{ pattern: "node_modules/**", included: false, served: true },
{
pattern: "test/**/*.@(js|css|jpg|html|xml|svg)",
included: false,
served: true
served: true,
nocache: true
}
],
reporters: [ "dots" ],
@ -218,6 +217,21 @@ module.exports = function( grunt ) {
main: {
browsers: isTravis && travisBrowsers || [ "ChromeHeadless", "FirefoxHeadless" ]
},
amd: {
browsers: isTravis && travisBrowsers || [ "ChromeHeadless" ],
options: {
client: {
qunit: {
// We're running `QUnit.start()` ourselves via `loadTests()`
// in test/jquery.js
autostart: false,
amd: true
}
}
}
},
jsdom: {
options: {
@ -229,7 +243,7 @@ module.exports = function( grunt ) {
// choosing a version etc. for jsdom.
"dist/jquery.js",
// Replacement for testinit.js#loadTests()
// A partial replacement for testinit.js#loadTests()
"test/data/testrunner.js",
// jsdom only runs basic tests

View File

@ -71,7 +71,8 @@
"start": "grunt watch",
"test:browserless": "grunt && grunt test:slow",
"test:browser": "grunt && grunt karma:main",
"test": "grunt && grunt test:slow && grunt karma:main",
"test:amd": "grunt && grunt karma:amd",
"test": "grunt && grunt test:slow && grunt karma:main && grunt karma:amd",
"jenkins": "npm run test:browserless"
},
"commitplease": {

View File

@ -38,3 +38,17 @@ function url( value ) {
return baseURL + value + ( /\?/.test( value ) ? "&" : "?" ) +
new Date().getTime() + "" + parseInt( Math.random() * 100000, 10 );
}
// The file-loading part of testinit.js#loadTests is handled by
// jsdom Karma config; here we just need to trigger relevant APIs.
this.loadTests = function() {
// Delay the initialization until after all the files are loaded
// as in the JSDOM case we load them via Karma (see Gruntfile.js)
// instead of directly in testinit.js.
window.addEventListener( "load", function() {
window.__karma__.start();
jQuery.noConflict();
QUnit.start();
} );
};

View File

@ -299,14 +299,16 @@ moduleTypeSupported();
this.loadTests = function() {
// Directly load tests that need synchronous evaluation
if ( !QUnit.urlParams.amd || document.readyState === "loading" ) {
// QUnit.config is populated from QUnit.urlParams but only at the beginning
// of the test run. We need to read both.
var amd = QUnit.config.amd || QUnit.urlParams.amd;
// Directly load tests that need evaluation before DOMContentLoaded.
if ( !amd || document.readyState === "loading" ) {
document.write( "<script src='" + parentUrl + "test/unit/ready.js'><\x2Fscript>" );
} else {
QUnit.module( "ready", function() {
QUnit.test( "jQuery ready", function( assert ) {
assert.ok( false, "Test should be initialized before DOM ready" );
} );
QUnit.skip( "jQuery ready tests skipped in async mode", function() {} );
} );
}
@ -360,7 +362,11 @@ this.loadTests = function() {
}
} else {
QUnit.load();
if ( window.__karma__ && window.__karma__.start ) {
window.__karma__.start();
} else {
QUnit.load();
}
/**
* Run in noConflict mode

View File

@ -29,7 +29,14 @@
// Load tests if they have not been loaded
// This is in a different script tag to ensure that
// jQuery is on the page when the testrunner executes
if ( !QUnit.urlParams.amd ) {
// QUnit.config is populated from QUnit.urlParams but only at the beginning
// of the test run. We need to read both.
var amd = QUnit.config.amd || QUnit.urlParams.amd;
// Workaround: Remove call to `window.__karma__.loaded()`
// in favour of calling `window.__karma__.start()` from `loadTests()`
// because tests such as unit/ready.js should run after document ready.
if ( !amd ) {
loadTests();
}
</script>

51
test/jquery.js vendored
View File

@ -2,44 +2,57 @@
( function() {
/* global loadTests: false */
var FILEPATH = "/test/jquery.js",
var config, src,
FILEPATH = "/test/jquery.js",
activeScript = [].slice.call( document.getElementsByTagName( "script" ), -1 )[ 0 ],
parentUrl = activeScript && activeScript.src ?
activeScript.src.replace( /[?#].*/, "" ) + FILEPATH.replace( /[^/]+/g, ".." ) + "/" :
"../",
QUnit = window.QUnit || parent.QUnit,
require = window.require || parent.require,
QUnit = window.QUnit,
require = window.require;
function getQUnitConfig() {
var config = Object.create( null );
// Default to unminified jQuery for directly-opened iframes
urlParams = QUnit ?
QUnit.urlParams :
{ dev: true },
src = urlParams.dev ?
"dist/jquery.js" :
"dist/jquery.min.js";
if ( !QUnit ) {
config.dev = true;
} else {
// Define configuration parameters controlling how jQuery is loaded
if ( QUnit ) {
// AMD loading is asynchronous and incompatible with synchronous test loading in Karma
if ( !window.__karma__ ) {
QUnit.config.urlConfig.push( {
id: "amd",
label: "Load with AMD",
tooltip: "Load the AMD jQuery file (and its dependencies)"
// QUnit.config is populated from QUnit.urlParams but only at the beginning
// of the test run. We need to read both.
QUnit.config.urlConfig.forEach( function( entry ) {
config[ entry.id ] = QUnit.config[ entry.id ] != null ?
QUnit.config[ entry.id ] :
QUnit.urlParams[ entry.id ];
} );
}
return config;
}
// Define configuration parameters controlling how jQuery is loaded
if ( QUnit ) {
QUnit.config.urlConfig.push( {
id: "amd",
label: "Load with AMD",
tooltip: "Load the AMD jQuery file (and its dependencies)"
}, {
id: "dev",
label: "Load unminified",
tooltip: "Load the development (unminified) jQuery file"
} );
}
config = getQUnitConfig();
src = config.dev ?
"dist/jquery.js" :
"dist/jquery.min.js";
// Honor AMD loading on the main window (detected by seeing QUnit on it).
// This doesn't apply to iframes because they synchronously expect jQuery to be there.
if ( urlParams.amd && window.QUnit ) {
if ( config.amd && QUnit ) {
require.config( {
baseUrl: parentUrl
} );

View File

@ -1,45 +1,43 @@
<!DOCTYPE html>
<html lang="en" id="html">
<head>
<meta charset="utf-8">
<title>CONTEXT</title>
<!-- Karma serves this page from /context.html. Other files are served from /base -->
<link rel="stylesheet" href="/base/test/data/testsuite.css" />
<meta charset="utf-8">
<title>CONTEXT</title>
<!-- Karma serves this page from /context.html. Other files are served from /base -->
<link rel="stylesheet" href="/base/test/data/testsuite.css" />
</head>
<body id="body">
<div id="qunit"></div>
<div id="qunit"></div>
<!-- Start: jQuery Test HTML -->
<!-- this iframe is outside the #qunit-fixture so it won't waste time by constantly reloading; the tests are "safe" and clean up after themselves -->
<iframe id="loadediframe" name="loadediframe" style="display:none;" src="/base/test/data/iframe.html"></iframe>
<div id="qunit-fixture"></div>
<!-- End: jQuery Test HTML -->
<!-- Start: jQuery Test HTML -->
<!-- this iframe is outside the #qunit-fixture so it won't waste time by constantly reloading; the tests are "safe" and clean up after themselves -->
<iframe id="loadediframe" name="loadediframe" style="display:none;" src="/base/test/data/iframe.html"></iframe>
<div id="qunit-fixture"></div>
<!-- End: jQuery Test HTML -->
<!-- Start: Karma boilerplate -->
<script src="/context.js"></script>
<script>
%CLIENT_CONFIG%
window.__karma__.setupContext(window);
<!-- Start: Karma boilerplate -->
<script src="/context.js"></script>
<script>
%CLIENT_CONFIG%
window.__karma__.setupContext(window);
%MAPPINGS%
</script>
%SCRIPTS%
<!-- End: Karma boilerplate -->
%MAPPINGS%
</script>
%SCRIPTS%
<!-- End: Karma boilerplate -->
<script src="/base/test/data/qunit-fixture.js"></script>
<script>
// Workaround: Remove call to window.__karma__.loaded()
// in favour of calling window.__karma__.start() at window.onload
// because tests such as unit/ready.js should run after document ready
window.addEventListener('load', function() {
window.__karma__.start();
<script src="/base/test/data/qunit-fixture.js"></script>
<script>
// QUnit.config is populated from QUnit.urlParams but only at the beginning
// of the test run. We need to read both.
var amd = QUnit.config.amd || QUnit.urlParams.amd;
// Workaround: https://github.com/karma-runner/karma-qunit/issues/92
QUnit.testStart(function () {
// Restore content
document.getElementById("qunit-fixture").innerHTML = QUnit.config.fixture;
});
});
</script>
// Workaround: Remove call to `window.__karma__.loaded()`
// in favour of calling `window.__karma__.start()` from `loadTests()`
// because tests such as unit/ready.js should run after document ready.
if ( !amd ) {
loadTests();
}
</script>
</body>
</html>

View File

@ -2,46 +2,44 @@
<html lang="en" id="html">
<head>
%X_UA_COMPATIBLE%
<title>DEBUG</title>
<meta charset="utf-8">
<!-- Karma serves this page from /context.html. Other files are served from /base -->
<link rel="stylesheet" href="/base/external/qunit/qunit.css" />
<link rel="stylesheet" href="/base/test/data/testsuite.css" />
<title>DEBUG</title>
<meta charset="utf-8">
<!-- Karma serves this page from /context.html. Other files are served from /base -->
<link rel="stylesheet" href="/base/external/qunit/qunit.css" />
<link rel="stylesheet" href="/base/test/data/testsuite.css" />
</head>
<body id="body">
<div id="qunit"></div>
<div id="qunit"></div>
<!-- Start: jQuery Test HTML -->
<!-- this iframe is outside the #qunit-fixture so it won't waste time by constantly reloading; the tests are "safe" and clean up after themselves -->
<iframe id="loadediframe" name="loadediframe" style="display:none;" src="/base/test/data/iframe.html"></iframe>
<div id="qunit-fixture"></div>
<!-- End: jQuery Test HTML -->
<!-- Start: jQuery Test HTML -->
<!-- this iframe is outside the #qunit-fixture so it won't waste time by constantly reloading; the tests are "safe" and clean up after themselves -->
<iframe id="loadediframe" name="loadediframe" style="display:none;" src="/base/test/data/iframe.html"></iframe>
<div id="qunit-fixture"></div>
<!-- End: jQuery Test HTML -->
<!-- Start: Karma boilerplate -->
<script src="/context.js"></script>
<script src="/debug.js"></script>
<script>
%CLIENT_CONFIG%
<!-- Start: Karma boilerplate -->
<script src="/context.js"></script>
<script src="/debug.js"></script>
<script>
%CLIENT_CONFIG%
%MAPPINGS%
</script>
%SCRIPTS%
<!-- End: Karma boilerplate -->
%MAPPINGS%
</script>
%SCRIPTS%
<!-- End: Karma boilerplate -->
<script src="/base/test/data/qunit-fixture.js"></script>
<script>
// Workaround: Remove call to window.__karma__.loaded()
// in favour of calling window.__karma__.start() at window.onload
// because tests such as unit/ready.js should run after document ready
window.addEventListener('load', function() {
window.__karma__.start();
<script src="/base/test/data/qunit-fixture.js"></script>
<script>
// QUnit.config is populated from QUnit.urlParams but only at the beginning
// of the test run. We need to read both.
var amd = QUnit.config.amd || QUnit.urlParams.amd;
// Workaround: https://github.com/karma-runner/karma-qunit/issues/92
QUnit.testStart(function () {
// Restore content
document.getElementById("qunit-fixture").innerHTML = QUnit.config.fixture;
});
});
</script>
// Workaround: Remove call to `window.__karma__.loaded()`
// in favour of calling `window.__karma__.start()` from `loadTests()`
// because tests such as unit/ready.js should run after document ready.
if ( !amd ) {
loadTests();
}
</script>
</body>
</html>