Build: migrate most grunt tasks off of grunt (3.x)

Close gh-5330

- lint
- npmcopy
- build, minify, and process for distribution.
- new custom build command using yargs
- compare size of minified/gzip built files
- pretest scripts, including qunit-fixture, babel transpilation, and npmcopy
- node smoke tests
- promises aplus tests
- new watch task using nodemon, which runs `npm run build:all` on `src` changes.

Also:

- upgraded husky and added the new lint command
- updated lint config to use new "flat" config format.
	See https://eslint.org/docs/latest/use/configure/configuration-files-new
- Temporarily disabled one lint rule until flat config is
	supported by eslint-plugin-import.
	See https://github.com/import-js/eslint-plugin-import/issues/2556
- committed package-lock.json
- updated all test scripts to use the new build
- added an express test server that uses middleware-mockserver
	this can be used to run tests without karma
- build-all-variants is now build:all
- run pretest script in jenkins

---------

Co-authored-by: Michał Gołębiowski-Owczarek <m.goleb@gmail.com>
This commit is contained in:
Timmy Willison 2023-09-20 18:18:42 -04:00 committed by GitHub
parent 6fe88690a3
commit ec8802bafe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 9289 additions and 34976 deletions

View File

@ -10,7 +10,7 @@ charset = utf-8
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
[package.json] [*.{json,yml}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2

View File

@ -1,17 +0,0 @@
external
node_modules
*.min.js
dist/**
!dist/jquery.js
!dist/jquery.min.js
!dist/jquery.slim.js
!dist/jquery.slim.min.js
test/data/jquery-1.9.1.js
test/data/badcall.js
test/data/badjson.js
test/data/json_obj.js
test/data/readywaitasset.js
test/data/readywaitloader.js
test/data/support/csp.js
test/data/support/getComputedSupport.js
test/data/core/jquery-iterability-transpiled.js

View File

@ -1,32 +0,0 @@
{
"root": true,
"extends": "jquery",
"reportUnusedDisableDirectives": true,
// Support: IE <=9 only, Android <=4.0 only
// The above browsers are failing a lot of tests in the ES5
// test suite at http://test262.ecmascript.org.
"parserOptions": {
"ecmaVersion": 3
},
// The browser env is not enabled on purpose so that code takes
// all browser-only globals from window instead of assuming
// they're available as globals. This makes it possible to use
// jQuery with tools like jsdom which provide a custom window
// implementation.
"env": {},
"globals": {
"window": true,
"define": true,
"module": true
},
"rules": {
"one-var": ["error", {"var": "always"}],
"strict": ["error", "function"]
}
}

View File

@ -1,20 +0,0 @@
{
"root": true,
"extends": "jquery",
"reportUnusedDisableDirectives": true,
"parserOptions": {
"ecmaVersion": 2017
},
"env": {
"es6": true,
"node": true
},
"rules": {
"strict": ["error", "global"]
}
}

View File

@ -1,5 +0,0 @@
{
"root": true,
"extends": "./.eslintrc-node.json"
}

View File

@ -40,40 +40,47 @@ jobs:
NODE_VERSION: "18.x" NODE_VERSION: "18.x"
NPM_SCRIPT: "test:browser" NPM_SCRIPT: "test:browser"
BROWSERS: "FirefoxHeadless" BROWSERS: "FirefoxHeadless"
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Cache - name: Cache
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
with: with:
path: ~/.npm path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }}
restore-keys: | restore-keys: |
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-npm-lock- ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-npm-lock-
- name: Use Node.js ${{ matrix.NODE_VERSION }} - name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
with: with:
node-version: ${{ matrix.NODE_VERSION }} node-version: ${{ matrix.NODE_VERSION }}
- name: Install firefox ESR - name: Install firefox ESR
run: | run: |
export FIREFOX_SOURCE_URL='https://download.mozilla.org/?product=firefox-esr-latest&lang=en-US&os=linux64' export FIREFOX_SOURCE_URL='https://download.mozilla.org/?product=firefox-esr-latest&lang=en-US&os=linux64'
wget --no-verbose $FIREFOX_SOURCE_URL -O - | tar -jx -C ${HOME} wget --no-verbose $FIREFOX_SOURCE_URL -O - | tar -jx -C ${HOME}
if: "contains(matrix.NAME, 'Firefox ESR')" if: contains(matrix.NAME, 'Firefox ESR')
- name: Install dependencies - name: Install dependencies
run: | run: npm install
npm install
- name: Install Playwright dependencies - name: Install Playwright dependencies
run: npx playwright-webkit install-deps run: npx playwright-webkit install-deps
if: "matrix.NPM_SCRIPT == 'test:browser' && contains(matrix.BROWSERS, 'WebkitHeadless')" if: matrix.NPM_SCRIPT == 'test:browser' && contains(matrix.BROWSERS, 'WebkitHeadless')
- name: Run tests - name: Lint code
env: run: npm run build && npm run lint
BROWSERS: ${{ matrix.BROWSERS }} if: matrix.NODE_VERSION == '18.x'
run: |
export PATH=${HOME}/firefox:$PATH - name: Prepare tests
npm run ${{ matrix.NPM_SCRIPT }} run: npm run pretest
- name: Run tests
env:
BROWSERS: ${{ matrix.BROWSERS }}
run: |
export PATH=${HOME}/firefox:$PATH
npm run ${{ matrix.NPM_SCRIPT }}

7
.gitignore vendored
View File

@ -8,14 +8,13 @@
.bower.json .bower.json
.sizecache.json .sizecache.json
yarn.lock yarn.lock
package-lock.json .eslintcache
npm-debug.log* npm-debug.log*
# Ignore everything in `dist` folder except for the ESLint config /dist
/dist/*
!/dist/.eslintrc.json
/external
/node_modules /node_modules
/test/data/core/jquery-iterability-transpiled.js /test/data/core/jquery-iterability-transpiled.js

4
.husky/commit-msg Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx commitplease .git/COMMIT_EDITMSG

5
.husky/pre-commit Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint
npm run qunit-fixture

View File

@ -1,5 +1,5 @@
.eslintignore .eslintignore
.eslintrc.json eslint.config.js
/.editorconfig /.editorconfig
/.gitattributes /.gitattributes

View File

@ -124,10 +124,10 @@ This will only run the "css" module tests. This will significantly speed up your
#### Loading changes on the test page #### Loading changes on the test page
Rather than rebuilding jQuery with `grunt` every time you make a change, you can use the included `grunt watch` task to rebuild distribution files whenever a file is saved. Rather than rebuilding jQuery with `npm run build` every time you make a change, you can use the included watch task to rebuild distribution files whenever a file is saved.
```bash ```bash
$ grunt watch $ npm start
``` ```
Alternatively, you can **load tests in AMD** to avoid the need for rebuilding altogether. Alternatively, you can **load tests in AMD** to avoid the need for rebuilding altogether.

View File

@ -1,20 +1,6 @@
"use strict"; "use strict";
module.exports = function( grunt ) { module.exports = function( grunt ) {
function readOptionalJSON( filepath ) {
const stripJSONComments = require( "strip-json-comments" );
let data = {};
try {
data = JSON.parse( stripJSONComments(
fs.readFileSync( filepath, { encoding: "utf8" } )
) );
} catch ( e ) {}
return data;
}
const fs = require( "fs" );
const { spawn } = require( "child_process" );
const gzip = require( "gzip-js" );
const nodeV16OrNewer = !/^v1[0-5]\./.test( process.version ); const nodeV16OrNewer = !/^v1[0-5]\./.test( process.version );
const nodeV17OrNewer = !/^v1[0-6]\./.test( process.version ); const nodeV17OrNewer = !/^v1[0-6]\./.test( process.version );
const customBrowsers = process.env.BROWSERS && process.env.BROWSERS.split( "," ); const customBrowsers = process.env.BROWSERS && process.env.BROWSERS.split( "," );
@ -34,112 +20,8 @@ module.exports = function( grunt ) {
grunt.option( "filename", "jquery.js" ); grunt.option( "filename", "jquery.js" );
} }
const builtJsFiles = [
"dist/jquery.js",
"dist/jquery.min.js",
"dist/jquery.slim.js",
"dist/jquery.slim.min.js"
];
const builtJsMinFiles = builtJsFiles
.filter( filepath => filepath.endsWith( ".min.js" ) );
grunt.initConfig( { grunt.initConfig( {
pkg: grunt.file.readJSON( "package.json" ), pkg: grunt.file.readJSON( "package.json" ),
dst: readOptionalJSON( "dist/.destination.json" ),
compare_size: {
files: builtJsMinFiles,
options: {
compress: {
gz: function( contents ) {
return gzip.zip( contents, {} ).length;
}
},
cache: "build/.sizecache.json"
}
},
babel: {
options: {
sourceMap: "inline",
retainLines: true,
plugins: [ "@babel/transform-for-of" ]
},
tests: {
files: {
"test/data/core/jquery-iterability-transpiled.js":
"test/data/core/jquery-iterability-transpiled-es6.js"
}
}
},
build: {
all: {
dest: "dist/jquery.js",
minimum: [
"core"
],
// Exclude specified modules if the module matching the key is removed
removeWith: {
ajax: [ "manipulation/_evalUrl", "deprecated/ajax-event-alias" ],
callbacks: [ "deferred" ],
css: [ "effects", "dimensions", "offset" ],
"css/showHide": [ "effects" ],
deferred: {
remove: [ "ajax", "effects", "queue", "core/ready" ],
include: [ "core/ready-no-deferred" ]
},
event: [ "deprecated/ajax-event-alias", "deprecated/event" ],
selector: [ "css/hiddenVisibleSelectors", "effects/animatedSelector" ]
}
}
},
npmcopy: {
all: {
options: {
destPrefix: "external"
},
files: {
"bootstrap/bootstrap.css": "bootstrap/dist/css/bootstrap.css",
"bootstrap/bootstrap.min.css": "bootstrap/dist/css/bootstrap.min.css",
"bootstrap/bootstrap.min.css.map": "bootstrap/dist/css/bootstrap.min.css.map",
"core-js/core-js.js": "core-js/client/core.min.js",
"core-js/LICENSE.txt": "core-js/LICENSE",
"npo/npo.js": "native-promise-only/lib/npo.src.js",
"qunit/qunit.js": "qunit/qunit/qunit.js",
"qunit/qunit.css": "qunit/qunit/qunit.css",
"qunit/LICENSE.txt": "qunit/LICENSE.txt",
"requirejs/require.js": "requirejs/require.js",
"sinon/sinon.js": "sinon/pkg/sinon.js",
"sinon/LICENSE.txt": "sinon/LICENSE"
}
}
},
jsonlint: {
pkg: {
src: [ "package.json" ]
}
},
eslint: {
options: {
// See https://github.com/sindresorhus/grunt-eslint/issues/119
quiet: true
},
// We have to explicitly declare "src" property otherwise "newer"
// task wouldn't work properly :/
dist: {
src: builtJsFiles
},
dev: {
src: [ "src/**/*.js", "Gruntfile.js", "test/**/*.js", "build/**/*.js" ]
}
},
testswarm: { testswarm: {
tests: [ tests: [
@ -206,9 +88,14 @@ module.exports = function( grunt ) {
"external/npo/npo.js", "external/npo/npo.js",
"external/requirejs/require.js", "external/requirejs/require.js",
"test/data/testinit.js", "test/data/testinit.js",
"test/jquery.js", "test/jquery.js",
{
pattern: "external/**",
included: false,
served: true,
nocache: true
},
{ {
pattern: "dist/jquery.*", pattern: "dist/jquery.*",
included: false, included: false,
@ -221,13 +108,6 @@ module.exports = function( grunt ) {
served: true, served: true,
nocache: 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)", pattern: "test/**/*.@(js|css|jpg|html|xml|svg)",
included: false, included: false,
@ -281,7 +161,6 @@ module.exports = function( grunt ) {
// jsdom only runs basic tests // jsdom only runs basic tests
"test/unit/basic.js", "test/unit/basic.js",
{ pattern: "external/**", included: false, served: true },
{ {
pattern: "test/**/*.@(js|css|jpg|html|xml|svg)", pattern: "test/**/*.@(js|css|jpg|html|xml|svg)",
included: false, included: false,
@ -310,100 +189,27 @@ module.exports = function( grunt ) {
browsers: [ "IE" ], browsers: [ "IE" ],
singleRun: false singleRun: false
} }
},
watch: {
files: [ "<%= eslint.dev.src %>" ],
tasks: [ "dev" ]
},
uglify: {
all: {
files: {
"dist/<%= grunt.option('filename').replace(/\\.js$/, '.min.js') %>":
"dist/<%= grunt.option('filename') %>"
},
options: {
preserveComments: false,
sourceMap: true,
sourceMapName:
"dist/<%= grunt.option('filename').replace('.js', '.min.map') %>",
report: "min",
output: {
"ascii_only": true,
// Support: Android 4.0 only
// UglifyJS 3 breaks Android 4.0 if this option is not enabled.
// This is in lieu of setting ie8 for all of mangle, compress, and output
"ie8": true
},
banner: "/*! jQuery v<%= pkg.version %> | " +
"(c) OpenJS Foundation and other contributors | jquery.org/license */",
compress: {
"hoist_funs": false,
loops: false,
// Support: IE <11
// typeofs transformation is unsafe for IE9-10
// See https://github.com/mishoo/UglifyJS2/issues/2198
typeofs: false
}
}
}
} }
} ); } );
// Load grunt tasks from NPM packages // Load grunt tasks from NPM packages
require( "load-grunt-tasks" )( grunt, { require( "load-grunt-tasks" )( grunt, {
pattern: nodeV16OrNewer ? [ "grunt-*" ] : [ "grunt-*", "!grunt-eslint" ] pattern: [ "grunt-*" ]
} ); } );
// Integrate jQuery specific tasks // Integrate jQuery specific tasks
grunt.loadTasks( "build/tasks" ); grunt.loadTasks( "build/grunt-tasks" );
grunt.registerTask( "print_old_node_message", ( ...args ) => { grunt.registerTask( "print_old_node_message", ( ...args ) => {
var task = args.join( ":" ); var task = args.join( ":" );
grunt.log.writeln( "Old Node.js detected, running the task \"" + task + "\" skipped..." ); grunt.log.writeln( "Old Node.js detected, running the task \"" + task + "\" skipped..." );
} ); } );
grunt.registerTask( "build-all-variants",
"Build both the full & slim builds",
function() {
const done = this.async();
spawn( "npm run build-all-variants", {
stdio: "inherit",
shell: true
} )
.on( "close", code => {
done( code === 0 );
} );
} );
grunt.registerTask( "print_jsdom_message", () => { grunt.registerTask( "print_jsdom_message", () => {
grunt.log.writeln( "Node.js 17 or newer detected, skipping jsdom tests..." ); grunt.log.writeln( "Node.js 17 or newer detected, skipping jsdom tests..." );
} ); } );
grunt.registerTask( "lint", [ grunt.registerTask( "test:jsdom", [
"jsonlint",
// Running the full eslint task without breaking it down to targets
// would run the dist target first which would point to errors in the built
// file, making it harder to fix them. We want to check the built file only
// if we already know the source files pass the linter.
runIfNewNode( "eslint:dev" ),
runIfNewNode( "eslint:dist" )
] );
grunt.registerTask( "lint:newer", [
"newer:jsonlint",
// Don't replace it with just the task; see the above comment.
runIfNewNode( "newer:eslint:dev" ),
runIfNewNode( "newer:eslint:dist" )
] );
grunt.registerTask( "test:fast", [ "node_smoke_tests" ] );
grunt.registerTask( "test:slow", [
runIfNewNode( "promises_aplus_tests" ),
// Support: Node.js 17+ // Support: Node.js 17+
// jsdom fails to connect to the Karma server in Node 17+. // jsdom fails to connect to the Karma server in Node 17+.
@ -411,33 +217,11 @@ module.exports = function( grunt ) {
nodeV17OrNewer ? "print_jsdom_message" : runIfNewNode( "karma:jsdom" ) nodeV17OrNewer ? "print_jsdom_message" : runIfNewNode( "karma:jsdom" )
] ); ] );
grunt.registerTask( "test:prepare", [
"qunit_fixture",
"babel:tests"
] );
grunt.registerTask( "test", [ grunt.registerTask( "test", [
"test:prepare", "test:jsdom"
"test:fast",
"test:slow"
] );
grunt.registerTask( "dev", [
"build:*:*",
runIfNewNode( "newer:eslint:dev" ),
"newer:uglify",
"remove_map_comment",
"dist:*",
"qunit_fixture",
"compare_size"
] ); ] );
grunt.registerTask( "default", [ grunt.registerTask( "default", [
runIfNewNode( "eslint:dev" ), "test"
"build-all-variants",
"test:prepare",
runIfNewNode( "eslint:dist" ),
"test:fast",
"compare_size"
] ); ] );
}; };

146
README.md
View File

@ -35,7 +35,7 @@ To build jQuery, you need to have the latest Node.js/npm and git 1.7 or later. E
For Windows, you have to download and install [git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/en/download/). For Windows, you have to download and install [git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/en/download/).
OS X users should install [Homebrew](https://brew.sh/). Once Homebrew is installed, run `brew install git` to install git, macOS users should install [Homebrew](https://brew.sh/). Once Homebrew is installed, run `brew install git` to install git,
and `brew install node` to install Node.js. and `brew install node` to install Node.js.
Linux/BSD users should use their appropriate package managers to install git and Node.js, or build from source Linux/BSD users should use their appropriate package managers to install git and Node.js, or build from source
@ -45,47 +45,47 @@ if you swing that way. Easy-peasy.
How to build your own jQuery How to build your own jQuery
---------------------------- ----------------------------
Clone a copy of the main jQuery git repo by running: First, [clone the jQuery git repo](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository).
Then, enter the jquery directory, install dependencies, and run the build script:
```bash ```bash
git clone git://github.com/jquery/jquery.git cd jquery
npm install
npm run build
``` ```
Enter the jquery directory and run the build script: The built version of jQuery will be placed in the `dist/` directory, along with a minified copy and associated map file.
## Build all jQuery release files
To build all variants of jQuery, run the following command:
```bash ```bash
cd jquery && npm run build npm run build:all
```
The built version of jQuery will be put in the `dist/` subdirectory, along with the minified copy and associated map file.
If you want to create custom build or help with jQuery development, it would be better to install [grunt command line interface](https://github.com/gruntjs/grunt-cli) as a global package:
```
npm install -g grunt-cli
```
Make sure you have `grunt` installed by testing:
```
grunt -V
``` ```
Now by running the `grunt` command, in the jquery directory, you can build a full version of jQuery, just like with an `npm run build` command: This will create all of the variants that jQuery includes in a release, including `jquery.js` and `jquery.slim.js` along their associated minified files and sourcemaps.
```
grunt
```
There are many other tasks available for jQuery Core: ## Building a Custom jQuery
```
grunt -help The build script can be used to create a custom version of jQuery that includes only the modules you need.
Any module may be excluded except for `core`. When excluding `selector`, it is not removed but replaced with a small wrapper around native `querySelectorAll` (see below for more information).
### Build Script Help
To see the full list of available options for the build script, run the following:
```bash
npm run build -- --help
``` ```
### Modules ### Modules
Special builds can be created that exclude subsets of jQuery functionality. To exclude a module, pass its path relative to the `src` folder (without the `.js` extension) to the `--exclude` option. When using the `--include` option, the default includes are dropped and a build is created with only those modules.
This allows for smaller custom builds when the builder is certain that those parts of jQuery are not being used.
For example, an app that only used JSONP for `$.ajax()` and did not need to calculate offsets or positions of elements could exclude the offset and ajax/xhr modules.
Any module may be excluded except for `core`, and `selector`. To exclude a module, pass its path relative to the `src` folder (without the `.js` extension). Some example modules that can be excluded or included are:
Some example modules that can be excluded are:
- **ajax**: All AJAX functionality: `$.ajax()`, `$.get()`, `$.post()`, `$.ajaxSetup()`, `.load()`, transports, and ajax event shorthands such as `.ajaxStart()`. - **ajax**: All AJAX functionality: `$.ajax()`, `$.get()`, `$.post()`, `$.ajaxSetup()`, `.load()`, transports, and ajax event shorthands such as `.ajaxStart()`.
- **ajax/xhr**: The XMLHTTPRequest AJAX transport only. - **ajax/xhr**: The XMLHTTPRequest AJAX transport only.
@ -101,84 +101,67 @@ Some example modules that can be excluded are:
- **offset**: The `.offset()`, `.position()`, `.offsetParent()`, `.scrollLeft()`, and `.scrollTop()` methods. - **offset**: The `.offset()`, `.position()`, `.offsetParent()`, `.scrollLeft()`, and `.scrollTop()` methods.
- **wrap**: The `.wrap()`, `.wrapAll()`, `.wrapInner()`, and `.unwrap()` methods. - **wrap**: The `.wrap()`, `.wrapAll()`, `.wrapInner()`, and `.unwrap()` methods.
- **core/ready**: Exclude the ready module if you place your scripts at the end of the body. Any ready callbacks bound with `jQuery()` will simply be called immediately. However, `jQuery(document).ready()` will not be a function and `.on("ready", ...)` or similar will not be triggered. - **core/ready**: Exclude the ready module if you place your scripts at the end of the body. Any ready callbacks bound with `jQuery()` will simply be called immediately. However, `jQuery(document).ready()` will not be a function and `.on("ready", ...)` or similar will not be triggered.
- **deferred**: Exclude jQuery.Deferred. This also removes jQuery.Callbacks. *Note* that modules that depend on jQuery.Deferred(AJAX, effects, core/ready) will not be removed and will still expect jQuery.Deferred to be there. Include your own jQuery.Deferred implementation or exclude those modules as well (`grunt custom:-deferred,-ajax,-effects,-core/ready`). - **deferred**: Exclude jQuery.Deferred. This also excludes all modules that rely on Deferred, including **ajax**, **effects**, and **queue**, but replaces **core/ready** with **core/ready-no-deferred**.
- **exports/global**: Exclude the attachment of global jQuery variables ($ and jQuery) to the window. - **exports/global**: Exclude the attachment of global jQuery variables ($ and jQuery) to the window.
- **exports/amd**: Exclude the AMD definition. - **exports/amd**: Exclude the AMD definition.
As a special case, you may also replace the full jQuery `selector` module by using a special flag `grunt custom:-selector`. - **selector**: The full jQuery selector engine. When this module is excluded, it is replaced with a rudimentary selector engine based on the browser's `querySelectorAll` method that does not support jQuery selector extensions or enhanced semantics. See the [selector-native.js](https://github.com/jquery/jquery/blob/main/src/selector-native.js) file for details.
- **selector**: The full jQuery selector engine. When this module is excluded, it is replaced by a rudimentary selector engine based on the browser's `querySelectorAll` method that does not support jQuery selector extensions or enhanced semantics. See the [selector-native.js](https://github.com/jquery/jquery/blob/main/src/selector-native.js) file for details.
For backwards compatibility purposes, the name `sizzle` is recognized as the alias for `selector`.
*Note*: Excluding the full `selector` module will also exclude all jQuery selector extensions (such as `effects/animatedSelector` and `css/hiddenVisibleSelectors`). *Note*: Excluding the full `selector` module will also exclude all jQuery selector extensions (such as `effects/animatedSelector` and `css/hiddenVisibleSelectors`).
The build process shows a message for each dependent module it excludes or includes.
##### AMD name ##### AMD name
As an option, you can set the module name for jQuery's AMD definition. By default, it is set to "jquery", which plays nicely with plugins and third-party libraries, but there may be cases where you'd like to change this. Simply pass it to the `--amd` parameter: You can set the module name for jQuery's AMD definition. By default, it is set to "jquery", which plays nicely with plugins and third-party libraries, but there may be cases where you'd like to change this. Pass it to the `--amd` parameter:
```bash ```bash
grunt custom --amd="custom-name" npm run build -- --amd="custom-name"
``` ```
Or, to define anonymously, set the name to an empty string. Or, to define anonymously, leave the name blank.
```bash ```bash
grunt custom --amd="" npm run build -- --amd
``` ```
##### File name ##### File name and directory
The default name for the built jQuery file is `jquery.js`; it is placed under the `dist/` directory. It's possible to change the file name using the `--filename` parameter: The default name for the built jQuery file is `jquery.js`; it is placed under the `dist/` directory. It's possible to change the file name using `--filename` and the directory using `--dir`. `--dir` is relative to the project root.
```bash ```bash
grunt custom:slim --filename="jquery.slim.js" npm run build -- --slim --filename="jquery.slim.js" --dir="/tmp"
``` ```
This would create a slim version of jQuery and place it under `dist/jquery.slim.js`. In fact, this is exactly the command we use to generate the slim jQuery during the release process. This would create a slim version of jQuery and place it under `tmp/jquery.slim.js`.
#### Custom Build Examples #### Custom Build Examples
To create a custom build, first check out the version: Create a custom build using `npm run build`, listing the modules to be excluded. Excluding a top-level module also excludes its corresponding directory of modules.
```bash
git pull; git checkout VERSION
```
Where VERSION is the version you want to customize. Then, make sure all Node dependencies are installed:
```bash
npm install
```
Create the custom build using the `grunt custom` option, listing the modules to be excluded.
Exclude all **ajax** functionality: Exclude all **ajax** functionality:
```bash ```bash
grunt custom:-ajax npm run build -- --exclude=ajax
``` ```
Excluding **css** removes modules depending on CSS: **effects**, **offset**, **dimensions**. Excluding **css** removes modules depending on CSS: **effects**, **offset**, **dimensions**.
```bash ```bash
grunt custom:-css npm run build -- --exclude=css
``` ```
Exclude a bunch of modules: Exclude a bunch of modules (`-e` is an alias for `--exclude`):
```bash ```bash
grunt custom:-ajax/jsonp,-css,-deprecated,-dimensions,-effects,-offset,-wrap npm run build -- -e ajax/jsonp -e css -e deprecated -e dimensions -e effects -e offset -e wrap
``` ```
There is also a special alias to generate a build with the same configuration as the official jQuery Slim build is generated: There is a special alias to generate a build with the same configuration as the official jQuery Slim build:
```bash ```bash
grunt custom:slim npm run build -- --filename=jquery.slim.js --slim
``` ```
For questions or requests regarding custom builds, please start a thread on the [Developing jQuery Core](https://forum.jquery.com/developing-jquery-core) section of the forum. Due to the combinatorics and custom nature of these builds, they are not regularly tested in jQuery's unit test process. *Non-official custom builds are not regularly tested. Use them at your own risk.*
Running the Unit Tests Running the Unit Tests
-------------------------------------- --------------------------------------
@ -189,10 +172,10 @@ Make sure you have the necessary dependencies:
npm install npm install
``` ```
Start `grunt watch` or `npm start` to auto-build jQuery as you work: Start `npm start` to auto-build jQuery as you work:
```bash ```bash
grunt watch npm start
``` ```
@ -205,35 +188,6 @@ Run the unit tests with a local server that supports PHP. Ensure that you run th
Building to a different directory
---------------------------------
To copy the built jQuery files from `/dist` to another directory:
```bash
grunt && grunt dist:/path/to/special/location/
```
With this example, the output files would be:
```bash
/path/to/special/location/jquery.js
/path/to/special/location/jquery.min.js
```
To add a permanent copy destination, create a file in `dist/` called ".destination.json". Inside the file, paste and customize the following:
```json
{
"/Absolute/path/to/other/destination": true
}
```
Additionally, both methods can be combined.
Essential Git Essential Git
------------- -------------

69
build/command.js Executable file
View File

@ -0,0 +1,69 @@
"use strict";
const { build } = require( "./tasks/build" );
const yargs = require( "yargs/yargs" );
const slimExclude = require( "./tasks/lib/slim-exclude" );
const argv = yargs( process.argv.slice( 2 ) )
.version( false )
.command( {
command: "[options]",
describe: "Build a jQuery bundle"
} )
.option( "filename", {
alias: "f",
type: "string",
description:
"Set the filename of the built file. Defaults to jquery.js."
} )
.option( "dir", {
alias: "d",
type: "string",
description:
"Set the dir to which to output the built file. Defaults to /dist."
} )
.option( "version", {
alias: "v",
type: "string",
description:
"Set the version to include in the built file. " +
"Defaults to the version in package.json plus the " +
"short commit SHA and any excluded modules."
} )
.option( "watch", {
alias: "w",
type: "boolean",
description:
"Watch the source files and rebuild when they change."
} )
.option( "exclude", {
alias: "e",
type: "array",
description:
"Modules to exclude from the build. " +
"Specifying this option will cause the " +
"specified modules to be excluded from the build."
} )
.option( "include", {
alias: "i",
type: "array",
description:
"Modules to include in the build. " +
"Specifying this option will override the " +
"default included modules and only include these modules."
} )
.option( "slim", {
alias: "s",
type: "boolean",
description: "Build a slim bundle, which excludes " +
slimExclude.join( ", " )
} )
.option( "amd", {
type: "string",
description:
"Set the name of the AMD module. Leave blank to make an anonymous module."
} )
.help()
.argv;
build( argv );

View File

@ -1,50 +1,85 @@
/** /**
* Special concat/build task to handle various jQuery build requirements * Special build task to handle various jQuery build requirements.
* Concats AMD modules, removes their definitions, * Compiles JS modules into one bundle, sets the custom AMD name,
* and includes/excludes specified modules * and includes/excludes specified modules
*/ */
"use strict"; "use strict";
module.exports = function( grunt ) { const fs = require( "fs" );
var fs = require( "fs" ), const path = require( "path" );
requirejs = require( "requirejs" ), const util = require( "util" );
slimBuildFlags = require( "./lib/slim-build-flags" ), const exec = util.promisify( require( "child_process" ).exec );
srcFolder = __dirname + "/../../src/", const requirejs = require( "requirejs" );
rdefineEnd = /\}\s*?\);[^}\w]*$/, const excludedFromSlim = require( "./lib/slim-exclude" );
read = function( fileName ) { const pkg = require( "../../package.json" );
return grunt.file.read( srcFolder + fileName ); const isCleanWorkingDir = require( "./lib/isCleanWorkingDir" );
}, const minify = require( "./minify" );
const getTimestamp = require( "./lib/getTimestamp" );
const verifyNodeVersion = require( "./lib/verifyNodeVersion" );
const srcFolder = path.resolve( __dirname, "../../src" );
// Catch `// @CODE` and subsequent comment lines event if they don't start const rdefineEnd = /\}\s*?\);[^}\w]*$/;
// in the first column.
wrapper = read( "wrapper.js" ).split( /[\x20\t]*\/\/ @CODE\n(?:[\x20\t]*\/\/[^\n]+\n)*/ ),
config = { const minimum = [ "core" ];
baseUrl: "src",
name: "jquery",
// Allow strict mode // Exclude specified modules if the module matching the key is removed
useStrict: true, const removeWith = {
ajax: [ "manipulation/_evalUrl", "deprecated/ajax-event-alias" ],
callbacks: [ "deferred" ],
css: [ "effects", "dimensions", "offset" ],
"css/showHide": [ "effects" ],
deferred: {
remove: [ "ajax", "effects", "queue", "core/ready" ],
include: [ "core/ready-no-deferred" ]
},
event: [ "deprecated/ajax-event-alias", "deprecated/event" ],
selector: [ "css/hiddenVisibleSelectors", "effects/animatedSelector" ]
};
// We have multiple minify steps async function read( filename ) {
optimize: "none", return fs.promises.readFile( path.join( srcFolder, filename ), "utf8" );
}
// Include dependencies loaded with require // Remove the src folder and file extension
findNestedDependencies: true, // and ensure unix-style path separators
function moduleName( filename ) {
return filename
.replace( `${srcFolder}${path.sep}`, "" )
.replace( /\.js$/, "" )
.split( path.sep )
.join( path.posix.sep );
}
// Avoid inserting define() placeholder async function readdirRecursive( dir, all = [] ) {
skipModuleInsertion: true, let files;
try {
files = await fs.promises.readdir( path.join( srcFolder, dir ), {
withFileTypes: true
} );
} catch ( e ) {
return all;
}
for ( const file of files ) {
const filepath = path.join( dir, file.name );
// Avoid breaking semicolons inserted by r.js if ( file.isDirectory() ) {
skipSemiColonInsertion: true, all.push( ...( await readdirRecursive( filepath ) ) );
wrap: { } else {
start: wrapper[ 0 ].replace( /\/\*\s*eslint(?: |-).*\s*\*\/\n/, "" ), all.push( moduleName( filepath ) );
end: wrapper[ 1 ] }
}, }
rawText: {}, return all;
onBuildWrite: convert }
};
async function getRequireConfig( { amd } = {} ) {
const wrapperSource = await read( "wrapper.js" );
// Catch `// @CODE` and subsequent comment lines event if they don't start
// in the first column.
const wrapper = wrapperSource.split(
/[\x20\t]*\/\/ @CODE\n(?:[\x20\t]*\/\/[^\n]+\n)*/
);
/** /**
* Strip all definitions generated by requirejs * Strip all definitions generated by requirejs
@ -57,7 +92,6 @@ module.exports = function( grunt ) {
* @param {String} contents The contents to be written (including their AMD wrappers) * @param {String} contents The contents to be written (including their AMD wrappers)
*/ */
function convert( name, path, contents ) { function convert( name, path, contents ) {
var amdName;
// Convert var modules // Convert var modules
if ( /.\/var\//.test( path.replace( process.cwd(), "" ) ) ) { if ( /.\/var\//.test( path.replace( process.cwd(), "" ) ) ) {
@ -96,273 +130,214 @@ module.exports = function( grunt ) {
} }
// AMD Name // AMD Name
if ( ( amdName = grunt.option( "amd" ) ) != null && /^exports\/amd$/.test( name ) ) { if ( amd != null && /^exports\/amd$/.test( name ) ) {
if ( amdName ) { if ( amd ) {
grunt.log.writeln( "Naming jQuery with AMD name: " + amdName ); console.log( "Naming jQuery with AMD name: " + amd );
} else { } else {
grunt.log.writeln( "AMD name now anonymous" ); console.log( "AMD name now anonymous" );
} }
// Remove the comma for anonymous defines // Remove the comma for anonymous defines
contents = contents contents = contents
.replace( /(\s*)"jquery"(\,\s*)/, amdName ? "$1\"" + amdName + "\"$2" : "" ); .replace( /(\s*)"jquery"(\,\s*)/, amd ? "$1\"" + amd + "\"$2" : "" );
} }
return contents; return contents;
} }
grunt.registerMultiTask( return {
"build", baseUrl: "src",
"Concatenate source, remove sub AMD definitions, " + name: "jquery",
"(include/exclude modules with +/- flags), embed date/version",
function() {
var flag, index,
done = this.async(),
flags = this.flags,
optIn = flags[ "*" ],
name = grunt.option( "filename" ),
minimum = this.data.minimum,
removeWith = this.data.removeWith,
excluded = [],
included = [],
version = grunt.config( "pkg.version" ),
/** // Allow strict mode
* Recursively calls the excluder to remove on all modules in the list useStrict: true,
* @param {Array} list
* @param {String} [prepend] Prepend this to the module name.
* Indicates we're walking a directory
*/
excludeList = function( list, prepend ) {
if ( list ) {
prepend = prepend ? prepend + "/" : "";
list.forEach( function( module ) {
// Exclude var modules as well // We have multiple minify steps
if ( module === "var" ) { optimize: "none",
excludeList(
fs.readdirSync( srcFolder + prepend + module ), prepend + module
);
return;
}
if ( prepend ) {
// Skip if this is not a js file and we're walking files in a dir // Include dependencies loaded with require
if ( !( module = /([\w-\/]+)\.js$/.exec( module ) ) ) { findNestedDependencies: true,
return;
}
// Prepend folder name if passed // Avoid inserting define() placeholder
// Remove .js extension skipModuleInsertion: true,
module = prepend + module[ 1 ];
}
// Avoid infinite recursion // Avoid breaking semicolons inserted by r.js
if ( excluded.indexOf( module ) === -1 ) { skipSemiColonInsertion: true,
excluder( "-" + module ); wrap: {
} start: wrapper[ 0 ].replace( /\/\*\s*eslint(?: |-).*\s*\*\/\n/, "" ),
} ); end: wrapper[ 1 ]
} },
}, rawText: {},
onBuildWrite: convert
};
}
/** function unique( array ) {
* Adds the specified module to the excluded or included list, depending on the flag return [ ...new Set( array ) ];
* @param {String} flag A module path relative to }
* the src directory starting with + or - to indicate
* whether it should be included or excluded
*/
excluder = function( flag ) {
var additional,
m = /^(\+|-|)([\w\/-]+)$/.exec( flag ),
exclude = m[ 1 ] === "-",
module = m[ 2 ];
// Recognize the legacy `sizzle` alias async function checkExclude( exclude, include ) {
if ( module === "sizzle" ) { const included = [ ...include ];
module = "selector"; const excluded = [ ...exclude ];
}
if ( exclude ) { for ( const module of exclude ) {
if ( minimum.indexOf( module ) !== -1 ) {
// Can't exclude certain modules throw new Error( `Module \"${module}\" is a minimum requirement.` );
if ( minimum.indexOf( module ) === -1 ) {
// Add to excluded
if ( excluded.indexOf( module ) === -1 ) {
grunt.log.writeln( flag );
excluded.push( module );
// Exclude all files in the folder of the same name
// These are the removable dependencies
// It's fine if the directory is not there
try {
// `selector` is a special case as we don't just remove
// the module, but we replace it with `selector-native`
// which re-uses parts of the `src/selector` folder.
if ( module !== "selector" ) {
excludeList(
fs.readdirSync( `${ srcFolder }/${ module }` ),
module
);
}
} catch ( e ) {
grunt.verbose.writeln( e );
}
}
additional = removeWith[ module ];
// Check removeWith list
if ( additional ) {
excludeList( additional.remove || additional );
if ( additional.include ) {
included = included.concat( additional.include );
grunt.log.writeln( "+" + additional.include );
}
}
} else {
grunt.log.error( "Module \"" + module + "\" is a minimum requirement." );
}
} else {
grunt.log.writeln( flag );
included.push( module );
}
};
// Filename can be passed to the command line using
// command line options
// e.g. grunt build --filename=jquery-custom.js
name = name ? ( "dist/" + name ) : this.data.dest;
// append commit id to version
if ( process.env.COMMIT ) {
version += " " + process.env.COMMIT;
} }
// figure out which files to exclude based on these rules in this order: // Exclude all files in the dir of the same name
// dependency explicit exclude // These are the removable dependencies
// > explicit exclude // It's fine if the directory is not there
// > explicit include // `selector` is a special case as we don't just remove
// > dependency implicit exclude // the module, but we replace it with `selector-native`
// > implicit exclude // which re-uses parts of the `src/selector` folder.
// examples: // "sizzle" is legacy for selector
// * none (implicit exclude) if ( module !== "selector" && module !== "sizzle" ) {
// *:* all (implicit include) const files = await readdirRecursive( module );
// *:*:-css all except css and dependents (explicit > implicit) excluded.push( ...files );
// *:*:-css:+effects same (excludes effects because explicit include is
// trumped by explicit exclude of dependency)
// *:+effects none except effects and its dependencies
// (explicit include trumps implicit exclude of dependency)
delete flags[ "*" ];
for ( flag in flags ) {
excluder( flag );
} }
// Handle full selector module exclusion. // Check removeWith list
// Replace with selector-native. const additional = removeWith[ module ];
if ( excluded.indexOf( "selector" ) > -1 ) { if ( additional ) {
config.rawText.selector = "define([ \"./selector-native\" ]);"; const [ additionalExcluded, additionalIncluded ] = await checkExclude(
additional.remove || additional,
additional.include || []
);
excluded.push( ...additionalExcluded );
included.push( ...additionalIncluded );
} }
}
// Replace exports/global with a noop noConflict return [ unique( excluded ), unique( included ) ];
if ( ( index = excluded.indexOf( "exports/global" ) ) > -1 ) { }
config.rawText[ "exports/global" ] = "define( [\n\t\"../core\"\n], " +
"function( jQuery ) {\n\tjQuery.noConflict = function() {};\n} );";
excluded.splice( index, 1 );
}
grunt.verbose.writeflags( excluded, "Excluded" ); async function build( {
grunt.verbose.writeflags( included, "Included" ); amd,
dir = "dist",
exclude = [],
filename = "jquery.js",
include = [],
slim = false,
version
} = {} ) {
// append excluded modules to version // Add the short commit hash to the version string
// when the version is not for a release.
if ( !version ) {
const { stdout } = await exec( "git rev-parse --short HEAD" );
const isClean = await isCleanWorkingDir();
// Add "+SHA" if the version is not set.
// Add ".dirty" as well if the working dir is not clean.
version = `${pkg.version}+${stdout.trim()}${isClean ? "" : ".dirty"}`;
}
await fs.promises.mkdir( dir, { recursive: true } );
// Exclude slim modules when slim is true
const [ excluded, included ] = await checkExclude(
slim ? exclude.concat( excludedFromSlim ) : exclude,
include
);
const config = await getRequireConfig( { amd } );
// Replace exports/global with a noop noConflict
if ( excluded.includes( "exports/global" ) ) {
const index = excluded.indexOf( "exports/global" );
config.rawText[ "exports/global" ] = "define( [\n\t\"../core\"\n], " +
"function( jQuery ) {\n\tjQuery.noConflict = function() {};\n} );";
excluded.splice( index, 1 );
}
// "sizzle" is legacy for selector
if ( excluded.indexOf( "selector" ) > -1 || excluded.indexOf( "sizzle" ) > -1 ) {
config.rawText.selector = "define( [ \"./selector-native\" ] );";
}
if ( excluded.length ) {
// Append excluded modules to version.
// Skip adding exclusions for slim builds.
// Don't worry about semver syntax for these.
if ( excluded.length ) { if ( excluded.length ) {
version += " -" + excluded.join( ",-" ); version += " -" + excluded.join( ",-" );
// set pkg.version to version with excludes, so minified file picks it up
grunt.config.set( "pkg.version", version );
grunt.verbose.writeln( "Version changed to " + version );
// Have to use shallow or core will get excluded since it is a dependency
config.excludeShallow = excluded;
} }
// Have to use shallow or core will get excluded since it is a dependency
config.excludeShallow = excluded;
}
if ( included.length ) {
config.include = included; config.include = included;
/** // Append extra included modules to version.
* Handle Final output from the optimizer if ( included.length ) {
* @param {String} compiled version += " +" + included.join( ",+" );
*/
config.out = function( compiled ) {
compiled = compiled
// Embed Version
.replace( /@VERSION/g, version )
// Embed Date
// yyyy-mm-ddThh:mmZ
.replace( /@DATE/g, ( new Date() ).toISOString().replace( /:\d+\.\d+Z$/, "Z" ) );
// Write concatenated source to file
grunt.file.write( name, compiled );
};
// Turn off opt-in if necessary
if ( !optIn ) {
// Overwrite the default inclusions with the explicit ones provided
config.rawText.jquery = "define( [\n" +
( included.length ?
included.map( module => "\t\"./" + module + "\"" ).join( ",\n" ) :
"" ) +
"\n] );";
} }
// Trace dependencies and concatenate files // Overwrite the default inclusions with the explicit ones provided
requirejs.optimize( config, function( response ) { config.rawText.jquery = "define( [\n" +
grunt.verbose.writeln( response ); included.map( module => "\t\"./" + module + "\"" ).join( ",\n" ) +
grunt.log.ok( "File '" + name + "' created." ); "\n] );";
done(); }
}, function( err ) {
done( err ); /**
* Handle Final output from the optimizer
* @param {String} compiled
*/
config.out = async function( compiled ) {
const compiledContents = compiled
// Embed Version
.replace( /@VERSION/g, version )
// Embed Date
// yyyy-mm-ddThh:mmZ
.replace( /@DATE/g, new Date().toISOString().replace( /:\d+\.\d+Z$/, "Z" ) );
// Write concatenated source to file
await fs.promises.writeFile(
path.join( dir, filename ),
compiledContents
);
};
await new Promise( ( resolve, reject ) => {
requirejs.optimize( config, () => {
// Wait a beat. For some reason, the write can
// take a moment after this to complete in Node 10.
setTimeout( resolve, 100 );
}, ( error ) => {
console.error( error );
reject( error );
} ); } );
} ); } );
// Special "alias" task to make custom build creation less grawlix-y console.log( `[${getTimestamp()}] ${filename} v${version} created.` );
// Translation example
//
// grunt custom:+ajax,-dimensions,-effects,-offset
//
// Becomes:
//
// grunt build:*:*:+ajax:-dimensions:-effects:-offset
//
// There's also a special "slim" alias that resolves to the jQuery Slim build
// configuration:
//
// grunt custom:slim
grunt.registerTask( "custom", function() {
var args = this.args,
modules = args.length ?
args[ 0 ]
.split( "," )
// Replace "slim" with respective exclusions meant for await minify( { filename, dir } );
// the official slim build }
.reduce( ( acc, elem ) => acc.concat(
elem === "slim" ?
slimBuildFlags :
[ elem ]
), [] )
.join( ":" ) : async function buildDefaultFiles( { version } = {} ) {
""; await Promise.all( [
build( { version } ),
build( { filename: "jquery.slim.js", slim: true, version } )
] );
grunt.log.writeln( "Creating custom build...\n" ); // Earlier Node.js versions do not support the ESM format.
grunt.task.run( [ if ( !verifyNodeVersion() ) {
"build:*:*" + ( modules ? ":" + modules : "" ), return;
"uglify", }
"remove_map_comment",
"dist" const { compareSize } = await import( "./compare_size.mjs" );
] ); return compareSize( {
files: [
"dist/jquery.min.js",
"dist/jquery.slim.min.js"
]
} ); } );
}; }
module.exports = { build, buildDefaultFiles };

View File

@ -0,0 +1,174 @@
import chalk from "chalk";
import fs from "node:fs";
import { promisify } from "node:util";
import zlib from "node:zlib";
import { exec as nodeExec } from "node:child_process";
import isCleanWorkingDir from "./lib/isCleanWorkingDir.js";
const VERSION = 1;
const gzip = promisify( zlib.gzip );
const exec = promisify( nodeExec );
async function getBranchName() {
const { stdout } = await exec( "git rev-parse --abbrev-ref HEAD" );
return stdout.trim();
}
async function getCommitHash() {
const { stdout } = await exec( "git rev-parse HEAD" );
return stdout.trim();
}
function getBranchHeader( branch, commit ) {
let branchHeader = branch.trim();
if ( commit ) {
branchHeader = chalk.bold( branchHeader ) + chalk.gray( ` @${commit}` );
} else {
branchHeader = chalk.italic( branchHeader );
}
return branchHeader;
}
async function getCache( loc ) {
let cache;
try {
const contents = await fs.promises.readFile( loc, "utf8" );
cache = JSON.parse( contents );
} catch ( err ) {
return {};
}
const lastRun = cache[ " last run" ];
if ( !lastRun || !lastRun.meta || lastRun.meta.version !== VERSION ) {
console.log( "Compare cache version mismatch. Rewriting..." );
return {};
}
return cache;
}
function cacheResults( results ) {
const files = Object.create( null );
results.forEach( function( result ) {
files[ result.filename ] = {
raw: result.raw,
gz: result.gz
};
} );
return files;
}
function saveCache( loc, cache ) {
return fs.promises.writeFile( loc, JSON.stringify( cache ) );
}
function compareSizes( existing, current, padLength ) {
if ( typeof current !== "number" ) {
return chalk.grey( `${existing}`.padStart( padLength ) );
}
const delta = current - existing;
if ( delta > 0 ) {
return chalk.red( `+${delta}`.padStart( padLength ) );
}
return chalk.green( `${delta}`.padStart( padLength ) );
}
export async function compareSize( { cache = ".sizecache.json", files } = {} ) {
if ( !files || !files.length ) {
throw new Error( "No files specified" );
}
const branch = await getBranchName();
const commit = await getCommitHash();
const sizeCache = await getCache( cache );
let rawPadLength = 0;
let gzPadLength = 0;
const results = await Promise.all(
files.map( async function( filename ) {
let contents = await fs.promises.readFile( filename, "utf8" );
// Remove the short SHA and .dirty from comparisons.
// The short SHA so commits can be compared against each other
// and .dirty to compare with the existing branch during development.
const sha = /jQuery v\d+.\d+.\d+(?:-\w+)?\+(?:slim.)?([^ \.]+(?:\.dirty)?)/.exec( contents )[ 1 ];
contents = contents.replace( new RegExp( sha, "g" ), "" );
const size = Buffer.byteLength( contents, "utf8" );
const gzippedSize = ( await gzip( contents ) ).length;
// Add one to give space for the `+` or `-` in the comparison
rawPadLength = Math.max( rawPadLength, size.toString().length + 1 );
gzPadLength = Math.max( gzPadLength, gzippedSize.toString().length + 1 );
return { filename, raw: size, gz: gzippedSize };
} )
);
const sizeHeader = "raw".padStart( rawPadLength ) +
"gz".padStart( gzPadLength + 1 ) +
" Filename";
const sizes = results.map( function( result ) {
const rawSize = result.raw.toString().padStart( rawPadLength );
const gzSize = result.gz.toString().padStart( gzPadLength );
return `${rawSize} ${gzSize} ${result.filename}`;
} );
const comparisons = Object.keys( sizeCache ).map( function( branch ) {
const meta = sizeCache[ branch ].meta || {};
const commit = meta.commit;
const files = sizeCache[ branch ].files;
const branchSizes = Object.keys( files ).map( function( filename ) {
const branchResult = files[ filename ];
const compareResult = results.find( function( result ) {
return result.filename === filename;
} ) || {};
const compareRaw = compareSizes( branchResult.raw, compareResult.raw, rawPadLength );
const compareGz = compareSizes( branchResult.gz, compareResult.gz, gzPadLength );
return `${compareRaw} ${compareGz} ${filename}`;
} );
return [
"", // New line before each branch
getBranchHeader( branch, commit ),
sizeHeader,
...branchSizes
].join( "\n" );
} );
const output = [
"", // Opening new line
chalk.bold( "Sizes" ),
sizeHeader,
...sizes,
...comparisons,
"" // Closing new line
].join( "\n" );
console.log( output );
// Always save the last run
// Save version under last run
sizeCache[ " last run" ] = {
meta: { version: VERSION },
files: cacheResults( results )
};
// Only save cache for the current branch
// if the working directory is clean.
if ( await isCleanWorkingDir() ) {
sizeCache[ branch ] = {
meta: { commit },
files: cacheResults( results )
};
console.log( `Saved cache for ${branch}.` );
}
await saveCache( cache, sizeCache );
return results;
}

View File

@ -1,71 +1,31 @@
"use strict"; "use strict";
module.exports = function( grunt ) { // Process files for distribution.
const fs = require( "fs" ); module.exports = function processForDist( text, filename ) {
const filename = grunt.option( "filename" ); if ( !text ) {
const distPaths = [ throw new Error( "text required for processForDist" );
`dist/${ filename }`, }
`dist/${ filename.replace( ".js", ".min.js" ) }`,
`dist/${ filename.replace( ".js", ".min.map" ) }`
];
// Process files for distribution if ( !filename ) {
grunt.registerTask( "dist", function() { throw new Error( "filename required for processForDist" );
let stored, flags, paths, nonascii; }
// Check for stored destination paths // Ensure files use only \n for line endings, not \r\n
// ( set in dist/.destination.json ) if ( /\x0d\x0a/.test( text ) ) {
stored = Object.keys( grunt.config( "dst" ) ); throw new Error( filename + ": Incorrect line endings (\\r\\n)" );
}
// Allow command line input as well // Ensure only ASCII chars so script tags don't need a charset attribute
flags = Object.keys( this.flags ); if ( text.length !== Buffer.byteLength( text, "utf8" ) ) {
let message = filename + ": Non-ASCII characters detected:\n";
// Combine all output target paths for ( let i = 0; i < text.length; i++ ) {
paths = [].concat( stored, flags ).filter( function( path ) { const c = text.charCodeAt( i );
return path !== "*"; if ( c > 127 ) {
} ); message += "- position " + i + ": " + c + "\n";
message += "==> " + text.substring( i - 20, i + 20 );
// Ensure the dist files are pure ASCII break;
nonascii = false;
distPaths.forEach( function( filename ) {
let i, c;
const text = fs.readFileSync( filename, "utf8" );
// Ensure files use only \n for line endings, not \r\n
if ( /\x0d\x0a/.test( text ) ) {
grunt.log.writeln( filename + ": Incorrect line endings (\\r\\n)" );
nonascii = true;
} }
}
// Ensure only ASCII chars so script tags don't need a charset attribute throw new Error( message );
if ( text.length !== Buffer.byteLength( text, "utf8" ) ) { }
grunt.log.writeln( filename + ": Non-ASCII characters detected:" );
for ( i = 0; i < text.length; i++ ) {
c = text.charCodeAt( i );
if ( c > 127 ) {
grunt.log.writeln( "- position " + i + ": " + c );
grunt.log.writeln( "-- " + text.substring( i - 20, i + 20 ) );
break;
}
}
nonascii = true;
}
// Optionally copy dist files to other locations
paths.forEach( function( path ) {
let created;
if ( !/\/$/.test( path ) ) {
path += "/";
}
created = path + filename.replace( "dist/", "" );
grunt.file.write( created, text );
grunt.log.writeln( "File '" + created + "' created." );
} );
} );
return !nonascii;
} );
}; };

View File

@ -0,0 +1,9 @@
"use strict";
module.exports = function getTimestamp() {
const now = new Date();
const hours = now.getHours().toString().padStart( 2, "0" );
const minutes = now.getMinutes().toString().padStart( 2, "0" );
const seconds = now.getSeconds().toString().padStart( 2, "0" );
return `${hours}:${minutes}:${seconds}`;
};

View File

@ -0,0 +1,9 @@
"use strict";
const util = require( "util" );
const exec = util.promisify( require( "child_process" ).exec );
module.exports = async function isCleanWorkingDir() {
const { stdout } = await exec( "git status --untracked-files=no --porcelain" );
return !stdout.trim();
};

View File

@ -2,6 +2,6 @@
// NOTE: keep it in sync with test/data/testinit.js // NOTE: keep it in sync with test/data/testinit.js
module.exports = [ module.exports = [
"-ajax", "ajax",
"-effects" "effects"
]; ];

View File

@ -1,16 +0,0 @@
"use strict";
// Run Node with provided parameters: the first one being the Grunt
// done function and latter ones being files to be tested.
// See the comment in ../node_smoke_tests.js for more information.
module.exports = function spawnTest( done, command ) {
var spawn = require( "child_process" ).spawn;
spawn( command, {
stdio: "inherit",
shell: true
} )
.on( "close", function( code ) {
done( code === 0 );
} );
};

View File

@ -0,0 +1,12 @@
"use strict";
const { version } = require( "process" );
const nodeV16OrNewer = !/^v1[0-5]\./.test( version );
module.exports = function verifyNodeVersion() {
if ( !nodeV16OrNewer ) {
console.log( "Old Node.js detected, task skipped..." );
return false;
}
return true;
};

83
build/tasks/minify.js Normal file
View File

@ -0,0 +1,83 @@
"use strict";
const UglifyJS = require( "uglify-js" );
const fs = require( "fs" );
const path = require( "path" );
const processForDist = require( "./dist" );
const getTimestamp = require( "./lib/getTimestamp" );
const rjs = /\.js$/;
module.exports = async function minify( { dir, filename } ) {
const filepath = path.join( dir, filename );
const contents = await fs.promises.readFile( filepath, "utf8" );
const version = /jQuery JavaScript Library ([^\n]+)/.exec( contents )[ 1 ];
const banner = `/*! jQuery ${version}` +
" | (c) OpenJS Foundation and other contributors" +
" | jquery.org/license */";
const minFilename = filename.replace( rjs, ".min.js" );
const mapFilename = filename.replace( rjs, ".min.map" );
const { code, error, map: incompleteMap, warning } = UglifyJS.minify(
contents,
{
compress: {
hoist_funs: false,
loops: false,
// Support: IE <11
// typeofs transformation is unsafe for IE9-10
// See https://github.com/mishoo/UglifyJS2/issues/2198
typeofs: false
},
output: {
ascii_only: true,
// Support: Android 4.0 only
// UglifyJS 3 breaks Android 4.0 if this option is not enabled.
// This is in lieu of setting ie for all of mangle, compress, and output
ie8: true,
preamble: banner
},
sourceMap: {
filename: minFilename
}
}
);
if ( error ) {
throw new Error( error );
}
if ( warning ) {
console.warn( warning );
}
// The map's `sources` property is set to an array index.
// Fix it by setting it to the correct filename.
const map = JSON.stringify( {
...JSON.parse( incompleteMap ),
file: minFilename,
sources: [ filename ]
} );
await Promise.all( [
fs.promises.writeFile(
path.join( dir, minFilename ),
code
),
fs.promises.writeFile(
path.join( dir, mapFilename ),
map
)
] );
// Always process files for dist
// Doing it here avoids extra file reads
processForDist( contents, filename );
processForDist( code, minFilename );
processForDist( map, mapFilename );
console.log( `[${getTimestamp()}] ${minFilename} ${version} with ${mapFilename} created.` );
};

View File

@ -1,42 +1,42 @@
"use strict"; "use strict";
module.exports = ( grunt ) => { const fs = require( "fs" );
const fs = require( "fs" ); const util = require( "util" );
const spawnTest = require( "./lib/spawn_test.js" ); const exec = util.promisify( require( "child_process" ).exec );
const nodeV16OrNewer = !/^v1[0-5]\./.test( process.version ); const verifyNodeVersion = require( "./lib/verifyNodeVersion" );
grunt.registerTask( "node_smoke_tests", function( jQueryModuleSpecifier = "./dist/jquery.js" ) { if ( !verifyNodeVersion() ) {
if ( !nodeV16OrNewer ) { return;
grunt.log.writeln( "Old Node.js detected, running the task " + }
`"node_smoke_tests:${ jQueryModuleSpecifier }" skipped...` );
return;
}
const testsDir = "./test/node_smoke_tests"; // Fire up all tests defined in test/node_smoke_tests/*.js in spawned sub-processes.
const nodeSmokeTests = []; // All the files under test/node_smoke_tests/*.js are supposed to exit with 0 code
// on success or another one on failure. Spawning in sub-processes is
// important so that the tests & the main process don't interfere with
// each other, e.g. so that they don't share the `require` cache.
// Fire up all tests defined in test/node_smoke_tests/*.js in spawned sub-processes. async function runTests( { module } ) {
// All the files under test/node_smoke_tests/*.js are supposed to exit with 0 code const dir = "./test/node_smoke_tests";
// on success or another one on failure. Spawning in sub-processes is const files = await fs.promises.readdir( dir, { withFileTypes: true } );
// important so that the tests & the main process don't interfere with const testFiles = files.filter( ( testFilePath ) => testFilePath.isFile() );
// each other, e.g. so that they don't share the `require` cache.
fs.readdirSync( testsDir ) if ( !testFiles.length ) {
.filter( ( testFilePath ) => throw new Error( `No test files found for "${module}"` );
fs.statSync( `${ testsDir }/${ testFilePath }` ).isFile() && }
/\.[cm]?js$/.test( testFilePath )
)
.forEach( ( testFilePath ) => {
const taskName = `node_${ testFilePath.replace( /\.[cm]?js$/, "" ) }:${ jQueryModuleSpecifier }`;
grunt.registerTask( taskName, function() { await Promise.all(
spawnTest( this.async(), `node "${ testsDir }/${ testFiles.map( ( testFile ) =>
testFilePath }" ${ jQueryModuleSpecifier }` ); exec( `node "${dir}/${testFile.name}" ${module}` )
} ); )
);
console.log( `Node smoke tests passed for "${module}".` );
}
nodeSmokeTests.push( taskName ); async function runDefaultTests() {
} ); await Promise.all( [
runTests( { module: "./dist/jquery.js" } ),
runTests( { module: "./dist/jquery.slim.js" } )
] );
}
grunt.task.run( nodeSmokeTests ); runDefaultTests();
} );
};

42
build/tasks/npmcopy.js Normal file
View File

@ -0,0 +1,42 @@
"use strict";
const fs = require( "fs" );
const path = require( "path" );
const projectDir = path.resolve( __dirname, "..", ".." );
const files = {
"bootstrap/bootstrap.css": "bootstrap/dist/css/bootstrap.css",
"bootstrap/bootstrap.min.css": "bootstrap/dist/css/bootstrap.min.css",
"bootstrap/bootstrap.min.css.map": "bootstrap/dist/css/bootstrap.min.css.map",
"core-js-bundle/core-js-bundle.js": "core-js-bundle/minified.js",
"core-js-bundle/LICENSE": "core-js-bundle/LICENSE",
"npo/npo.js": "native-promise-only/lib/npo.src.js",
"qunit/qunit.js": "qunit/qunit/qunit.js",
"qunit/qunit.css": "qunit/qunit/qunit.css",
"qunit/LICENSE.txt": "qunit/LICENSE.txt",
"requirejs/require.js": "requirejs/require.js",
"sinon/sinon.js": "sinon/pkg/sinon.js",
"sinon/LICENSE.txt": "sinon/LICENSE"
};
async function npmcopy() {
await fs.promises.mkdir( path.resolve( projectDir, "external" ), {
recursive: true
} );
for ( const [ dest, source ] of Object.entries( files ) ) {
const from = path.resolve( projectDir, "node_modules", source );
const to = path.resolve( projectDir, "external", dest );
const toDir = path.dirname( to );
await fs.promises.mkdir( toDir, { recursive: true } );
await fs.promises.copyFile( from, to );
console.log( `${source}${dest}` );
}
}
npmcopy();

View File

@ -1,27 +1,32 @@
"use strict"; "use strict";
module.exports = grunt => { const { spawn } = require( "child_process" );
const timeout = 2000; const verifyNodeVersion = require( "./lib/verifyNodeVersion" );
const spawnTest = require( "./lib/spawn_test.js" ); const path = require( "path" );
const os = require( "os" );
grunt.registerTask( "promises_aplus_tests", if ( !verifyNodeVersion() ) {
[ "promises_aplus_tests:deferred", "promises_aplus_tests:when" ] ); return;
}
grunt.registerTask( "promises_aplus_tests:deferred", function() { const command = path.resolve(
spawnTest( this.async(), __dirname,
"\"" + __dirname + "/../../node_modules/.bin/promises-aplus-tests\"" + `../../node_modules/.bin/promises-aplus-tests${os.platform() === "win32" ? ".cmd" : ""}`
" test/promises_aplus_adapters/deferred.js" + );
" --reporter dot" + const args = [ "--reporter", "dot", "--timeout", "2000" ];
" --timeout " + timeout const tests = [
"test/promises_aplus_adapters/deferred.js",
"test/promises_aplus_adapters/when.js"
];
async function runTests() {
tests.forEach( ( test ) => {
spawn(
command,
[ test ].concat( args ),
{ stdio: "inherit" }
); );
} ); } );
}
grunt.registerTask( "promises_aplus_tests:when", function() { runTests();
spawnTest( this.async(),
"\"" + __dirname + "/../../node_modules/.bin/promises-aplus-tests\"" +
" test/promises_aplus_adapters/when.js" +
" --reporter dot" +
" --timeout " + timeout
);
} );
};

View File

@ -0,0 +1,17 @@
"use strict";
const fs = require( "fs" );
async function generateFixture() {
const fixture = await fs.promises.readFile( "./test/data/qunit-fixture.html", "utf8" );
await fs.promises.writeFile(
"./test/data/qunit-fixture.js",
"// Generated by build/tasks/qunit-fixture.js\n" +
"QUnit.config.fixture = " +
JSON.stringify( fixture.replace( /\r\n/g, "\n" ) ) +
";\n"
);
console.log( "Updated ./test/data/qunit-fixture.js" );
}
generateFixture();

View File

@ -1,22 +0,0 @@
"use strict";
var fs = require( "fs" );
module.exports = function( grunt ) {
grunt.registerTask( "qunit_fixture", function() {
var dest = "./test/data/qunit-fixture.js";
fs.writeFileSync(
dest,
"// Generated by build/tasks/qunit_fixture.js\n" +
"QUnit.config.fixture = " +
JSON.stringify(
fs.readFileSync(
"./test/data/qunit-fixture.html",
"utf8"
).toString().replace( /\r\n/g, "\n" )
) +
";\n"
);
grunt.log.ok( "Updated " + dest + "." );
} );
};

View File

@ -1,17 +0,0 @@
"use strict";
var fs = require( "fs" );
module.exports = function( grunt ) {
var config = grunt.config( "uglify.all.files" );
grunt.registerTask( "remove_map_comment", function() {
var minLoc = grunt.config.process( Object.keys( config )[ 0 ] );
// Remove the source map comment; it causes way too many problems.
// The map file is still generated for manual associations
// https://github.com/jquery/jquery/issues/1707
var text = fs.readFileSync( minLoc, "utf8" )
.replace( /\/\/# sourceMappingURL=\S+/, "" );
fs.writeFileSync( minLoc, text );
} );
};

35
dist/.eslintrc.json vendored
View File

@ -1,35 +0,0 @@
{
"root": true,
"parserOptions": {
"ecmaVersion": 5,
"sourceType": "script"
},
"overrides": [
{
"files": "jquery{,.slim}.min.js",
"parserOptions": {
"ecmaVersion": 5,
"sourceType": "script"
}
},
{
"files": "jquery{,.slim}.js",
"extends": "../.eslintrc-browser.json",
"rules": {
// That is okay for the built version
"no-multiple-empty-lines": "off",
// When custom compilation is used, the version string
// can get large. Accept that in the built version.
"max-len": "off",
"one-var": "off"
}
}
]
}

271
eslint.config.js Normal file
View File

@ -0,0 +1,271 @@
"use strict";
const jqueryConfig = require( "eslint-config-jquery" );
const globals = require( "globals" );
module.exports = [
{
// Only global ignores will bypass the parser
// and avoid JS parsing errors
// See https://github.com/eslint/eslint/discussions/17412
ignores: [
"external",
"test/data/json_obj.js"
]
},
{
files: [
"eslint.config.js",
"Gruntfile.js",
"test/node_smoke_tests/**",
"test/promises_aplus_adapters/**",
"test/middleware-mockserver.js"
],
languageOptions: {
globals: {
...globals.node
},
sourceType: "commonjs"
},
rules: {
...jqueryConfig.rules,
strict: [ "error", "global" ]
}
},
// Source
{
files: [ "src/**" ],
languageOptions: {
// The browser env is not enabled on purpose so that code takes
// all browser-only globals from window instead of assuming
// they're available as globals. This makes it possible to use
// jQuery with tools like jsdom which provide a custom window
// implementation.
globals: {
define: false,
window: false
},
sourceType: "commonjs"
},
rules: {
...jqueryConfig.rules,
indent: [
"error",
"tab",
{
outerIIFEBody: 0,
// Ignore the top level function defining an AMD module
ignoredNodes: [
"Program > ExpressionStatement > CallExpression > :last-child > *"
]
}
],
"one-var": [ "error", { var: "always" } ],
strict: [ "error", "function" ]
}
},
{
files: [ "src/selector.js" ],
rules: {
indent: "off"
}
},
{
files: [ "src/wrapper.js" ],
languageOptions: {
globals: {
jQuery: false,
module: true
},
sourceType: "script"
},
rules: {
"no-unused-vars": "off",
indent: [
"error",
"tab",
{
// Unlike other codes, "wrapper.js" is implemented in UMD.
// So it required a specific exception for jQuery's UMD
// Code Style. This makes that indentation check is not
// performed for 1 depth of outer FunctionExpressions
ignoredNodes: [
"Program > ExpressionStatement > CallExpression > :last-child > *"
]
}
]
}
},
{
files: [ "src/exports/amd.js" ],
languageOptions: {
globals: {
define: false
}
}
},
// Tests
{
files: [
"test/**"
],
ignores: [
"test/data/jquery-1.9.1.js",
"test/data/badcall.js",
"test/data/badjson.js",
"test/data/support/csp.js",
"test/data/support/getComputedSupport.js",
"test/data/core/jquery-iterability-transpiled.js"
],
languageOptions: {
globals: {
...globals.browser,
require: false,
Promise: false,
Symbol: false,
trustedTypes: false,
QUnit: false,
ajaxTest: false,
testIframe: false,
createDashboardXML: false,
createWithFriesXML: false,
createXMLFragment: false,
includesModule: false,
moduleTeardown: false,
url: false,
q: false,
jQuery: true,
sinon: true,
amdDefined: true,
fireNative: true,
Globals: true,
hasPHP: true,
isLocal: true,
supportjQuery: true,
originaljQuery: true,
$: true,
original$: true,
baseURL: true,
externalHost: true
}
},
rules: {
...jqueryConfig.rules,
strict: [ "error", "function" ],
// See https://github.com/eslint/eslint/issues/2342
"no-unused-vars": "off",
// Too many errors
"max-len": "off",
camelcase: "off",
"one-var": "off"
}
},
{
files: [
"test/data/testrunner.js",
"test/data/core/jquery-iterability-transpiled-es6.js"
],
languageOptions: {
sourceType: "script"
}
},
{
files: [
"test/unit/deferred.js"
],
rules: {
// Deferred tests set strict mode for certain tests
strict: "off"
}
},
{
files: [
"test/node_smoke_tests/**",
"test/promises_aplus_adapters/**",
"test/middleware-mockserver.js"
],
languageOptions: {
globals: {
...globals.node,
...globals.es2021
}
},
rules: {
strict: [ "error", "global" ]
}
},
{
files: [
"build/**",
"test/data/testinit.js",
"test/data/testinit-jsdom.js"
],
languageOptions: {
globals: {
...globals.node,
...globals.es2021
}
},
rules: {
...jqueryConfig.rules,
strict: [ "error", "global" ]
}
},
{
files: [
"build/**/*.js",
"test/data/testinit.js",
"test/data/testinit-jsdom.js"
],
languageOptions: {
sourceType: "commonjs"
}
},
{
files: [
"dist/jquery.js",
"dist/jquery.slim.js"
],
languageOptions: {
globals: {
...globals.browser,
...globals.es2021,
define: false,
module: false,
Symbol: false
}
},
rules: {
...jqueryConfig.rules,
// That is okay for the built version
"no-multiple-empty-lines": "off",
// When custom compilation is used, the version string
// can get large. Accept that in the built version.
"max-len": "off",
"one-var": "off"
}
}
];

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,19 +0,0 @@
Copyright (c) 2014-2019 Denis Pushkarev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because one or more lines are too long

373
external/npo/npo.js vendored
View File

@ -1,373 +0,0 @@
/*! Native Promise Only
v0.8.1 (c) Kyle Simpson
MIT License: http://getify.mit-license.org
*/
(function UMD(name,context,definition){
// special form of UMD for polyfilling across evironments
context[name] = context[name] || definition();
if (typeof module != "undefined" && module.exports) { module.exports = context[name]; }
else if (typeof define == "function" && define.amd) { define(function $AMD$(){ return context[name]; }); }
})("Promise",typeof global != "undefined" ? global : this,function DEF(){
/*jshint validthis:true */
"use strict";
var builtInProp, cycle, scheduling_queue,
ToString = Object.prototype.toString,
timer = (typeof setImmediate != "undefined") ?
function timer(fn) { return setImmediate(fn); } :
setTimeout
;
// dammit, IE8.
try {
Object.defineProperty({},"x",{});
builtInProp = function builtInProp(obj,name,val,config) {
return Object.defineProperty(obj,name,{
value: val,
writable: true,
configurable: config !== false
});
};
}
catch (err) {
builtInProp = function builtInProp(obj,name,val) {
obj[name] = val;
return obj;
};
}
// Note: using a queue instead of array for efficiency
scheduling_queue = (function Queue() {
var first, last, item;
function Item(fn,self) {
this.fn = fn;
this.self = self;
this.next = void 0;
}
return {
add: function add(fn,self) {
item = new Item(fn,self);
if (last) {
last.next = item;
}
else {
first = item;
}
last = item;
item = void 0;
},
drain: function drain() {
var f = first;
first = last = cycle = void 0;
while (f) {
f.fn.call(f.self);
f = f.next;
}
}
};
})();
function schedule(fn,self) {
scheduling_queue.add(fn,self);
if (!cycle) {
cycle = timer(scheduling_queue.drain);
}
}
// promise duck typing
function isThenable(o) {
var _then, o_type = typeof o;
if (o != null &&
(
o_type == "object" || o_type == "function"
)
) {
_then = o.then;
}
return typeof _then == "function" ? _then : false;
}
function notify() {
for (var i=0; i<this.chain.length; i++) {
notifyIsolated(
this,
(this.state === 1) ? this.chain[i].success : this.chain[i].failure,
this.chain[i]
);
}
this.chain.length = 0;
}
// NOTE: This is a separate function to isolate
// the `try..catch` so that other code can be
// optimized better
function notifyIsolated(self,cb,chain) {
var ret, _then;
try {
if (cb === false) {
chain.reject(self.msg);
}
else {
if (cb === true) {
ret = self.msg;
}
else {
ret = cb.call(void 0,self.msg);
}
if (ret === chain.promise) {
chain.reject(TypeError("Promise-chain cycle"));
}
else if (_then = isThenable(ret)) {
_then.call(ret,chain.resolve,chain.reject);
}
else {
chain.resolve(ret);
}
}
}
catch (err) {
chain.reject(err);
}
}
function resolve(msg) {
var _then, self = this;
// already triggered?
if (self.triggered) { return; }
self.triggered = true;
// unwrap
if (self.def) {
self = self.def;
}
try {
if (_then = isThenable(msg)) {
schedule(function(){
var def_wrapper = new MakeDefWrapper(self);
try {
_then.call(msg,
function $resolve$(){ resolve.apply(def_wrapper,arguments); },
function $reject$(){ reject.apply(def_wrapper,arguments); }
);
}
catch (err) {
reject.call(def_wrapper,err);
}
})
}
else {
self.msg = msg;
self.state = 1;
if (self.chain.length > 0) {
schedule(notify,self);
}
}
}
catch (err) {
reject.call(new MakeDefWrapper(self),err);
}
}
function reject(msg) {
var self = this;
// already triggered?
if (self.triggered) { return; }
self.triggered = true;
// unwrap
if (self.def) {
self = self.def;
}
self.msg = msg;
self.state = 2;
if (self.chain.length > 0) {
schedule(notify,self);
}
}
function iteratePromises(Constructor,arr,resolver,rejecter) {
for (var idx=0; idx<arr.length; idx++) {
(function IIFE(idx){
Constructor.resolve(arr[idx])
.then(
function $resolver$(msg){
resolver(idx,msg);
},
rejecter
);
})(idx);
}
}
function MakeDefWrapper(self) {
this.def = self;
this.triggered = false;
}
function MakeDef(self) {
this.promise = self;
this.state = 0;
this.triggered = false;
this.chain = [];
this.msg = void 0;
}
function Promise(executor) {
if (typeof executor != "function") {
throw TypeError("Not a function");
}
if (this.__NPO__ !== 0) {
throw TypeError("Not a promise");
}
// instance shadowing the inherited "brand"
// to signal an already "initialized" promise
this.__NPO__ = 1;
var def = new MakeDef(this);
this["then"] = function then(success,failure) {
var o = {
success: typeof success == "function" ? success : true,
failure: typeof failure == "function" ? failure : false
};
// Note: `then(..)` itself can be borrowed to be used against
// a different promise constructor for making the chained promise,
// by substituting a different `this` binding.
o.promise = new this.constructor(function extractChain(resolve,reject) {
if (typeof resolve != "function" || typeof reject != "function") {
throw TypeError("Not a function");
}
o.resolve = resolve;
o.reject = reject;
});
def.chain.push(o);
if (def.state !== 0) {
schedule(notify,def);
}
return o.promise;
};
this["catch"] = function $catch$(failure) {
return this.then(void 0,failure);
};
try {
executor.call(
void 0,
function publicResolve(msg){
resolve.call(def,msg);
},
function publicReject(msg) {
reject.call(def,msg);
}
);
}
catch (err) {
reject.call(def,err);
}
}
var PromisePrototype = builtInProp({},"constructor",Promise,
/*configurable=*/false
);
// Note: Android 4 cannot use `Object.defineProperty(..)` here
Promise.prototype = PromisePrototype;
// built-in "brand" to signal an "uninitialized" promise
builtInProp(PromisePrototype,"__NPO__",0,
/*configurable=*/false
);
builtInProp(Promise,"resolve",function Promise$resolve(msg) {
var Constructor = this;
// spec mandated checks
// note: best "isPromise" check that's practical for now
if (msg && typeof msg == "object" && msg.__NPO__ === 1) {
return msg;
}
return new Constructor(function executor(resolve,reject){
if (typeof resolve != "function" || typeof reject != "function") {
throw TypeError("Not a function");
}
resolve(msg);
});
});
builtInProp(Promise,"reject",function Promise$reject(msg) {
return new this(function executor(resolve,reject){
if (typeof resolve != "function" || typeof reject != "function") {
throw TypeError("Not a function");
}
reject(msg);
});
});
builtInProp(Promise,"all",function Promise$all(arr) {
var Constructor = this;
// spec mandated checks
if (ToString.call(arr) != "[object Array]") {
return Constructor.reject(TypeError("Not an array"));
}
if (arr.length === 0) {
return Constructor.resolve([]);
}
return new Constructor(function executor(resolve,reject){
if (typeof resolve != "function" || typeof reject != "function") {
throw TypeError("Not a function");
}
var len = arr.length, msgs = Array(len), count = 0;
iteratePromises(Constructor,arr,function resolver(idx,msg) {
msgs[idx] = msg;
if (++count === len) {
resolve(msgs);
}
},reject);
});
});
builtInProp(Promise,"race",function Promise$race(arr) {
var Constructor = this;
// spec mandated checks
if (ToString.call(arr) != "[object Array]") {
return Constructor.reject(TypeError("Not an array"));
}
return new Constructor(function executor(resolve,reject){
if (typeof resolve != "function" || typeof reject != "function") {
throw TypeError("Not a function");
}
iteratePromises(Constructor,arr,function resolver(idx,msg){
resolve(msg);
},reject);
});
});
return Promise;
});

View File

@ -1,35 +0,0 @@
Copyright JS Foundation and other contributors, https://js.foundation
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/qunitjs/qunit
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
All files located in the node_modules directory are externally maintained
libraries used by this software which have their own licenses; we
recommend you read them, as their terms may differ from the terms above.

View File

@ -1,436 +0,0 @@
/*!
* QUnit 2.9.2
* https://qunitjs.com/
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
* Date: 2019-02-21T22:49Z
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
margin: 0;
padding: 0;
}
/** Header (excluding toolbar) */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699A4;
background-color: #0D3349;
font-size: 1.5em;
line-height: 1em;
font-weight: 400;
border-radius: 5px 5px 0 0;
}
#qunit-header a {
text-decoration: none;
color: #C2CCD1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #FFF;
}
#qunit-banner {
height: 5px;
}
#qunit-filteredTest {
padding: 0.5em 1em 0.5em 1em;
color: #366097;
background-color: #F4FF77;
}
#qunit-userAgent {
padding: 0.5em 1em 0.5em 1em;
color: #FFF;
background-color: #2B81AF;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
/** Toolbar */
#qunit-testrunner-toolbar {
padding: 0.5em 1em 0.5em 1em;
color: #5E740B;
background-color: #EEE;
}
#qunit-testrunner-toolbar .clearfix {
height: 0;
clear: both;
}
#qunit-testrunner-toolbar label {
display: inline-block;
}
#qunit-testrunner-toolbar input[type=checkbox],
#qunit-testrunner-toolbar input[type=radio] {
margin: 3px;
vertical-align: -2px;
}
#qunit-testrunner-toolbar input[type=text] {
box-sizing: border-box;
height: 1.6em;
}
.qunit-url-config,
.qunit-filter,
#qunit-modulefilter {
display: inline-block;
line-height: 2.1em;
}
.qunit-filter,
#qunit-modulefilter {
float: right;
position: relative;
margin-left: 1em;
}
.qunit-url-config label {
margin-right: 0.5em;
}
#qunit-modulefilter-search {
box-sizing: border-box;
width: 400px;
}
#qunit-modulefilter-search-container:after {
position: absolute;
right: 0.3em;
content: "\25bc";
color: black;
}
#qunit-modulefilter-dropdown {
/* align with #qunit-modulefilter-search */
box-sizing: border-box;
width: 400px;
position: absolute;
right: 0;
top: 50%;
margin-top: 0.8em;
border: 1px solid #D3D3D3;
border-top: none;
border-radius: 0 0 .25em .25em;
color: #000;
background-color: #F5F5F5;
z-index: 99;
}
#qunit-modulefilter-dropdown a {
color: inherit;
text-decoration: none;
}
#qunit-modulefilter-dropdown .clickable.checked {
font-weight: bold;
color: #000;
background-color: #D2E0E6;
}
#qunit-modulefilter-dropdown .clickable:hover {
color: #FFF;
background-color: #0D3349;
}
#qunit-modulefilter-actions {
display: block;
overflow: auto;
/* align with #qunit-modulefilter-dropdown-list */
font: smaller/1.5em sans-serif;
}
#qunit-modulefilter-dropdown #qunit-modulefilter-actions > * {
box-sizing: border-box;
max-height: 2.8em;
display: block;
padding: 0.4em;
}
#qunit-modulefilter-dropdown #qunit-modulefilter-actions > button {
float: right;
font: inherit;
}
#qunit-modulefilter-dropdown #qunit-modulefilter-actions > :last-child {
/* insert padding to align with checkbox margins */
padding-left: 3px;
}
#qunit-modulefilter-dropdown-list {
max-height: 200px;
overflow-y: auto;
margin: 0;
border-top: 2px groove threedhighlight;
padding: 0.4em 0 0;
font: smaller/1.5em sans-serif;
}
#qunit-modulefilter-dropdown-list li {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#qunit-modulefilter-dropdown-list .clickable {
display: block;
padding-left: 0.15em;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 1em 0.4em 1em;
border-bottom: 1px solid #FFF;
list-style-position: inside;
}
#qunit-tests > li {
display: none;
}
#qunit-tests li.running,
#qunit-tests li.pass,
#qunit-tests li.fail,
#qunit-tests li.skipped,
#qunit-tests li.aborted {
display: list-item;
}
#qunit-tests.hidepass {
position: relative;
}
#qunit-tests.hidepass li.running,
#qunit-tests.hidepass li.pass:not(.todo) {
visibility: hidden;
position: absolute;
width: 0;
height: 0;
padding: 0;
border: 0;
margin: 0;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li.skipped strong {
cursor: default;
}
#qunit-tests li a {
padding: 0.5em;
color: #C2CCD1;
text-decoration: none;
}
#qunit-tests li p a {
padding: 0.25em;
color: #6B6464;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests li .runtime {
float: right;
font-size: smaller;
}
.qunit-assert-list {
margin-top: 0.5em;
padding: 0.5em;
background-color: #FFF;
border-radius: 5px;
}
.qunit-source {
margin: 0.6em 0 0.3em;
}
.qunit-collapsed {
display: none;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: 0.2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 0.5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
color: #374E0C;
background-color: #E0F2BE;
text-decoration: none;
}
#qunit-tests ins {
color: #500;
background-color: #FFCACA;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: #000; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
padding: 5px;
background-color: #FFF;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #3C510C;
background-color: #FFF;
border-left: 10px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #FFF;
border-left: 10px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 5px 5px;
}
#qunit-tests .fail { color: #000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: #008000; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/*** Aborted tests */
#qunit-tests .aborted { color: #000; background-color: orange; }
/*** Skipped tests */
#qunit-tests .skipped {
background-color: #EBECE9;
}
#qunit-tests .qunit-todo-label,
#qunit-tests .qunit-skipped-label {
background-color: #F4FF77;
display: inline-block;
font-style: normal;
color: #366097;
line-height: 1.8em;
padding: 0 0.5em;
margin: -0.4em 0.4em -0.4em 0;
}
#qunit-tests .qunit-todo-label {
background-color: #EEE;
}
/** Result */
#qunit-testresult {
color: #2B81AF;
background-color: #D2E0E6;
border-bottom: 1px solid #FFF;
}
#qunit-testresult .clearfix {
height: 0;
clear: both;
}
#qunit-testresult .module-name {
font-weight: 700;
}
#qunit-testresult-display {
padding: 0.5em 1em 0.5em 1em;
width: 85%;
float:left;
}
#qunit-testresult-controls {
padding: 0.5em 1em 0.5em 1em;
width: 10%;
float:left;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
width: 1000px;
height: 1000px;
}

6604
external/qunit/qunit.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
(The BSD License)
Copyright (c) 2010-2017, Christian Johansen, christian@cjohansen.no
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Christian Johansen nor the names of his contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

11809
external/sinon/sinon.js vendored

File diff suppressed because one or more lines are too long

7533
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,31 @@
"description": "JavaScript library for DOM operations", "description": "JavaScript library for DOM operations",
"version": "3.7.2-pre", "version": "3.7.2-pre",
"main": "dist/jquery.js", "main": "dist/jquery.js",
"scripts": {
"babel:tests": "babel test/data/core/jquery-iterability-transpiled-es6.js --out-file test/data/core/jquery-iterability-transpiled.js",
"build": "node ./build/command.js",
"build:all": "node -e \"require('./build/tasks/build.js').buildDefaultFiles()\"",
"build:main": "node -e \"require('./build/tasks/build.js').build()\"",
"jenkins": "npm run pretest && npm run test:browserless",
"lint:dev": "eslint --cache .",
"lint:json": "jsonlint --quiet package.json",
"lint": "concurrently -r \"npm:lint:dev\" \"npm:lint:json\"",
"npmcopy": "node build/tasks/npmcopy.js",
"prepare": "husky install",
"pretest": "npm run qunit-fixture && npm run babel:tests && npm run npmcopy",
"qunit-fixture": "node build/tasks/qunit-fixture.js",
"start": "nodemon --watch src -x \"npm run build:all\"",
"test:browserless": "npm run test:node_smoke_tests && npm run test:promises_aplus && npm run test:jsdom",
"test:browser": "npm run build:all && grunt karma:main",
"test:amd": "npm run build:main && grunt karma:amd",
"test:jsdom": "npm run build:main && grunt test:jsdom",
"test:no-deprecated": "npm run build -- -e deprecated && grunt karma:main",
"test:selector-native": "npm run build -- -e selector && grunt karma:main",
"test:slim": "npm run build -- --slim && grunt karma:main",
"test:node_smoke_tests": "npm run build:all && node build/tasks/node_smoke_tests.js",
"test:promises_aplus": "npm run build:main && node build/tasks/promises_aplus_tests.js",
"test": "npm run build:all && npm run lint && npm run test:browserless && npm run test:browser && npm run test:amd && npm run test:slim && npm run test:no-deprecated && npm run test:selector-native"
},
"homepage": "https://jquery.com", "homepage": "https://jquery.com",
"author": { "author": {
"name": "OpenJS Foundation and other contributors", "name": "OpenJS Foundation and other contributors",
@ -24,27 +49,25 @@
}, },
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@babel/core": "7.3.3", "@babel/cli": "7.22.10",
"@babel/plugin-transform-for-of": "7.2.0", "@babel/core": "7.22.11",
"@babel/plugin-transform-for-of": "7.22.5",
"@prantlf/jsonlint": "14.0.3",
"bootstrap": "5.3.0", "bootstrap": "5.3.0",
"chalk": "5.3.0",
"colors": "1.4.0", "colors": "1.4.0",
"commitplease": "3.2.0", "commitplease": "3.2.0",
"core-js": "2.6.5", "concurrently": "8.2.0",
"eslint-config-jquery": "3.0.0", "core-js-bundle": "3.32.1",
"eslint": "8.48.0",
"eslint-config-jquery": "3.0.1",
"express": "4.18.2",
"globals": "13.20.0",
"grunt": "1.5.3", "grunt": "1.5.3",
"grunt-babel": "8.0.0",
"grunt-cli": "1.4.3", "grunt-cli": "1.4.3",
"grunt-compare-size": "0.4.2",
"grunt-contrib-uglify": "3.4.0",
"grunt-contrib-watch": "1.1.0",
"grunt-eslint": "22.0.0",
"grunt-git-authors": "3.2.0", "grunt-git-authors": "3.2.0",
"grunt-jsonlint": "2.1.2",
"grunt-karma": "4.0.2", "grunt-karma": "4.0.2",
"grunt-newer": "1.3.0", "husky": "8.0.3",
"grunt-npmcopy": "0.2.0",
"gzip-js": "0.3.2",
"husky": "4.2.5",
"jsdom": "19.0.0", "jsdom": "19.0.0",
"karma": "6.4.1", "karma": "6.4.1",
"karma-browserstack-launcher": "1.6.0", "karma-browserstack-launcher": "1.6.0",
@ -56,6 +79,7 @@
"karma-webkit-launcher": "2.1.0", "karma-webkit-launcher": "2.1.0",
"load-grunt-tasks": "5.1.0", "load-grunt-tasks": "5.1.0",
"native-promise-only": "0.8.1", "native-promise-only": "0.8.1",
"nodemon": "3.0.1",
"playwright-webkit": "1.30.0", "playwright-webkit": "1.30.0",
"promises-aplus-tests": "2.1.2", "promises-aplus-tests": "2.1.2",
"q": "1.5.1", "q": "1.5.1",
@ -65,23 +89,8 @@
"sinon": "2.3.7", "sinon": "2.3.7",
"strip-json-comments": "2.0.1", "strip-json-comments": "2.0.1",
"testswarm": "1.1.2", "testswarm": "1.1.2",
"uglify-js": "3.4.7" "uglify-js": "3.4.7",
}, "yargs": "17.7.2"
"scripts": {
"build": "npm install && npm run build-all-variants",
"build-all-variants": "grunt custom:slim --filename=jquery.slim.js && grunt custom",
"start": "grunt watch",
"test:browserless": "grunt && npm run test:node_smoke_tests && grunt test:slow",
"test:browser": "grunt && grunt karma:main",
"test:amd": "grunt && grunt karma:amd",
"test:no-deprecated": "grunt test:prepare && grunt custom:-deprecated && grunt karma:main",
"test:selector-native": "grunt test:prepare && grunt custom:-selector && grunt karma:main",
"test:slim": "grunt test:prepare && grunt custom:slim && grunt karma:main",
"test:node_smoke_tests:full": "grunt node_smoke_tests:./dist/jquery.js",
"test:node_smoke_tests:slim": "grunt node_smoke_tests:./dist/jquery.slim.js",
"test:node_smoke_tests": "npm run test:node_smoke_tests:full && npm run test:node_smoke_tests:slim",
"test": "npm run test:browserless && npm run test:slim && npm run test:no-deprecated && npm run test:selector-native && grunt && grunt test:slow && grunt karma:main && grunt karma:amd",
"jenkins": "npm run test:browserless"
}, },
"commitplease": { "commitplease": {
"nohook": true, "nohook": true,
@ -112,11 +121,5 @@
], ],
"markerPattern": "^((clos|fix|resolv)(e[sd]|ing))|^(refs?)", "markerPattern": "^((clos|fix|resolv)(e[sd]|ing))|^(refs?)",
"ticketPattern": "^((Closes|Fixes) ([a-zA-Z]{2,}-)[0-9]+)|^(Refs? [^#])" "ticketPattern": "^((Closes|Fixes) ([a-zA-Z]{2,}-)[0-9]+)|^(Refs? [^#])"
},
"husky": {
"hooks": {
"commit-msg": "commitplease .git/COMMIT_EDITMSG",
"pre-commit": "grunt lint:newer qunit_fixture"
}
} }
} }

View File

@ -1,45 +0,0 @@
{
"root": true,
"extends": "../.eslintrc-browser.json",
"rules": {
"indent": [ "error", "tab", {
"outerIIFEBody": 0,
// Ignore the top level function defining an AMD module
"ignoredNodes": [
"Program > ExpressionStatement > CallExpression > :last-child > *"
]
} ]
},
"overrides": [
{
"files": "wrapper.js",
"rules": {
"no-unused-vars": "off",
"indent": [ "error", "tab", {
// Unlike other codes, "wrapper.js" is implemented in UMD.
// So it required a specific exception for jQuery's UMD
// Code Style. This makes that indentation check is not
// performed for 1 depth of outer FunctionExpressions
"ignoredNodes": [
"Program > ExpressionStatement > CallExpression > :last-child > *"
]
} ]
},
"globals": {
"jQuery": false
}
},
{
"files": "selector.js",
"rules": {
"indent": "off"
}
}
]
}

View File

@ -1,78 +0,0 @@
{
"root": true,
"extends": "../.eslintrc-browser.json",
"env": {
// In source the browser env is not enabled but unit tests rely on them
// too much and we don't run them in non-browser environments anyway.
"browser": true
},
"globals": {
"require": false,
"Promise": false,
"Symbol": false,
"QUnit": false,
"ajaxTest": false,
"testIframe": false,
"createDashboardXML": false,
"createWithFriesXML": false,
"createXMLFragment": false,
"includesModule": false,
"moduleTeardown": false,
"url": false,
"q": false,
"jQuery": true,
"sinon": true,
"amdDefined": true,
"fireNative": true,
"Globals": true,
"hasPHP": true,
"isLocal": true,
"supportjQuery": true,
"originaljQuery": true,
"$": true,
"original$": true,
"baseURL": true,
"externalHost": true
},
"rules": {
// See https://github.com/eslint/eslint/issues/2342
"no-unused-vars": "off",
// Too many errors
"max-len": "off",
"brace-style": "off",
"key-spacing": "off",
"camelcase": "off",
"one-var": "off",
"strict": "off",
// Not really too many - waiting for autofix features for these rules
"lines-around-comment": "off",
"dot-notation": "off"
},
"overrides": [
{
"files": [
"middleware-mockserver.js"
],
"extends": "../.eslintrc-node.json"
},
{
"files": [
"data/core/jquery-iterability-transpiled-es6.js",
"data/testinit-jsdom.js"
],
"parserOptions": {
"ecmaVersion": 2015
}
}
]
}

View File

@ -0,0 +1,5 @@
{
"plugins": ["@babel/transform-for-of"],
"retainLines": true,
"sourceMaps": "inline"
}

View File

@ -3,7 +3,7 @@
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>jQuery objects transpiled iterability test page</title> <title>jQuery objects transpiled iterability test page</title>
<script src="../../../external/core-js/core-js.js"></script> <script src="../../../external/core-js-bundle/core-js-bundle.js"></script>
<script src="../../jquery.js"></script> <script src="../../jquery.js"></script>
<script src="../iframeTest.js"></script> <script src="../iframeTest.js"></script>
<script src="jquery-iterability-transpiled.js"></script> <script src="jquery-iterability-transpiled.js"></script>

View File

@ -2,19 +2,19 @@
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../external/bootstrap/bootstrap.min.css" class="stylesheet"> <link rel="stylesheet" href="../../../external/bootstrap/bootstrap.min.css" class="stylesheet" />
</head> </head>
<body> <body>
<div> <div>
<script src="../../jquery.js"></script> <script src="../../jquery.js"></script>
<script src="../iframeTest.js"></script> <script src="../iframeTest.js"></script>
<script src="getComputedSupport.js"></script> <script src="getComputedSupport.js"></script>
</div> </div>
<script> <script>
startIframeTest( startIframeTest(
getComputedStyle( document.body ), getComputedStyle( document.body ),
getComputedSupport( jQuery.support ) getComputedSupport( jQuery.support )
); );
</script> </script>
</body> </body>
</html> </html>

View File

@ -34,10 +34,10 @@ window.original$ = this.$ = "replaced";
* @example url("mock.php?foo=bar") * @example url("mock.php?foo=bar")
* @result "data/mock.php?foo=bar&10538358345554" * @result "data/mock.php?foo=bar&10538358345554"
*/ */
function url( value ) { this.url = function( value ) {
return baseURL + value + ( /\?/.test( value ) ? "&" : "?" ) + return baseURL + value + ( /\?/.test( value ) ? "&" : "?" ) +
new Date().getTime() + "" + parseInt( Math.random() * 100000, 10 ); new Date().getTime() + "" + parseInt( Math.random() * 100000, 10 );
} };
// We only run basic tests in jsdom so we don't need to repeat the logic // We only run basic tests in jsdom so we don't need to repeat the logic
// from the regular testinit.js // from the regular testinit.js

View File

@ -17,13 +17,7 @@ var FILEPATH = "/test/data/testinit.js",
supportjQuery = this.jQuery, supportjQuery = this.jQuery,
// see RFC 2606 // see RFC 2606
externalHost = "example.com", externalHost = "example.com";
// NOTE: keep it in sync with build/tasks/lib/slim-build-flags.js
slimBuildFlags = [
"-ajax",
"-effects"
];
this.hasPHP = true; this.hasPHP = true;
this.isLocal = window.location.protocol === "file:"; this.isLocal = window.location.protocol === "file:";
@ -265,7 +259,7 @@ this.ajaxTest = function( title, expect, options ) {
completed = true; completed = true;
delete ajaxTest.abort; delete ajaxTest.abort;
assert.ok( false, "aborted " + reason ); assert.ok( false, "aborted " + reason );
jQuery.each( requests, function( i, request ) { jQuery.each( requests, function( _i, request ) {
request.abort(); request.abort();
} ); } );
} }
@ -346,16 +340,8 @@ this.includesModule = function( moduleName ) {
var excludedModulesPart, excludedModules; var excludedModulesPart, excludedModules;
// A short-cut for the slim build, e.g. "4.0.0-pre slim" // example version for `npm run build -- -e deprecated`:
if ( jQuery.fn.jquery.indexOf( " slim" ) > -1 ) { // "v3.7.2-pre+14dc9347 -deprecated,-deprecated/ajax-event-alias,-deprecated/event"
// The module is included if it does NOT exist on the list
// of modules excluded in the slim build
return slimBuildFlags.indexOf( "-" + moduleName ) === -1;
}
// example version for `grunt custom:-deprecated`:
// "4.0.0-pre -deprecated,-deprecated/ajax-event-alias,-deprecated/event"
excludedModulesPart = jQuery.fn.jquery excludedModulesPart = jQuery.fn.jquery
// Take the flags out of the version string. // Take the flags out of the version string.
@ -420,6 +406,7 @@ this.loadTests = function() {
var i = 0, var i = 0,
tests = [ tests = [
// A special module with basic tests, meant for // A special module with basic tests, meant for
// not fully supported environments like Android 2.3, // not fully supported environments like Android 2.3,
// jsdom or PhantomJS. We run it everywhere, though, // jsdom or PhantomJS. We run it everywhere, though,

View File

@ -66,14 +66,34 @@ const mocks = {
resp.end( "<root><element /></root>" ); resp.end( "<root><element /></root>" );
}, },
script: function( req, resp ) { script: function( req, resp ) {
const headers = {};
if ( req.query.header === "ecma" ) { if ( req.query.header === "ecma" ) {
resp.writeHead( 200, { "content-type": "application/ecmascript" } ); headers[ "content-type" ] = "application/ecmascript";
} else if ( "header" in req.query ) { } else if ( "header" in req.query ) {
resp.writeHead( 200, { "content-type": "text/javascript" } ); headers[ "content-type" ] = "text/javascript";
} else { } else {
resp.writeHead( 200, { "content-type": "text/html" } ); headers[ "content-type" ] = "text/html";
}
if ( req.query.cors ) {
headers[ "access-control-allow-origin" ] = "*";
}
if ( resp.set ) {
resp.set( headers );
} else {
for ( const key in headers ) {
resp.writeHead( 200, { [ key ]: headers[ key ] } );
}
}
if ( req.query.callback ) {
resp.end( `${ cleanCallback( req.query.callback ) }(${ JSON.stringify( {
headers: req.headers
} ) })` );
} else {
resp.end( "QUnit.assert.ok( true, \"mock executed\" );" );
} }
resp.end( "QUnit.assert.ok( true, \"mock executed\" );" );
}, },
testbar: function( _req, resp ) { testbar: function( _req, resp ) {
resp.writeHead( 200 ); resp.writeHead( 200 );
@ -137,14 +157,25 @@ const mocks = {
} }
}, },
headers: function( req, resp ) { headers: function( req, resp ) {
resp.writeHead( 200, { const headers = {
"Sample-Header": "Hello World", "Sample-Header": "Hello World",
"Empty-Header": "", "Empty-Header": "",
"Sample-Header2": "Hello World 2", "Sample-Header2": "Hello World 2",
"List-Header": "Item 1", "List-Header": "Item 1",
"list-header": "Item 2", "list-header": "Item 2",
"constructor": "prototype collision (constructor)" "constructor": "prototype collision (constructor)"
} ); };
// Use resp.append in express to
// avoid overwriting List-Header
if ( resp.append ) {
for ( const key in headers ) {
resp.append( key, headers[ key ] );
}
} else {
resp.writeHead( 200, headers );
}
req.query.keys.split( "|" ).forEach( function( key ) { req.query.keys.split( "|" ).forEach( function( key ) {
if ( key.toLowerCase() in req.headers ) { if ( key.toLowerCase() in req.headers ) {
resp.write( `${ key }: ${ req.headers[ key.toLowerCase() ] }\n` ); resp.write( `${ key }: ${ req.headers[ key.toLowerCase() ] }\n` );
@ -297,7 +328,7 @@ function MockserverMiddlewareFactory() {
parsed: parsed parsed: parsed
} ); } );
if ( /^test\/data\/mock.php\//.test( path ) ) { if ( /^\/?test\/data\/mock.php\/?/.test( path ) ) {
// Support REST-like Apache PathInfo // Support REST-like Apache PathInfo
path = "test\/data\/mock.php"; path = "test\/data\/mock.php";
@ -308,6 +339,7 @@ function MockserverMiddlewareFactory() {
return; return;
} }
// console.log( "Mock handling", req.method, parsed.href );
handlers[ path ]( subReq, resp, next ); handlers[ path ]( subReq, resp, next );
}; };
} }

View File

@ -1,13 +0,0 @@
{
"root": true,
"extends": "../../.eslintrc-node.json",
"parserOptions": {
"ecmaVersion": 2015,
"sourceType": "script"
},
"env": {
"es2020": true
}
}

View File

@ -1,5 +0,0 @@
{
"root": true,
"extends": "../../.eslintrc-node.json"
}

21
test/server.js Normal file
View File

@ -0,0 +1,21 @@
const express = require( "express" );
const mockServer = require( "./middleware-mockserver" );
const fs = require( "fs" );
const nameHTML = fs.readFileSync( "./test/data/name.html", "utf8" );
const app = express();
app.use( mockServer() );
app.post( "/test/data/name.html", function( _req, res ) {
res.send( nameHTML );
} );
app.use( "/dist", express.static( "dist" ) );
app.use( "/src", express.static( "src" ) );
app.use( "/test", express.static( "test" ) );
app.use( "/external", express.static( "external" ) );
app.listen( 3000, function() {
console.log( "Server is running on port 3000" );
} );

View File

@ -298,6 +298,7 @@ QUnit.module( "ajax", {
assert.strictEqual( xhr.getResponseHeader( "Sample-Header2" ), "Hello World 2", "Second sample header received" ); assert.strictEqual( xhr.getResponseHeader( "Sample-Header2" ), "Hello World 2", "Second sample header received" );
if ( isAndroid ) { if ( isAndroid ) {
// Support: Android 4.0-4.3 only // Support: Android 4.0-4.3 only
// Android Browser only returns the last value for each header // Android Browser only returns the last value for each header
// so there's no way for jQuery get all parts. // so there's no way for jQuery get all parts.
@ -307,6 +308,7 @@ QUnit.module( "ajax", {
} }
if ( isAndroid && QUnit.isSwarm ) { if ( isAndroid && QUnit.isSwarm ) {
// Support: Android 4.0-4.3 on BrowserStack only // Support: Android 4.0-4.3 on BrowserStack only
// Android Browser versions provided by BrowserStack fail this test // Android Browser versions provided by BrowserStack fail this test
// while locally fired emulators don't, even when they connect // while locally fired emulators don't, even when they connect
@ -426,6 +428,7 @@ QUnit.module( "ajax", {
}, },
cache: false, cache: false,
beforeSend: function( xhr, settings ) { beforeSend: function( xhr, settings ) {
// Clear the cache-buster param value // Clear the cache-buster param value
var url = settings.url.replace( /_=[^&#]+/, "_=" ); var url = settings.url.replace( /_=[^&#]+/, "_=" );
assert.equal( url, baseURL + "name.html?abc&devo=hat&_=#brownies", assert.equal( url, baseURL + "name.html?abc&devo=hat&_=#brownies",
@ -661,7 +664,7 @@ QUnit.module( "ajax", {
url: url( "404.txt" ), url: url( "404.txt" ),
beforeSend: nocallback( "beforeSend" ), beforeSend: nocallback( "beforeSend" ),
error: nocallback( "error" ), error: nocallback( "error" ),
complete: nocallback( "complete" ) complete: nocallback( "complete" )
}; };
} ); } );
@ -850,8 +853,8 @@ QUnit.module( "ajax", {
success: function( data ) { success: function( data ) {
assert.ok( data.match( /^html text/ ), "Check content for datatype html" ); assert.ok( data.match( /^html text/ ), "Check content for datatype html" );
jQuery( "#ap" ).html( data ); jQuery( "#ap" ).html( data );
assert.strictEqual( window[ "testFoo" ], "foo", "Check if script was evaluated for datatype html" ); assert.strictEqual( window.testFoo, "foo", "Check if script was evaluated for datatype html" );
assert.strictEqual( window[ "testBar" ], "bar", "Check if script src was evaluated for datatype html" ); assert.strictEqual( window.testBar, "bar", "Check if script src was evaluated for datatype html" );
} }
}; };
} ); } );
@ -861,6 +864,7 @@ QUnit.module( "ajax", {
return { return {
dataType: "jsonp", dataType: "jsonp",
url: url( "mock.php?action=errorWithScript" ), url: url( "mock.php?action=errorWithScript" ),
// error is the significant assertion // error is the significant assertion
error: function( xhr ) { error: function( xhr ) {
var expected = { "status": 404, "msg": "Not Found" }; var expected = { "status": 404, "msg": "Not Found" };
@ -889,6 +893,7 @@ QUnit.module( "ajax", {
complete: function() { complete: function() {
jQuery.globalEval = globalEval; jQuery.globalEval = globalEval;
}, },
// error is the significant assertion // error is the significant assertion
error: function( xhr ) { error: function( xhr ) {
assert.strictEqual( xhr.status, 404, testMsg ); assert.strictEqual( xhr.status, 404, testMsg );
@ -1148,8 +1153,8 @@ QUnit.module( "ajax", {
Globals.register( "functionToCleanUp" ); Globals.register( "functionToCleanUp" );
Globals.register( "XXX" ); Globals.register( "XXX" );
Globals.register( "jsonpResults" ); Globals.register( "jsonpResults" );
window[ "jsonpResults" ] = function( data ) { window.jsonpResults = function( data ) {
assert.ok( data[ "data" ], "JSON results returned (GET, custom callback function)" ); assert.ok( data.data, "JSON results returned (GET, custom callback function)" );
}; };
}, },
requests: [ { requests: [ {
@ -1158,7 +1163,7 @@ QUnit.module( "ajax", {
crossDomain: crossDomain, crossDomain: crossDomain,
jsonp: "callback", jsonp: "callback",
success: function( data ) { success: function( data ) {
assert.ok( data[ "data" ], "JSON results returned (GET, data obj callback)" ); assert.ok( data.data, "JSON results returned (GET, data obj callback)" );
} }
}, { }, {
url: baseURL + "mock.php?action=jsonp", url: baseURL + "mock.php?action=jsonp",
@ -1167,7 +1172,7 @@ QUnit.module( "ajax", {
jsonpCallback: "jsonpResults", jsonpCallback: "jsonpResults",
success: function( data ) { success: function( data ) {
assert.strictEqual( assert.strictEqual(
typeof window[ "jsonpResults" ], typeof window.jsonpResults,
"function", "function",
"should not rewrite original function" "should not rewrite original function"
); );
@ -1179,8 +1184,8 @@ QUnit.module( "ajax", {
crossDomain: crossDomain, crossDomain: crossDomain,
jsonpCallback: "functionToCleanUp", jsonpCallback: "functionToCleanUp",
success: function( data ) { success: function( data ) {
assert.ok( data[ "data" ], "JSON results returned (GET, custom callback name to be cleaned up)" ); assert.ok( data.data, "JSON results returned (GET, custom callback name to be cleaned up)" );
assert.strictEqual( window[ "functionToCleanUp" ], true, "Callback was removed (GET, custom callback name to be cleaned up)" ); assert.strictEqual( window.functionToCleanUp, true, "Callback was removed (GET, custom callback name to be cleaned up)" );
var xhr; var xhr;
jQuery.ajax( { jQuery.ajax( {
url: baseURL + "mock.php?action=jsonp", url: baseURL + "mock.php?action=jsonp",
@ -1194,7 +1199,7 @@ QUnit.module( "ajax", {
} ); } );
xhr.fail( function() { xhr.fail( function() {
assert.ok( true, "Ajax error JSON (GET, custom callback name to be cleaned up)" ); assert.ok( true, "Ajax error JSON (GET, custom callback name to be cleaned up)" );
assert.strictEqual( window[ "functionToCleanUp" ], true, "Callback was removed after early abort (GET, custom callback name to be cleaned up)" ); assert.strictEqual( window.functionToCleanUp, true, "Callback was removed after early abort (GET, custom callback name to be cleaned up)" );
} ); } );
} }
}, { }, {
@ -1207,7 +1212,7 @@ QUnit.module( "ajax", {
assert.ok( /action=jsonp&callback=XXX&_=\d+$/.test( this.url ), "The URL wasn't messed with (GET, custom callback name with no url manipulation)" ); assert.ok( /action=jsonp&callback=XXX&_=\d+$/.test( this.url ), "The URL wasn't messed with (GET, custom callback name with no url manipulation)" );
}, },
success: function( data ) { success: function( data ) {
assert.ok( data[ "data" ], "JSON results returned (GET, custom callback name with no url manipulation)" ); assert.ok( data.data, "JSON results returned (GET, custom callback name with no url manipulation)" );
} }
} ] } ]
}; };
@ -1244,7 +1249,7 @@ QUnit.module( "ajax", {
dataType: "jsonp", dataType: "jsonp",
crossDomain: crossDomain, crossDomain: crossDomain,
success: function( data ) { success: function( data ) {
assert.ok( data[ "data" ], "JSON results returned (POST, no callback)" ); assert.ok( data.data, "JSON results returned (POST, no callback)" );
} }
}, },
{ {
@ -1254,7 +1259,7 @@ QUnit.module( "ajax", {
dataType: "jsonp", dataType: "jsonp",
crossDomain: crossDomain, crossDomain: crossDomain,
success: function( data ) { success: function( data ) {
assert.ok( data[ "data" ], "JSON results returned (POST, data callback)" ); assert.ok( data.data, "JSON results returned (POST, data callback)" );
} }
}, },
{ {
@ -1264,7 +1269,7 @@ QUnit.module( "ajax", {
dataType: "jsonp", dataType: "jsonp",
crossDomain: crossDomain, crossDomain: crossDomain,
success: function( data ) { success: function( data ) {
assert.ok( data[ "data" ], "JSON results returned (POST, data obj callback)" ); assert.ok( data.data, "JSON results returned (POST, data obj callback)" );
} }
} }
]; ];
@ -1312,7 +1317,7 @@ QUnit.module( "ajax", {
url: url( "mock.php?action=testbar" ), url: url( "mock.php?action=testbar" ),
dataType: "script", dataType: "script",
success: function() { success: function() {
assert.strictEqual( window[ "testBar" ], "bar", "Script results returned (GET, no callback)" ); assert.strictEqual( window.testBar, "bar", "Script results returned (GET, no callback)" );
} }
}; };
} ); } );
@ -1326,7 +1331,7 @@ QUnit.module( "ajax", {
type: "POST", type: "POST",
dataType: "script", dataType: "script",
success: function( data, status ) { success: function( data, status ) {
assert.strictEqual( window[ "testBar" ], "bar", "Script results returned (POST, no callback)" ); assert.strictEqual( window.testBar, "bar", "Script results returned (POST, no callback)" );
assert.strictEqual( status, "success", "Script results returned (POST, no callback)" ); assert.strictEqual( status, "success", "Script results returned (POST, no callback)" );
} }
}; };
@ -1340,7 +1345,7 @@ QUnit.module( "ajax", {
url: url( "mock.php?action=testbar" ), url: url( "mock.php?action=testbar" ),
dataType: "script", dataType: "script",
success: function() { success: function() {
assert.strictEqual( window[ "testBar" ], "bar", "Script results returned (GET, no callback)" ); assert.strictEqual( window.testBar, "bar", "Script results returned (GET, no callback)" );
} }
}; };
} ); } );
@ -1385,10 +1390,10 @@ QUnit.module( "ajax", {
}, },
success: function( json ) { success: function( json ) {
assert.ok( json.length >= 2, "Check length" ); assert.ok( json.length >= 2, "Check length" );
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" ); assert.strictEqual( json[ 0 ].name, "John", "Check JSON: first, name" );
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" ); assert.strictEqual( json[ 0 ].age, 21, "Check JSON: first, age" );
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" ); assert.strictEqual( json[ 1 ].name, "Peter", "Check JSON: second, name" );
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" ); assert.strictEqual( json[ 1 ].age, 25, "Check JSON: second, age" );
} }
}, },
{ {
@ -1405,10 +1410,10 @@ QUnit.module( "ajax", {
], ],
success: function( json ) { success: function( json ) {
assert.ok( json.length >= 2, "Check length" ); assert.ok( json.length >= 2, "Check length" );
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" ); assert.strictEqual( json[ 0 ].name, "John", "Check JSON: first, name" );
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" ); assert.strictEqual( json[ 0 ].age, 21, "Check JSON: first, age" );
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" ); assert.strictEqual( json[ 1 ].name, "Peter", "Check JSON: second, name" );
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" ); assert.strictEqual( json[ 1 ].age, 25, "Check JSON: second, age" );
} }
} }
]; ];
@ -1429,10 +1434,10 @@ QUnit.module( "ajax", {
assert.strictEqual( typeof text, "string", "json wasn't auto-determined" ); assert.strictEqual( typeof text, "string", "json wasn't auto-determined" );
var json = JSON.parse( text ); var json = JSON.parse( text );
assert.ok( json.length >= 2, "Check length" ); assert.ok( json.length >= 2, "Check length" );
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" ); assert.strictEqual( json[ 0 ].name, "John", "Check JSON: first, name" );
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" ); assert.strictEqual( json[ 0 ].age, 21, "Check JSON: first, age" );
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" ); assert.strictEqual( json[ 1 ].name, "Peter", "Check JSON: second, name" );
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" ); assert.strictEqual( json[ 1 ].age, 25, "Check JSON: second, age" );
} }
}, },
{ {
@ -1454,10 +1459,10 @@ QUnit.module( "ajax", {
assert.strictEqual( typeof text, "string", "json wasn't auto-determined" ); assert.strictEqual( typeof text, "string", "json wasn't auto-determined" );
var json = JSON.parse( text ); var json = JSON.parse( text );
assert.ok( json.length >= 2, "Check length" ); assert.ok( json.length >= 2, "Check length" );
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" ); assert.strictEqual( json[ 0 ].name, "John", "Check JSON: first, name" );
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" ); assert.strictEqual( json[ 0 ].age, 21, "Check JSON: first, age" );
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" ); assert.strictEqual( json[ 1 ].name, "Peter", "Check JSON: second, name" );
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" ); assert.strictEqual( json[ 1 ].age, 25, "Check JSON: second, age" );
} }
} }
]; ];
@ -1683,6 +1688,7 @@ QUnit.module( "ajax", {
var ifModifiedNow = new Date(); var ifModifiedNow = new Date();
jQuery.each( jQuery.each(
/* jQuery.each arguments start */ /* jQuery.each arguments start */
{ {
" (cache)": true, " (cache)": true,
@ -1737,6 +1743,7 @@ QUnit.module( "ajax", {
} }
); );
} }
/* jQuery.each arguments end */ /* jQuery.each arguments end */
); );
@ -1813,6 +1820,7 @@ QUnit.module( "ajax", {
} }
jQuery.each( jQuery.each(
/* jQuery.each arguments start */ /* jQuery.each arguments start */
{ {
"name.html": true, "name.html": true,
@ -1887,6 +1895,7 @@ QUnit.module( "ajax", {
} ); } );
} }
/* jQuery.each arguments end*/ /* jQuery.each arguments end*/
); );
} ); } );
@ -2670,10 +2679,10 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re
}, },
function( json ) { function( json ) {
assert.ok( json.length >= 2, "Check length" ); assert.ok( json.length >= 2, "Check length" );
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" ); assert.strictEqual( json[ 0 ].name, "John", "Check JSON: first, name" );
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" ); assert.strictEqual( json[ 0 ].age, 21, "Check JSON: first, age" );
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" ); assert.strictEqual( json[ 1 ].name, "Peter", "Check JSON: second, name" );
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" ); assert.strictEqual( json[ 1 ].age, 25, "Check JSON: second, age" );
done(); done();
} }
); );
@ -2683,9 +2692,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re
assert.expect( 2 ); assert.expect( 2 );
var done = assert.async(); var done = assert.async();
jQuery.getJSON( url( "mock.php?action=json" ), function( json ) { jQuery.getJSON( url( "mock.php?action=json" ), function( json ) {
if ( json && json[ "data" ] ) { if ( json && json.data ) {
assert.strictEqual( json[ "data" ][ "lang" ], "en", "Check JSON: lang" ); assert.strictEqual( json.data.lang, "en", "Check JSON: lang" );
assert.strictEqual( json[ "data" ].length, 25, "Check JSON: length" ); assert.strictEqual( json.data.length, 25, "Check JSON: length" );
done(); done();
} }
} ); } );
@ -2725,7 +2734,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re
Globals.register( "testBar" ); Globals.register( "testBar" );
jQuery.getScript( url( "mock.php?action=testbar" ), function() { jQuery.getScript( url( "mock.php?action=testbar" ), function() {
assert.strictEqual( window[ "testBar" ], "bar", "Check if script was evaluated" ); assert.strictEqual( window.testBar, "bar", "Check if script was evaluated" );
done(); done();
} ); } );
} }
@ -2756,7 +2765,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re
jQuery.getScript( { jQuery.getScript( {
url: url( "mock.php?action=testbar" ), url: url( "mock.php?action=testbar" ),
success: function() { success: function() {
assert.strictEqual( window[ "testBar" ], "bar", "Check if script was evaluated" ); assert.strictEqual( window.testBar, "bar", "Check if script was evaluated" );
done(); done();
} }
} ); } );
@ -2858,7 +2867,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re
assert.expect( 7 ); assert.expect( 7 );
var done = assert.async(); var done = assert.async();
var verifyEvaluation = function() { var verifyEvaluation = function() {
assert.strictEqual( window[ "testBar" ], "bar", "Check if script src was evaluated after load" ); assert.strictEqual( window.testBar, "bar", "Check if script src was evaluated after load" );
assert.strictEqual( jQuery( "#ap" ).html(), "bar", "Check if script evaluation has modified DOM" ); assert.strictEqual( jQuery( "#ap" ).html(), "bar", "Check if script evaluation has modified DOM" );
done(); done();
}; };
@ -2869,7 +2878,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re
jQuery( "#first" ).load( url( "mock.php?action=testHTML&baseURL=" + baseURL ), function() { jQuery( "#first" ).load( url( "mock.php?action=testHTML&baseURL=" + baseURL ), function() {
assert.ok( jQuery( "#first" ).html().match( /^html text/ ), "Check content after loading html" ); assert.ok( jQuery( "#first" ).html().match( /^html text/ ), "Check content after loading html" );
assert.strictEqual( jQuery( "#foo" ).html(), "foo", "Check if script evaluation has modified DOM" ); assert.strictEqual( jQuery( "#foo" ).html(), "foo", "Check if script evaluation has modified DOM" );
assert.strictEqual( window[ "testFoo" ], "foo", "Check if script was evaluated after load" ); assert.strictEqual( window.testFoo, "foo", "Check if script was evaluated after load" );
setTimeout( verifyEvaluation, 600 ); setTimeout( verifyEvaluation, 600 );
} ); } );
} ); } );
@ -2881,7 +2890,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re
jQuery( "#first" ).load( url( "test2.html" ), function() { jQuery( "#first" ).load( url( "test2.html" ), function() {
assert.strictEqual( jQuery( "#foo" ).html(), "foo", "Check if script evaluation has modified DOM" ); assert.strictEqual( jQuery( "#foo" ).html(), "foo", "Check if script evaluation has modified DOM" );
assert.strictEqual( window[ "testFoo" ], "foo", "Check if script was evaluated after load" ); assert.strictEqual( window.testFoo, "foo", "Check if script was evaluated after load" );
done(); done();
} ); } );
} ); } );

View File

@ -239,7 +239,7 @@ QUnit.test( "attr(Hash)", function( assert ) {
assert.equal( assert.equal(
jQuery( "#text1" ).attr( { jQuery( "#text1" ).attr( {
"value": function() { "value": function() {
return this[ "id" ]; return this.id;
} } ).attr( "value" ), } } ).attr( "value" ),
"text1", "text1",
"Set attribute to computed value #1" "Set attribute to computed value #1"
@ -394,11 +394,11 @@ QUnit.test( "attr(String, Object)", function( assert ) {
table = jQuery( "#table" ).append( "<tr><td>cell</td></tr><tr><td>cell</td><td>cell</td></tr><tr><td>cell</td><td>cell</td></tr>" ); table = jQuery( "#table" ).append( "<tr><td>cell</td></tr><tr><td>cell</td><td>cell</td></tr><tr><td>cell</td><td>cell</td></tr>" );
td = table.find( "td" ).eq( 0 ); td = table.find( "td" ).eq( 0 );
td.attr( "rowspan", "2" ); td.attr( "rowspan", "2" );
assert.equal( td[ 0 ][ "rowSpan" ], 2, "Check rowspan is correctly set" ); assert.equal( td[ 0 ].rowSpan, 2, "Check rowspan is correctly set" );
td.attr( "colspan", "2" ); td.attr( "colspan", "2" );
assert.equal( td[ 0 ][ "colSpan" ], 2, "Check colspan is correctly set" ); assert.equal( td[ 0 ].colSpan, 2, "Check colspan is correctly set" );
table.attr( "cellspacing", "2" ); table.attr( "cellspacing", "2" );
assert.equal( table[ 0 ][ "cellSpacing" ], "2", "Check cellspacing is correctly set" ); assert.equal( table[ 0 ].cellSpacing, "2", "Check cellspacing is correctly set" );
assert.equal( jQuery( "#area1" ).attr( "value" ), undefined, "Value attribute is distinct from value property." ); assert.equal( jQuery( "#area1" ).attr( "value" ), undefined, "Value attribute is distinct from value property." );
@ -456,6 +456,7 @@ QUnit.test( "attr(String, Object)", function( assert ) {
$radio = jQuery( "<input>", { $radio = jQuery( "<input>", {
"value": "sup", "value": "sup",
// Use uppercase here to ensure the type // Use uppercase here to ensure the type
// attrHook is still used // attrHook is still used
"TYPE": "radio" "TYPE": "radio"
@ -724,9 +725,9 @@ QUnit.test( "prop(String, Object) on null/undefined", function( assert ) {
$body = jQuery( body ); $body = jQuery( body );
assert.ok( $body.prop( "nextSibling" ) === null, "Make sure a null expando returns null" ); assert.ok( $body.prop( "nextSibling" ) === null, "Make sure a null expando returns null" );
body[ "foo" ] = "bar"; body.foo = "bar";
assert.equal( $body.prop( "foo" ), "bar", "Make sure the expando is preferred over the dom attribute" ); assert.equal( $body.prop( "foo" ), "bar", "Make sure the expando is preferred over the dom attribute" );
body[ "foo" ] = undefined; body.foo = undefined;
assert.ok( $body.prop( "foo" ) === undefined, "Make sure the expando is preferred over the dom attribute, even if undefined" ); assert.ok( $body.prop( "foo" ) === undefined, "Make sure the expando is preferred over the dom attribute, even if undefined" );
select = document.createElement( "select" ); select = document.createElement( "select" );
@ -871,7 +872,7 @@ QUnit.test( "removeProp(String)", function( assert ) {
obj = {}; obj = {};
assert.strictEqual( assert.strictEqual(
jQuery( "#firstp" ).prop( "nonexisting", "foo" ).removeProp( "nonexisting" )[ 0 ][ "nonexisting" ], jQuery( "#firstp" ).prop( "nonexisting", "foo" ).removeProp( "nonexisting" )[ 0 ].nonexisting,
undefined, undefined,
"removeprop works correctly on DOM element nodes" "removeprop works correctly on DOM element nodes"
); );
@ -879,12 +880,12 @@ QUnit.test( "removeProp(String)", function( assert ) {
jQuery.each( [ document, obj ], function( i, ele ) { jQuery.each( [ document, obj ], function( i, ele ) {
var $ele = jQuery( ele ); var $ele = jQuery( ele );
$ele.prop( "nonexisting", "foo" ).removeProp( "nonexisting" ); $ele.prop( "nonexisting", "foo" ).removeProp( "nonexisting" );
assert.strictEqual( ele[ "nonexisting" ], undefined, "removeProp works correctly on non DOM element nodes (bug trac-7500)." ); assert.strictEqual( ele.nonexisting, undefined, "removeProp works correctly on non DOM element nodes (bug trac-7500)." );
} ); } );
jQuery.each( [ commentNode, textNode, attributeNode ], function( i, ele ) { jQuery.each( [ commentNode, textNode, attributeNode ], function( i, ele ) {
var $ele = jQuery( ele ); var $ele = jQuery( ele );
$ele.prop( "nonexisting", "foo" ).removeProp( "nonexisting" ); $ele.prop( "nonexisting", "foo" ).removeProp( "nonexisting" );
assert.strictEqual( ele[ "nonexisting" ], undefined, "removeProp works correctly on non DOM element nodes (bug trac-7500)." ); assert.strictEqual( ele.nonexisting, undefined, "removeProp works correctly on non DOM element nodes (bug trac-7500)." );
} ); } );
} ); } );
@ -1131,7 +1132,7 @@ QUnit.test( "val(select) after form.reset() (Bug trac-2551)", function( assert )
jQuery( "#kkk" ).val( "gf" ); jQuery( "#kkk" ).val( "gf" );
document[ "kk" ].reset(); document.kk.reset();
assert.equal( jQuery( "#kkk" )[ 0 ].value, "cf", "Check value of select after form reset." ); assert.equal( jQuery( "#kkk" )[ 0 ].value, "cf", "Check value of select after form reset." );
assert.equal( jQuery( "#kkk" ).val(), "cf", "Check value of select after form reset." ); assert.equal( jQuery( "#kkk" ).val(), "cf", "Check value of select after form reset." );

View File

@ -19,6 +19,7 @@ var output,
outputA = addToOutput( "A" ), outputA = addToOutput( "A" ),
outputB = addToOutput( "B" ), outputB = addToOutput( "B" ),
outputC = addToOutput( "C" ), outputC = addToOutput( "C" ),
/* eslint-disable key-spacing */
tests = { tests = {
"": "XABC X XABCABCC X XBB X XABA X XX", "": "XABC X XABCABCC X XBB X XABA X XX",
"once": "XABC X X X X X XABA X XX", "once": "XABC X X X X X XABA X XX",
@ -227,7 +228,9 @@ jQuery.each( tests, function( strFlags, resultString ) {
// Return false // Return false
output = "X"; output = "X";
cblist = jQuery.Callbacks( flags ); cblist = jQuery.Callbacks( flags );
cblist.add( outputA, function() { return false; }, outputB ); cblist.add( outputA, function() {
return false;
}, outputB );
cblist.add( outputA ); cblist.add( outputA );
cblist.fire(); cblist.fire();
assert.strictEqual( output, results.shift(), "Callback returning false" ); assert.strictEqual( output, results.shift(), "Callback returning false" );
@ -269,7 +272,7 @@ QUnit.test( "jQuery.Callbacks( options ) - options are copied", function( assert
fn = function() { fn = function() {
assert.ok( !( count++ ), "called once" ); assert.ok( !( count++ ), "called once" );
}; };
options[ "unique" ] = false; options.unique = false;
cb.add( fn, fn ); cb.add( fn, fn );
cb.fire(); cb.fire();
} ); } );
@ -364,7 +367,9 @@ QUnit.test( "jQuery.Callbacks() - disabled callback doesn't fire (gh-1790)", fun
var cb = jQuery.Callbacks(), var cb = jQuery.Callbacks(),
fired = false, fired = false,
shot = function() { fired = true; }; shot = function() {
fired = true;
};
cb.disable(); cb.disable();
cb.empty(); cb.empty();
@ -379,8 +384,12 @@ QUnit.test( "jQuery.Callbacks() - list with memory stays locked (gh-3469)", func
var cb = jQuery.Callbacks( "memory" ), var cb = jQuery.Callbacks( "memory" ),
fired = 0, fired = 0,
count1 = function() { fired += 1; }, count1 = function() {
count2 = function() { fired += 10; }; fired += 1;
},
count2 = function() {
fired += 10;
};
cb.add( count1 ); cb.add( count1 );
cb.fire(); cb.fire();

View File

@ -38,19 +38,21 @@ QUnit.test( "jQuery()", function( assert ) {
// few here but beware of modular builds where these methods may be excluded. // few here but beware of modular builds where these methods may be excluded.
if ( includesModule( "deprecated" ) ) { if ( includesModule( "deprecated" ) ) {
expected++; expected++;
attrObj[ "click" ] = function() { assert.ok( exec, "Click executed." ); }; attrObj.click = function() {
assert.ok( exec, "Click executed." );
};
} }
if ( includesModule( "dimensions" ) ) { if ( includesModule( "dimensions" ) ) {
expected++; expected++;
attrObj[ "width" ] = 10; attrObj.width = 10;
} }
if ( includesModule( "offset" ) ) { if ( includesModule( "offset" ) ) {
expected++; expected++;
attrObj[ "offset" ] = { "top": 1, "left": 1 }; attrObj.offset = { "top": 1, "left": 1 };
} }
if ( includesModule( "css" ) ) { if ( includesModule( "css" ) ) {
expected += 2; expected += 2;
attrObj[ "css" ] = { "paddingLeft": 1, "paddingRight": 1 }; attrObj.css = { "paddingLeft": 1, "paddingRight": 1 };
} }
if ( includesModule( "attributes" ) ) { if ( includesModule( "attributes" ) ) {
expected++; expected++;
@ -216,17 +218,17 @@ QUnit.test( "noConflict", function( assert ) {
var $$ = jQuery; var $$ = jQuery;
assert.strictEqual( jQuery, jQuery.noConflict(), "noConflict returned the jQuery object" ); assert.strictEqual( jQuery, jQuery.noConflict(), "noConflict returned the jQuery object" );
assert.strictEqual( window[ "jQuery" ], $$, "Make sure jQuery wasn't touched." ); assert.strictEqual( window.jQuery, $$, "Make sure jQuery wasn't touched." );
assert.strictEqual( window[ "$" ], original$, "Make sure $ was reverted." ); assert.strictEqual( window.$, original$, "Make sure $ was reverted." );
jQuery = $ = $$; jQuery = $ = $$;
assert.strictEqual( jQuery.noConflict( true ), $$, "noConflict returned the jQuery object" ); assert.strictEqual( jQuery.noConflict( true ), $$, "noConflict returned the jQuery object" );
assert.strictEqual( window[ "jQuery" ], originaljQuery, "Make sure jQuery was reverted." ); assert.strictEqual( window.jQuery, originaljQuery, "Make sure jQuery was reverted." );
assert.strictEqual( window[ "$" ], original$, "Make sure $ was reverted." ); assert.strictEqual( window.$, original$, "Make sure $ was reverted." );
assert.ok( $$().pushStack( [] ), "Make sure that jQuery still works." ); assert.ok( $$().pushStack( [] ), "Make sure that jQuery still works." );
window[ "jQuery" ] = jQuery = $$; window.jQuery = jQuery = $$;
} ); } );
QUnit.test( "isPlainObject", function( assert ) { QUnit.test( "isPlainObject", function( assert ) {
@ -274,7 +276,7 @@ QUnit.test( "isPlainObject", function( assert ) {
// Makes the function a little more realistic // Makes the function a little more realistic
// (and harder to detect, incidentally) // (and harder to detect, incidentally)
fn.prototype[ "someMethod" ] = function() {}; fn.prototype.someMethod = function() {};
// Again, instantiated objects shouldn't be matched // Again, instantiated objects shouldn't be matched
assert.ok( !jQuery.isPlainObject( new fn() ), "new fn" ); assert.ok( !jQuery.isPlainObject( new fn() ), "new fn" );
@ -431,10 +433,10 @@ QUnit.test( "XSS via location.hash", function( assert ) {
var done = assert.async(); var done = assert.async();
assert.expect( 1 ); assert.expect( 1 );
jQuery[ "_check9521" ] = function( x ) { jQuery._check9521 = function( x ) {
assert.ok( x, "script called from #id-like selector with inline handler" ); assert.ok( x, "script called from #id-like selector with inline handler" );
jQuery( "#check9521" ).remove(); jQuery( "#check9521" ).remove();
delete jQuery[ "_check9521" ]; delete jQuery._check9521;
done(); done();
}; };
try { try {
@ -442,7 +444,7 @@ QUnit.test( "XSS via location.hash", function( assert ) {
// This throws an error because it's processed like an id // This throws an error because it's processed like an id
jQuery( "#<img id='check9521' src='no-such-.gif' onerror='jQuery._check9521(false)'>" ).appendTo( "#qunit-fixture" ); jQuery( "#<img id='check9521' src='no-such-.gif' onerror='jQuery._check9521(false)'>" ).appendTo( "#qunit-fixture" );
} catch ( err ) { } catch ( err ) {
jQuery[ "_check9521" ]( true ); jQuery._check9521( true );
} }
} ); } );
@ -451,12 +453,12 @@ QUnit.test( "jQuery('html')", function( assert ) {
var s, div, j; var s, div, j;
jQuery[ "foo" ] = false; jQuery.foo = false;
s = jQuery( "<script>jQuery.foo='test';</script>" )[ 0 ]; s = jQuery( "<script>jQuery.foo='test';</script>" )[ 0 ];
assert.ok( s, "Creating a script" ); assert.ok( s, "Creating a script" );
assert.ok( !jQuery[ "foo" ], "Make sure the script wasn't executed prematurely" ); assert.ok( !jQuery.foo, "Make sure the script wasn't executed prematurely" );
jQuery( "body" ).append( "<script>jQuery.foo='test';</script>" ); jQuery( "body" ).append( "<script>jQuery.foo='test';</script>" );
assert.ok( jQuery[ "foo" ], "Executing a script's contents in the right context" ); assert.ok( jQuery.foo, "Executing a script's contents in the right context" );
// Test multi-line HTML // Test multi-line HTML
div = jQuery( "<div>\r\nsome text\n<p>some p</p>\nmore text\r\n</div>" )[ 0 ]; div = jQuery( "<div>\r\nsome text\n<p>some p</p>\nmore text\r\n</div>" )[ 0 ];
@ -584,20 +586,20 @@ QUnit.test( "inArray()", function( assert ) {
assert.expect( 19 ); assert.expect( 19 );
var selections = { var selections = {
p: q( "firstp", "sap", "ap", "first" ), p: q( "firstp", "sap", "ap", "first" ),
em: q( "siblingnext", "siblingfirst" ), em: q( "siblingnext", "siblingfirst" ),
div: q( "qunit-testrunner-toolbar", "nothiddendiv", "nothiddendivchild", "foo" ), div: q( "qunit-testrunner-toolbar", "nothiddendiv", "nothiddendivchild", "foo" ),
a: q( "mark", "groups", "google", "simon1" ), a: q( "mark", "groups", "google", "simon1" ),
empty: [] empty: []
}, },
tests = { tests = {
p: { elem: jQuery( "#ap" )[ 0 ], index: 2 }, p: { elem: jQuery( "#ap" )[ 0 ], index: 2 },
em: { elem: jQuery( "#siblingfirst" )[ 0 ], index: 1 }, em: { elem: jQuery( "#siblingfirst" )[ 0 ], index: 1 },
div: { elem: jQuery( "#nothiddendiv" )[ 0 ], index: 1 }, div: { elem: jQuery( "#nothiddendiv" )[ 0 ], index: 1 },
a: { elem: jQuery( "#simon1" )[ 0 ], index: 3 } a: { elem: jQuery( "#simon1" )[ 0 ], index: 3 }
}, },
falseTests = { falseTests = {
p: jQuery( "#liveSpan1" )[ 0 ], p: jQuery( "#liveSpan1" )[ 0 ],
em: jQuery( "#nothiddendiv" )[ 0 ], em: jQuery( "#nothiddendiv" )[ 0 ],
empty: "" empty: ""
}; };
@ -634,7 +636,9 @@ QUnit.test( "each(Function)", function( assert ) {
var div, pass, i; var div, pass, i;
div = jQuery( "div" ); div = jQuery( "div" );
div.each( function() {this.foo = "zoo";} ); div.each( function() {
this.foo = "zoo";
} );
pass = true; pass = true;
for ( i = 0; i < div.length; i++ ) { for ( i = 0; i < div.length; i++ ) {
if ( div.get( i ).foo !== "zoo" ) { if ( div.get( i ).foo !== "zoo" ) {
@ -740,8 +744,13 @@ QUnit.test( "jQuery.map", function( assert ) {
result = { result = {
Zero: function() {}, Zero: function() {},
One: function( a ) { a = a; }, One: function( a ) {
Two: function( a, b ) { a = a; b = b; } a = a;
},
Two: function( a, b ) {
a = a;
b = b;
}
}; };
callback = function( v, k ) { callback = function( v, k ) {
assert.equal( k, "foo", label + "-argument function treated like object" ); assert.equal( k, "foo", label + "-argument function treated like object" );
@ -1000,25 +1009,25 @@ QUnit.test( "jQuery.extend(Object, Object)", function( assert ) {
assert.deepEqual( options, optionsCopy, "Check if not modified: options must not be modified" ); assert.deepEqual( options, optionsCopy, "Check if not modified: options must not be modified" );
jQuery.extend( true, deep1, deep2 ); jQuery.extend( true, deep1, deep2 );
assert.deepEqual( deep1[ "foo" ], deepmerged[ "foo" ], "Check if foo: settings must be extended" ); assert.deepEqual( deep1.foo, deepmerged.foo, "Check if foo: settings must be extended" );
assert.deepEqual( deep2[ "foo" ], deep2copy[ "foo" ], "Check if not deep2: options must not be modified" ); assert.deepEqual( deep2.foo, deep2copy.foo, "Check if not deep2: options must not be modified" );
assert.equal( deep1[ "foo2" ], document, "Make sure that a deep clone was not attempted on the document" ); assert.equal( deep1.foo2, document, "Make sure that a deep clone was not attempted on the document" );
assert.ok( jQuery.extend( true, {}, nestedarray )[ "arr" ] !== arr, "Deep extend of object must clone child array" ); assert.ok( jQuery.extend( true, {}, nestedarray ).arr !== arr, "Deep extend of object must clone child array" );
// trac-5991 // trac-5991
assert.ok( Array.isArray( jQuery.extend( true, { "arr": {} }, nestedarray )[ "arr" ] ), "Cloned array have to be an Array" ); assert.ok( Array.isArray( jQuery.extend( true, { "arr": {} }, nestedarray ).arr ), "Cloned array have to be an Array" );
assert.ok( jQuery.isPlainObject( jQuery.extend( true, { "arr": arr }, { "arr": {} } )[ "arr" ] ), "Cloned object have to be an plain object" ); assert.ok( jQuery.isPlainObject( jQuery.extend( true, { "arr": arr }, { "arr": {} } ).arr ), "Cloned object have to be an plain object" );
empty = {}; empty = {};
optionsWithLength = { "foo": { "length": -1 } }; optionsWithLength = { "foo": { "length": -1 } };
jQuery.extend( true, empty, optionsWithLength ); jQuery.extend( true, empty, optionsWithLength );
assert.deepEqual( empty[ "foo" ], optionsWithLength[ "foo" ], "The length property must copy correctly" ); assert.deepEqual( empty.foo, optionsWithLength.foo, "The length property must copy correctly" );
empty = {}; empty = {};
optionsWithDate = { "foo": { "date": new Date() } }; optionsWithDate = { "foo": { "date": new Date() } };
jQuery.extend( true, empty, optionsWithDate ); jQuery.extend( true, empty, optionsWithDate );
assert.deepEqual( empty[ "foo" ], optionsWithDate[ "foo" ], "Dates copy correctly" ); assert.deepEqual( empty.foo, optionsWithDate.foo, "Dates copy correctly" );
/** @constructor */ /** @constructor */
myKlass = function() {}; myKlass = function() {};
@ -1026,13 +1035,13 @@ QUnit.test( "jQuery.extend(Object, Object)", function( assert ) {
optionsWithCustomObject = { "foo": { "date": customObject } }; optionsWithCustomObject = { "foo": { "date": customObject } };
empty = {}; empty = {};
jQuery.extend( true, empty, optionsWithCustomObject ); jQuery.extend( true, empty, optionsWithCustomObject );
assert.ok( empty[ "foo" ] && empty[ "foo" ][ "date" ] === customObject, "Custom objects copy correctly (no methods)" ); assert.ok( empty.foo && empty.foo.date === customObject, "Custom objects copy correctly (no methods)" );
// Makes the class a little more realistic // Makes the class a little more realistic
myKlass.prototype = { "someMethod": function() {} }; myKlass.prototype = { "someMethod": function() {} };
empty = {}; empty = {};
jQuery.extend( true, empty, optionsWithCustomObject ); jQuery.extend( true, empty, optionsWithCustomObject );
assert.ok( empty[ "foo" ] && empty[ "foo" ][ "date" ] === customObject, "Custom objects copy correctly" ); assert.ok( empty.foo && empty.foo.date === customObject, "Custom objects copy correctly" );
MyNumber = Number; MyNumber = Number;
@ -1040,18 +1049,18 @@ QUnit.test( "jQuery.extend(Object, Object)", function( assert ) {
assert.ok( parseInt( ret.foo, 10 ) === 5, "Wrapped numbers copy correctly" ); assert.ok( parseInt( ret.foo, 10 ) === 5, "Wrapped numbers copy correctly" );
nullUndef = jQuery.extend( {}, options, { "xnumber2": null } ); nullUndef = jQuery.extend( {}, options, { "xnumber2": null } );
assert.ok( nullUndef[ "xnumber2" ] === null, "Check to make sure null values are copied" ); assert.ok( nullUndef.xnumber2 === null, "Check to make sure null values are copied" );
nullUndef = jQuery.extend( {}, options, { "xnumber2": undefined } ); nullUndef = jQuery.extend( {}, options, { "xnumber2": undefined } );
assert.ok( nullUndef[ "xnumber2" ] === options[ "xnumber2" ], "Check to make sure undefined values are not copied" ); assert.ok( nullUndef.xnumber2 === options.xnumber2, "Check to make sure undefined values are not copied" );
nullUndef = jQuery.extend( {}, options, { "xnumber0": null } ); nullUndef = jQuery.extend( {}, options, { "xnumber0": null } );
assert.ok( nullUndef[ "xnumber0" ] === null, "Check to make sure null values are inserted" ); assert.ok( nullUndef.xnumber0 === null, "Check to make sure null values are inserted" );
target = {}; target = {};
recursive = { foo:target, bar:5 }; recursive = { foo: target, bar: 5 };
jQuery.extend( true, target, recursive ); jQuery.extend( true, target, recursive );
assert.deepEqual( target, { bar:5 }, "Check to make sure a recursive obj doesn't go never-ending loop by not copying it over" ); assert.deepEqual( target, { bar: 5 }, "Check to make sure a recursive obj doesn't go never-ending loop by not copying it over" );
ret = jQuery.extend( true, { foo: [] }, { foo: [ 0 ] } ); // 1907 ret = jQuery.extend( true, { foo: [] }, { foo: [ 0 ] } ); // 1907
assert.equal( ret.foo.length, 1, "Check to make sure a value with coercion 'false' copies over when necessary to fix trac-1907" ); assert.equal( ret.foo.length, 1, "Check to make sure a value with coercion 'false' copies over when necessary to fix trac-1907" );
@ -1059,11 +1068,11 @@ QUnit.test( "jQuery.extend(Object, Object)", function( assert ) {
ret = jQuery.extend( true, { foo: "1,2,3" }, { foo: [ 1, 2, 3 ] } ); ret = jQuery.extend( true, { foo: "1,2,3" }, { foo: [ 1, 2, 3 ] } );
assert.ok( typeof ret.foo !== "string", "Check to make sure values equal with coercion (but not actually equal) overwrite correctly" ); assert.ok( typeof ret.foo !== "string", "Check to make sure values equal with coercion (but not actually equal) overwrite correctly" );
ret = jQuery.extend( true, { foo:"bar" }, { foo:null } ); ret = jQuery.extend( true, { foo: "bar" }, { foo: null } );
assert.ok( typeof ret.foo !== "undefined", "Make sure a null value doesn't crash with deep extend, for trac-1908" ); assert.ok( typeof ret.foo !== "undefined", "Make sure a null value doesn't crash with deep extend, for trac-1908" );
obj = { foo:null }; obj = { foo: null };
jQuery.extend( true, obj, { foo:"notnull" } ); jQuery.extend( true, obj, { foo: "notnull" } );
assert.equal( obj.foo, "notnull", "Make sure a null value can be overwritten" ); assert.equal( obj.foo, "notnull", "Make sure a null value can be overwritten" );
function func() {} function func() {}
@ -1089,19 +1098,19 @@ QUnit.test( "jQuery.extend(Object, Object {created with \"defineProperties\"})",
assert.expect( 2 ); assert.expect( 2 );
var definedObj = Object.defineProperties( {}, { var definedObj = Object.defineProperties( {}, {
"enumerableProp": { "enumerableProp": {
get: function() { get: function() {
return true; return true;
}, },
enumerable: true enumerable: true
}, },
"nonenumerableProp": { "nonenumerableProp": {
get: function() { get: function() {
return true; return true;
} }
} }
} ), } ),
accessorObj = {}; accessorObj = {};
jQuery.extend( accessorObj, definedObj ); jQuery.extend( accessorObj, definedObj );
assert.equal( accessorObj.enumerableProp, true, "Verify that getters are transferred" ); assert.equal( accessorObj.enumerableProp, true, "Verify that getters are transferred" );
@ -1173,8 +1182,13 @@ QUnit.test( "jQuery.each(Object,Function)", function( assert ) {
seen = { seen = {
Zero: function() {}, Zero: function() {},
One: function( a ) { a = a; }, One: function( a ) {
Two: function( a, b ) { a = a; b = b; } a = a;
},
Two: function( a, b ) {
a = a;
b = b;
}
}; };
callback = function( k ) { callback = function( k ) {
assert.equal( k, "foo", label + "-argument function treated like object" ); assert.equal( k, "foo", label + "-argument function treated like object" );
@ -1283,7 +1297,9 @@ QUnit.test( "jQuery.makeArray", function( assert ) {
assert.equal( jQuery.makeArray( document.getElementsByName( "PWD" ) ).slice( 0, 1 )[ 0 ].name, "PWD", "Pass makeArray a nodelist" ); assert.equal( jQuery.makeArray( document.getElementsByName( "PWD" ) ).slice( 0, 1 )[ 0 ].name, "PWD", "Pass makeArray a nodelist" );
assert.equal( ( function() { return jQuery.makeArray( arguments ); } )( 1, 2 ).join( "" ), "12", "Pass makeArray an arguments array" ); assert.equal( ( function() {
return jQuery.makeArray( arguments );
} )( 1, 2 ).join( "" ), "12", "Pass makeArray an arguments array" );
assert.equal( jQuery.makeArray( [ 1, 2, 3 ] ).join( "" ), "123", "Pass makeArray a real array" ); assert.equal( jQuery.makeArray( [ 1, 2, 3 ] ).join( "" ), "123", "Pass makeArray a real array" );
@ -1297,12 +1313,14 @@ QUnit.test( "jQuery.makeArray", function( assert ) {
assert.equal( jQuery.makeArray( document.createElement( "div" ) )[ 0 ].nodeName.toUpperCase(), "DIV", "Pass makeArray a single node" ); assert.equal( jQuery.makeArray( document.createElement( "div" ) )[ 0 ].nodeName.toUpperCase(), "DIV", "Pass makeArray a single node" );
assert.equal( jQuery.makeArray( { length:2, 0:"a", 1:"b" } ).join( "" ), "ab", "Pass makeArray an array like map (with length)" ); assert.equal( jQuery.makeArray( { length: 2, 0: "a", 1: "b" } ).join( "" ), "ab", "Pass makeArray an array like map (with length)" );
assert.ok( !!jQuery.makeArray( document.documentElement.childNodes ).slice( 0, 1 )[ 0 ].nodeName, "Pass makeArray a childNodes array" ); assert.ok( !!jQuery.makeArray( document.documentElement.childNodes ).slice( 0, 1 )[ 0 ].nodeName, "Pass makeArray a childNodes array" );
// function, is tricky as it has length // function, is tricky as it has length
assert.equal( jQuery.makeArray( function() { return 1;} )[ 0 ](), 1, "Pass makeArray a function" ); assert.equal( jQuery.makeArray( function() {
return 1;
} )[ 0 ](), 1, "Pass makeArray a function" );
//window, also has length //window, also has length
assert.equal( jQuery.makeArray( window )[ 0 ], window, "Pass makeArray the window" ); assert.equal( jQuery.makeArray( window )[ 0 ], window, "Pass makeArray the window" );
@ -1328,7 +1346,7 @@ QUnit.test( "jQuery.isEmptyObject", function( assert ) {
assert.expect( 2 ); assert.expect( 2 );
assert.equal( true, jQuery.isEmptyObject( {} ), "isEmptyObject on empty object literal" ); assert.equal( true, jQuery.isEmptyObject( {} ), "isEmptyObject on empty object literal" );
assert.equal( false, jQuery.isEmptyObject( { a:1 } ), "isEmptyObject on non-empty object literal" ); assert.equal( false, jQuery.isEmptyObject( { a: 1 } ), "isEmptyObject on non-empty object literal" );
// What about this ? // What about this ?
// equal(true, jQuery.isEmptyObject(null), "isEmptyObject on null" ); // equal(true, jQuery.isEmptyObject(null), "isEmptyObject on null" );

View File

@ -38,7 +38,7 @@ QUnit.test( "css(String|Hash)", function( assert ) {
width = parseFloat( jQuery( "#nothiddendiv" ).css( "width" ) ); width = parseFloat( jQuery( "#nothiddendiv" ).css( "width" ) );
height = parseFloat( jQuery( "#nothiddendiv" ).css( "height" ) ); height = parseFloat( jQuery( "#nothiddendiv" ).css( "height" ) );
jQuery( "#nothiddendiv" ).css( { "overflow":"hidden", "width": -1, "height": -1 } ); jQuery( "#nothiddendiv" ).css( { "overflow": "hidden", "width": -1, "height": -1 } );
assert.equal( parseFloat( jQuery( "#nothiddendiv" ).css( "width" ) ), 0, "Test negative width set to 0" ); assert.equal( parseFloat( jQuery( "#nothiddendiv" ).css( "width" ) ), 0, "Test negative width set to 0" );
assert.equal( parseFloat( jQuery( "#nothiddendiv" ).css( "height" ) ), 0, "Test negative height set to 0" ); assert.equal( parseFloat( jQuery( "#nothiddendiv" ).css( "height" ) ), 0, "Test negative height set to 0" );
@ -321,8 +321,7 @@ QUnit.test( "css(String, Object)", function( assert ) {
success = true; success = true;
try { try {
jQuery( "#foo" ).css( "backgroundColor", "rgba(0, 0, 0, 0.1)" ); jQuery( "#foo" ).css( "backgroundColor", "rgba(0, 0, 0, 0.1)" );
} } catch ( e ) {
catch ( e ) {
success = false; success = false;
} }
assert.ok( success, "Setting RGBA values does not throw Error (trac-5509)" ); assert.ok( success, "Setting RGBA values does not throw Error (trac-5509)" );
@ -1221,6 +1220,7 @@ QUnit.test( "Do not append px (trac-9548, trac-12990, gh-2792, gh-5179)", functi
$div.css( "animation-iteration-count", 2 ); $div.css( "animation-iteration-count", 2 );
if ( $div.css( "animation-iteration-count" ) !== undefined ) { if ( $div.css( "animation-iteration-count" ) !== undefined ) {
// if $div.css( "animation-iteration-count" ) returns "1", // if $div.css( "animation-iteration-count" ) returns "1",
// it actually returns the default value of animation-iteration-count // it actually returns the default value of animation-iteration-count
assert.equal( $div.css( "animation-iteration-count" ), "2", assert.equal( $div.css( "animation-iteration-count" ), "2",
@ -1788,7 +1788,7 @@ QUnit.test( "Do not throw on frame elements from css method (trac-15098)", funct
if ( transformName ) { if ( transformName ) {
assert.equal( elemStyle[ transformName ], transformVal, "setting properly-prefixed transform" ); assert.equal( elemStyle[ transformName ], transformVal, "setting properly-prefixed transform" );
} }
assert.equal( elemStyle[ "undefined" ], undefined, "Nothing writes to node.style.undefined" ); assert.equal( elemStyle.undefined, undefined, "Nothing writes to node.style.undefined" );
} ); } );
QUnit.test( "Don't detect fake set properties on a node when caching the prefixed version", function( assert ) { QUnit.test( "Don't detect fake set properties on a node when caching the prefixed version", function( assert ) {

View File

@ -74,14 +74,14 @@ function dataTests( elem, assert ) {
assert.strictEqual( jQuery.hasData( elem ), false, "jQuery.hasData agrees no data exists even when an empty data obj exists" ); assert.strictEqual( jQuery.hasData( elem ), false, "jQuery.hasData agrees no data exists even when an empty data obj exists" );
dataObj[ "foo" ] = "bar"; dataObj.foo = "bar";
assert.equal( jQuery.data( elem, "foo" ), "bar", "Data is readable by jQuery.data when set directly on a returned data object" ); assert.equal( jQuery.data( elem, "foo" ), "bar", "Data is readable by jQuery.data when set directly on a returned data object" );
assert.strictEqual( jQuery.hasData( elem ), true, "jQuery.hasData agrees data exists when data exists" ); assert.strictEqual( jQuery.hasData( elem ), true, "jQuery.hasData agrees data exists when data exists" );
jQuery.data( elem, "foo", "baz" ); jQuery.data( elem, "foo", "baz" );
assert.equal( jQuery.data( elem, "foo" ), "baz", "Data can be changed by jQuery.data" ); assert.equal( jQuery.data( elem, "foo" ), "baz", "Data can be changed by jQuery.data" );
assert.equal( dataObj[ "foo" ], "baz", "Changes made through jQuery.data propagate to referenced data object" ); assert.equal( dataObj.foo, "baz", "Changes made through jQuery.data propagate to referenced data object" );
jQuery.data( elem, "foo", undefined ); jQuery.data( elem, "foo", undefined );
assert.equal( jQuery.data( elem, "foo" ), "baz", "Data is not unset by passing undefined to jQuery.data" ); assert.equal( jQuery.data( elem, "foo" ), "baz", "Data is not unset by passing undefined to jQuery.data" );
@ -398,7 +398,7 @@ QUnit.test( "data-* attributes", function( assert ) {
break; break;
case 2: case 2:
assert.equal( jQuery( elem ).data( "zoooo" ), "bar", "Check zoooo property" ); assert.equal( jQuery( elem ).data( "zoooo" ), "bar", "Check zoooo property" );
assert.deepEqual( jQuery( elem ).data( "bar" ), { "test":"baz" }, "Check bar property" ); assert.deepEqual( jQuery( elem ).data( "bar" ), { "test": "baz" }, "Check bar property" );
break; break;
case 3: case 3:
assert.equal( jQuery( elem ).data( "number" ), true, "Check number property" ); assert.equal( jQuery( elem ).data( "number" ), true, "Check number property" );
@ -426,13 +426,13 @@ QUnit.test( ".data(Object)", function( assert ) {
assert.equal( div.data( "test" ), "in", "Verify setting an object in data" ); assert.equal( div.data( "test" ), "in", "Verify setting an object in data" );
assert.equal( div.data( "test2" ), "in2", "Verify setting an object in data" ); assert.equal( div.data( "test2" ), "in2", "Verify setting an object in data" );
obj = { test:"unset" }; obj = { test: "unset" };
jqobj = jQuery( obj ); jqobj = jQuery( obj );
jqobj.data( "test", "unset" ); jqobj.data( "test", "unset" );
jqobj.data( { "test": "in", "test2": "in2" } ); jqobj.data( { "test": "in", "test2": "in2" } );
assert.equal( jQuery.data( obj )[ "test" ], "in", "Verify setting an object on an object extends the data object" ); assert.equal( jQuery.data( obj ).test, "in", "Verify setting an object on an object extends the data object" );
assert.equal( obj[ "test2" ], undefined, "Verify setting an object on an object does not extend the object" ); assert.equal( obj.test2, undefined, "Verify setting an object on an object does not extend the object" );
// manually clean up detached elements // manually clean up detached elements
div.remove(); div.remove();
@ -523,12 +523,12 @@ QUnit.test( ".data should follow html5 specification regarding camel casing", fu
var div = jQuery( "<div id='myObject' data-w-t-f='ftw' data-big-a-little-a='bouncing-b' data-foo='a' data-foo-bar='b' data-foo-bar-baz='c'></div>" ) var div = jQuery( "<div id='myObject' data-w-t-f='ftw' data-big-a-little-a='bouncing-b' data-foo='a' data-foo-bar='b' data-foo-bar-baz='c'></div>" )
.prependTo( "body" ); .prependTo( "body" );
assert.equal( div.data()[ "wTF" ], "ftw", "Verify single letter data-* key" ); assert.equal( div.data().wTF, "ftw", "Verify single letter data-* key" );
assert.equal( div.data()[ "bigALittleA" ], "bouncing-b", "Verify single letter mixed data-* key" ); assert.equal( div.data().bigALittleA, "bouncing-b", "Verify single letter mixed data-* key" );
assert.equal( div.data()[ "foo" ], "a", "Verify single word data-* key" ); assert.equal( div.data().foo, "a", "Verify single word data-* key" );
assert.equal( div.data()[ "fooBar" ], "b", "Verify multiple word data-* key" ); assert.equal( div.data().fooBar, "b", "Verify multiple word data-* key" );
assert.equal( div.data()[ "fooBarBaz" ], "c", "Verify multiple word data-* key" ); assert.equal( div.data().fooBarBaz, "c", "Verify multiple word data-* key" );
assert.equal( div.data( "foo" ), "a", "Verify single word data-* key" ); assert.equal( div.data( "foo" ), "a", "Verify single word data-* key" );
assert.equal( div.data( "fooBar" ), "b", "Verify multiple word data-* key" ); assert.equal( div.data( "fooBar" ), "b", "Verify multiple word data-* key" );

View File

@ -108,7 +108,9 @@ QUnit.test( "jQuery.Deferred.then - filtering (done)", function( assert ) {
piped = defer.then( function( a, b ) { piped = defer.then( function( a, b ) {
return a * b; return a * b;
} ), } ),
done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); done = jQuery.map( new Array( 3 ), function() {
return assert.async();
} );
piped.done( function( result ) { piped.done( function( result ) {
value3 = result; value3 = result;
@ -145,7 +147,9 @@ QUnit.test( "jQuery.Deferred.then - filtering (fail)", function( assert ) {
piped = defer.then( null, function( a, b ) { piped = defer.then( null, function( a, b ) {
return a * b; return a * b;
} ), } ),
done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); done = jQuery.map( new Array( 3 ), function() {
return assert.async();
} );
piped.done( function( result ) { piped.done( function( result ) {
value3 = result; value3 = result;
@ -178,10 +182,12 @@ QUnit.test( "jQuery.Deferred.catch", function( assert ) {
var value1, value2, value3, var value1, value2, value3,
defer = jQuery.Deferred(), defer = jQuery.Deferred(),
piped = defer[ "catch" ]( function( a, b ) { piped = defer.catch( function( a, b ) {
return a * b; return a * b;
} ), } ),
done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); done = jQuery.map( new Array( 3 ), function() {
return assert.async();
} );
piped.done( function( result ) { piped.done( function( result ) {
value3 = result; value3 = result;
@ -192,18 +198,18 @@ QUnit.test( "jQuery.Deferred.catch", function( assert ) {
value2 = b; value2 = b;
} ); } );
defer.reject( 2, 3 )[ "catch" ]( function() { defer.reject( 2, 3 ).catch( function() {
assert.strictEqual( value1, 2, "first reject value ok" ); assert.strictEqual( value1, 2, "first reject value ok" );
assert.strictEqual( value2, 3, "second reject value ok" ); assert.strictEqual( value2, 3, "second reject value ok" );
assert.strictEqual( value3, 6, "result of filter ok" ); assert.strictEqual( value3, 6, "result of filter ok" );
done.pop().call(); done.pop().call();
} ); } );
jQuery.Deferred().resolve()[ "catch" ]( function() { jQuery.Deferred().resolve().catch( function() {
assert.ok( false, "then should not be called on resolve" ); assert.ok( false, "then should not be called on resolve" );
} ).then( done.pop() ); } ).then( done.pop() );
jQuery.Deferred().reject()[ "catch" ]( jQuery.noop ).done( function( value ) { jQuery.Deferred().reject().catch( jQuery.noop ).done( function( value ) {
assert.strictEqual( value, undefined, "then fail callback can return undefined/null" ); assert.strictEqual( value, undefined, "then fail callback can return undefined/null" );
done.pop().call(); done.pop().call();
} ); } );
@ -218,7 +224,9 @@ QUnit.test( "[PIPE ONLY] jQuery.Deferred.pipe - filtering (fail)", function( ass
piped = defer.pipe( null, function( a, b ) { piped = defer.pipe( null, function( a, b ) {
return a * b; return a * b;
} ), } ),
done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); done = jQuery.map( new Array( 3 ), function() {
return assert.async();
} );
piped.fail( function( result ) { piped.fail( function( result ) {
value3 = result; value3 = result;
@ -416,7 +424,9 @@ QUnit.test( "jQuery.Deferred.then - context", function( assert ) {
var defer, piped, defer2, piped2, var defer, piped, defer2, piped2,
context = { custom: true }, context = { custom: true },
done = jQuery.map( new Array( 5 ), function() { return assert.async(); } ); done = jQuery.map( new Array( 5 ), function() {
return assert.async();
} );
jQuery.Deferred().resolveWith( context, [ 2 ] ).then( function( value ) { jQuery.Deferred().resolveWith( context, [ 2 ] ).then( function( value ) {
assert.strictEqual( this, context, "custom context received by .then handler" ); assert.strictEqual( this, context, "custom context received by .then handler" );
@ -475,7 +485,9 @@ QUnit.test( "[PIPE ONLY] jQuery.Deferred.pipe - context", function( assert ) {
var defer, piped, defer2, piped2, var defer, piped, defer2, piped2,
context = { custom: true }, context = { custom: true },
done = jQuery.map( new Array( 5 ), function() { return assert.async(); } ); done = jQuery.map( new Array( 5 ), function() {
return assert.async();
} );
jQuery.Deferred().resolveWith( context, [ 2 ] ).pipe( function( value ) { jQuery.Deferred().resolveWith( context, [ 2 ] ).pipe( function( value ) {
assert.strictEqual( this, context, "custom context received by .pipe handler" ); assert.strictEqual( this, context, "custom context received by .pipe handler" );
@ -676,7 +688,9 @@ QUnit.test( "jQuery.Deferred - 1.x/2.x compatibility", function( assert ) {
var context = { id: "callback context" }, var context = { id: "callback context" },
thenable = jQuery.Deferred().resolve( "thenable fulfillment" ).promise(), thenable = jQuery.Deferred().resolve( "thenable fulfillment" ).promise(),
done = jQuery.map( new Array( 8 ), function() { return assert.async(); } ); done = jQuery.map( new Array( 8 ), function() {
return assert.async();
} );
thenable.unwrapped = false; thenable.unwrapped = false;
@ -727,7 +741,9 @@ QUnit.test( "jQuery.Deferred.then - progress and thenables", function( assert )
var trigger = jQuery.Deferred().notify(), var trigger = jQuery.Deferred().notify(),
expectedProgress = [ "baz", "baz" ], expectedProgress = [ "baz", "baz" ],
done = jQuery.map( new Array( 2 ), function() { return assert.async(); } ), done = jQuery.map( new Array( 2 ), function() {
return assert.async();
} ),
failer = function( evt ) { failer = function( evt ) {
return function() { return function() {
assert.ok( false, "no unexpected " + evt ); assert.ok( false, "no unexpected " + evt );
@ -752,7 +768,9 @@ QUnit.test( "jQuery.Deferred - notify and resolve", function( assert ) {
assert.expect( 7 ); assert.expect( 7 );
var notifiedResolved = jQuery.Deferred().notify( "foo" )/*xxx .resolve( "bar" )*/, var notifiedResolved = jQuery.Deferred().notify( "foo" )/*xxx .resolve( "bar" )*/,
done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); done = jQuery.map( new Array( 3 ), function() {
return assert.async();
} );
notifiedResolved.progress( function( v ) { notifiedResolved.progress( function( v ) {
assert.strictEqual( v, "foo", "progress value" ); assert.strictEqual( v, "foo", "progress value" );
@ -836,7 +854,9 @@ QUnit.test( "jQuery.when(nonThenable) - like Promise.resolve", function( assert
// Support: Android 4.0 only // Support: Android 4.0 only
// Strict mode functions invoked without .call/.apply get global-object context // Strict mode functions invoked without .call/.apply get global-object context
defaultContext = ( function getDefaultContext() { return this; } ).call(), defaultContext = ( function getDefaultContext() {
return this;
} ).call(),
done = assert.async( 20 ); done = assert.async( 20 );
@ -891,6 +911,7 @@ QUnit.test( "jQuery.when(thenable) - like Promise.resolve", function( assert ) {
var customToStringThen = { var customToStringThen = {
then: function( onFulfilled ) { then: function( onFulfilled ) {
// Support: Android 4.0 only // Support: Android 4.0 only
// Strict mode functions invoked without .call/.apply get global-object context // Strict mode functions invoked without .call/.apply get global-object context
onFulfilled.call(); onFulfilled.call();
@ -956,7 +977,9 @@ QUnit.test( "jQuery.when(thenable) - like Promise.resolve", function( assert ) {
// Support: Android 4.0 only // Support: Android 4.0 only
// Strict mode functions invoked without .call/.apply get global-object context // Strict mode functions invoked without .call/.apply get global-object context
defaultContext = ( function getDefaultContext() { return this; } ).call(), defaultContext = ( function getDefaultContext() {
return this;
} ).call(),
done = assert.async( numCases * 2 ); done = assert.async( numCases * 2 );
@ -1036,7 +1059,9 @@ QUnit.test( "jQuery.when(a, b) - like Promise.all", function( assert ) {
// Support: Android 4.0 only // Support: Android 4.0 only
// Strict mode functions invoked without .call/.apply get global-object context // Strict mode functions invoked without .call/.apply get global-object context
defaultContext = ( function getDefaultContext() { return this; } ).call(), defaultContext = ( function getDefaultContext() {
return this;
} ).call(),
done = assert.async( 98 ); done = assert.async( 98 );

View File

@ -46,8 +46,12 @@ QUnit.test( "hover() mouseenter mouseleave", function( assert ) {
assert.expect( 1 ); assert.expect( 1 );
var times = 0, var times = 0,
handler1 = function() { ++times; }, handler1 = function() {
handler2 = function() { ++times; }; ++times;
},
handler2 = function() {
++times;
};
jQuery( "#firstp" ) jQuery( "#firstp" )
.hover( handler1, handler2 ) .hover( handler1, handler2 )

62
test/unit/effects.js vendored
View File

@ -7,8 +7,12 @@ if ( !includesModule( "effects" ) ) {
var oldRaf = window.requestAnimationFrame, var oldRaf = window.requestAnimationFrame,
hideOptions = { hideOptions = {
inline: function() { jQuery.style( this, "display", "none" ); }, inline: function() {
cascade: function() { this.className = "hidden"; } jQuery.style( this, "display", "none" );
},
cascade: function() {
this.className = "hidden";
}
}; };
QUnit.module( "effects", { QUnit.module( "effects", {
@ -564,12 +568,12 @@ QUnit.test( "animate duration 0", function( assert ) {
assert.expect( 11 ); assert.expect( 11 );
var $elem, var $elem,
$elems = jQuery( [ { a:0 }, { a:0 } ] ), $elems = jQuery( [ { a: 0 }, { a: 0 } ] ),
counter = 0; counter = 0;
assert.equal( jQuery.timers.length, 0, "Make sure no animation was running from another test" ); assert.equal( jQuery.timers.length, 0, "Make sure no animation was running from another test" );
$elems.eq( 0 ).animate( { a:1 }, 0, function() { $elems.eq( 0 ).animate( { a: 1 }, 0, function() {
assert.ok( true, "Animate a simple property." ); assert.ok( true, "Animate a simple property." );
counter++; counter++;
} ); } );
@ -579,18 +583,18 @@ QUnit.test( "animate duration 0", function( assert ) {
assert.equal( counter, 1, "One synchronic animations" ); assert.equal( counter, 1, "One synchronic animations" );
$elems.animate( { a:2 }, 0, function() { $elems.animate( { a: 2 }, 0, function() {
assert.ok( true, "Animate a second simple property." ); assert.ok( true, "Animate a second simple property." );
counter++; counter++;
} ); } );
assert.equal( counter, 3, "Multiple synchronic animations" ); assert.equal( counter, 3, "Multiple synchronic animations" );
$elems.eq( 0 ).animate( { a:3 }, 0, function() { $elems.eq( 0 ).animate( { a: 3 }, 0, function() {
assert.ok( true, "Animate a third simple property." ); assert.ok( true, "Animate a third simple property." );
counter++; counter++;
} ); } );
$elems.eq( 1 ).animate( { a:3 }, 200, function() { $elems.eq( 1 ).animate( { a: 3 }, 200, function() {
counter++; counter++;
// Failed until [6115] // Failed until [6115]
@ -981,15 +985,33 @@ jQuery.each( {
num = 0; num = 0;
// TODO: uncrowd this // TODO: uncrowd this
if ( t_h === "show" ) { num++; } if ( t_h === "show" ) {
if ( t_w === "show" ) { num++; } num++;
if ( t_w === "hide" || t_w === "show" ) { num++; } }
if ( t_h === "hide" || t_h === "show" ) { num++; } if ( t_w === "show" ) {
if ( t_o === "hide" || t_o === "show" ) { num++; } num++;
if ( t_w === "hide" ) { num++; } }
if ( t_o.constructor === Number ) { num += 2; } if ( t_w === "hide" || t_w === "show" ) {
if ( t_w.constructor === Number ) { num += 2; } num++;
if ( t_h.constructor === Number ) { num += 2; } }
if ( t_h === "hide" || t_h === "show" ) {
num++;
}
if ( t_o === "hide" || t_o === "show" ) {
num++;
}
if ( t_w === "hide" ) {
num++;
}
if ( t_o.constructor === Number ) {
num += 2;
}
if ( t_w.constructor === Number ) {
num += 2;
}
if ( t_h.constructor === Number ) {
num += 2;
}
assert.expect( num ); assert.expect( num );
@ -2487,7 +2509,9 @@ QUnit.test( "Show/hide/toggle and display: inline", function( assert ) {
.hide().show( N ), .hide().show( N ),
$el.clone().data( { call: "hide+toggle", done: "inline" } ).appendTo( fixture ) $el.clone().data( { call: "hide+toggle", done: "inline" } ).appendTo( fixture )
.hide().toggle( N ) .hide().toggle( N )
], function( $clone ) { return $clone[ 0 ]; } ); ], function( $clone ) {
return $clone[ 0 ];
} );
// Animations not allowed to complete // Animations not allowed to complete
interrupted = jQuery.map( [ interrupted = jQuery.map( [
@ -2495,7 +2519,9 @@ QUnit.test( "Show/hide/toggle and display: inline", function( assert ) {
$el.clone().data( { call: "toggle+stop" } ).appendTo( fixture ).toggle( N ), $el.clone().data( { call: "toggle+stop" } ).appendTo( fixture ).toggle( N ),
$el.clone().data( { call: "hide+show+stop" } ).appendTo( fixture ).hide().show( N ), $el.clone().data( { call: "hide+show+stop" } ).appendTo( fixture ).hide().show( N ),
$el.clone().data( { call: "hide+toggle+stop" } ).appendTo( fixture ).hide().toggle( N ) $el.clone().data( { call: "hide+toggle+stop" } ).appendTo( fixture ).hide().toggle( N )
], function( $clone ) { return $clone[ 0 ]; } ); ], function( $clone ) {
return $clone[ 0 ];
} );
// All elements should be inline-block during the animation // All elements should be inline-block during the animation
clock.tick( N / 2 ); clock.tick( N / 2 );

View File

@ -224,12 +224,12 @@ QUnit.test( "on(), namespace with special add", function( assert ) {
div.on( "test.a", { x: 1 }, function( e ) { div.on( "test.a", { x: 1 }, function( e ) {
assert.ok( !!e.xyz, "Make sure that the data is getting passed through." ); assert.ok( !!e.xyz, "Make sure that the data is getting passed through." );
assert.equal( e.data[ "x" ], 1, "Make sure data is attached properly." ); assert.equal( e.data.x, 1, "Make sure data is attached properly." );
} ); } );
div.on( "test.b", { x: 2 }, function( e ) { div.on( "test.b", { x: 2 }, function( e ) {
assert.ok( !!e.xyz, "Make sure that the data is getting passed through." ); assert.ok( !!e.xyz, "Make sure that the data is getting passed through." );
assert.equal( e.data[ "x" ], 2, "Make sure data is attached properly." ); assert.equal( e.data.x, 2, "Make sure data is attached properly." );
} ); } );
// Should trigger 5 // Should trigger 5
@ -293,14 +293,14 @@ QUnit.test( "on/one/off(Object)", function( assert ) {
// Regular bind // Regular bind
.on( { .on( {
"click":handler, "click": handler,
"mouseover":handler "mouseover": handler
} ) } )
// Bind with data // Bind with data
.one( { .one( {
"click":handlerWithData, "click": handlerWithData,
"mouseover":handlerWithData "mouseover": handlerWithData
}, 2 ); }, 2 );
trigger(); trigger();
@ -313,8 +313,8 @@ QUnit.test( "on/one/off(Object)", function( assert ) {
assert.equal( mouseoverCounter, 4, "on(Object)" ); assert.equal( mouseoverCounter, 4, "on(Object)" );
jQuery( "#firstp" ).off( { jQuery( "#firstp" ).off( {
"click":handler, "click": handler,
"mouseover":handler "mouseover": handler
} ); } );
trigger(); trigger();
@ -553,7 +553,9 @@ QUnit.test( "on(), namespaced events, cloned events", function( assert ) {
} ).trigger( "tester" ); } ).trigger( "tester" );
// Make sure events stick with appendTo'd elements (which are cloned) trac-2027 // Make sure events stick with appendTo'd elements (which are cloned) trac-2027
jQuery( "<a href='#fail' class='test'>test</a>" ).on( "click", function() { return false; } ).appendTo( "#qunit-fixture" ); jQuery( "<a href='#fail' class='test'>test</a>" ).on( "click", function() {
return false;
} ).appendTo( "#qunit-fixture" );
assert.ok( jQuery( "a.test" ).eq( 0 ).triggerHandler( "click" ) === false, "Handler is bound to appendTo'd elements" ); assert.ok( jQuery( "a.test" ).eq( 0 ).triggerHandler( "click" ) === false, "Handler is bound to appendTo'd elements" );
} ); } );
@ -704,7 +706,9 @@ QUnit.test( "on(name, false), off(name, false)", function( assert ) {
assert.expect( 3 ); assert.expect( 3 );
var main = 0; var main = 0;
jQuery( "#qunit-fixture" ).on( "click", function() { main++; } ); jQuery( "#qunit-fixture" ).on( "click", function() {
main++;
} );
jQuery( "#ap" ).trigger( "click" ); jQuery( "#ap" ).trigger( "click" );
assert.equal( main, 1, "Verify that the trigger happened correctly." ); assert.equal( main, 1, "Verify that the trigger happened correctly." );
@ -727,7 +731,9 @@ QUnit.test( "on(name, selector, false), off(name, selector, false)", function( a
var main = 0; var main = 0;
jQuery( "#qunit-fixture" ).on( "click", "#ap", function() { main++; } ); jQuery( "#qunit-fixture" ).on( "click", "#ap", function() {
main++;
} );
jQuery( "#ap" ).trigger( "click" ); jQuery( "#ap" ).trigger( "click" );
assert.equal( main, 1, "Verify that the trigger happened correctly." ); assert.equal( main, 1, "Verify that the trigger happened correctly." );
@ -766,7 +772,7 @@ QUnit.test( "on()/trigger()/off() on plain object", function( assert ) {
events = jQuery._data( obj, "events" ); events = jQuery._data( obj, "events" );
assert.ok( events, "Object has events bound." ); assert.ok( events, "Object has events bound." );
assert.equal( obj[ "events" ], undefined, "Events object on plain objects is not events" ); assert.equal( obj.events, undefined, "Events object on plain objects is not events" );
assert.equal( obj.test, undefined, "Make sure that test event is not on the plain object." ); assert.equal( obj.test, undefined, "Make sure that test event is not on the plain object." );
assert.equal( obj.handle, undefined, "Make sure that the event handler is not on the plain object." ); assert.equal( obj.handle, undefined, "Make sure that the event handler is not on the plain object." );
@ -785,7 +791,7 @@ QUnit.test( "on()/trigger()/off() on plain object", function( assert ) {
assert.equal( obj && obj[ jQuery.expando ] && assert.equal( obj && obj[ jQuery.expando ] &&
obj[ jQuery.expando ][ jQuery.expando ] && obj[ jQuery.expando ][ jQuery.expando ] &&
obj[ jQuery.expando ][ jQuery.expando ][ "events" ], undefined, "Make sure events object is removed" ); obj[ jQuery.expando ][ jQuery.expando ].events, undefined, "Make sure events object is removed" );
} ); } );
QUnit.test( "off(type)", function( assert ) { QUnit.test( "off(type)", function( assert ) {
@ -938,12 +944,26 @@ QUnit.test( "trigger() bubbling", function( assert ) {
var win = 0, doc = 0, html = 0, body = 0, main = 0, ap = 0; var win = 0, doc = 0, html = 0, body = 0, main = 0, ap = 0;
jQuery( window ).on( "click", function() { win++; } ); jQuery( window ).on( "click", function() {
jQuery( document ).on( "click", function( e ) { if ( e.target !== document ) { doc++; } } ); win++;
jQuery( "html" ).on( "click", function() { html++; } ); } );
jQuery( "body" ).on( "click", function() { body++; } ); jQuery( document ).on( "click", function( e ) {
jQuery( "#qunit-fixture" ).on( "click", function() { main++; } ); if ( e.target !== document ) {
jQuery( "#ap" ).on( "click", function() { ap++; return false; } ); doc++;
}
} );
jQuery( "html" ).on( "click", function() {
html++;
} );
jQuery( "body" ).on( "click", function() {
body++;
} );
jQuery( "#qunit-fixture" ).on( "click", function() {
main++;
} );
jQuery( "#ap" ).on( "click", function() {
ap++; return false;
} );
jQuery( "html" ).trigger( "click" ); jQuery( "html" ).trigger( "click" );
assert.equal( win, 1, "HTML bubble" ); assert.equal( win, 1, "HTML bubble" );
@ -1159,7 +1179,9 @@ QUnit.test( "trigger(eventObject, [data], [fn])", function( assert ) {
event.stopPropagation(); event.stopPropagation();
assert.equal( event.isPropagationStopped(), true, "Verify isPropagationStopped" ); assert.equal( event.isPropagationStopped(), true, "Verify isPropagationStopped" );
event.isPropagationStopped = function() { return false; }; event.isPropagationStopped = function() {
return false;
};
event.stopImmediatePropagation(); event.stopImmediatePropagation();
assert.equal( event.isPropagationStopped(), true, "Verify isPropagationStopped" ); assert.equal( event.isPropagationStopped(), true, "Verify isPropagationStopped" );
assert.equal( event.isImmediatePropagationStopped(), true, "Verify isPropagationStopped" ); assert.equal( event.isImmediatePropagationStopped(), true, "Verify isPropagationStopped" );
@ -1394,7 +1416,9 @@ QUnit.test( "Submit event can be stopped (trac-11049)", function( assert ) {
return false; return false;
} ) } )
.find( "#myform input[type=submit]" ) .find( "#myform input[type=submit]" )
.each( function() { this.click(); } ) .each( function() {
this.click();
} )
.end() .end()
.on( "submit", function() { .on( "submit", function() {
assert.ok( false, "submit bubbled on second handler" ); assert.ok( false, "submit bubbled on second handler" );
@ -1506,10 +1530,18 @@ QUnit.test( ".on()/.off()", function( assert ) {
var event, clicked, hash, called, livec, lived, livee, var event, clicked, hash, called, livec, lived, livee,
submit = 0, div = 0, livea = 0, liveb = 0; submit = 0, div = 0, livea = 0, liveb = 0;
jQuery( "#body" ).on( "submit", "#qunit-fixture div", function() { submit++; return false; } ); jQuery( "#body" ).on( "submit", "#qunit-fixture div", function() {
jQuery( "#body" ).on( "click", "#qunit-fixture div", function() { div++; } ); submit++; return false;
jQuery( "#body" ).on( "click", "div#nothiddendiv", function() { livea++; } ); } );
jQuery( "#body" ).on( "click", "div#nothiddendivchild", function() { liveb++; } ); jQuery( "#body" ).on( "click", "#qunit-fixture div", function() {
div++;
} );
jQuery( "#body" ).on( "click", "div#nothiddendiv", function() {
livea++;
} );
jQuery( "#body" ).on( "click", "div#nothiddendivchild", function() {
liveb++;
} );
// Nothing should trigger on the body // Nothing should trigger on the body
jQuery( "body" ).trigger( "click" ); jQuery( "body" ).trigger( "click" );
@ -1569,7 +1601,9 @@ QUnit.test( ".on()/.off()", function( assert ) {
// Make sure that stopPropagation doesn't stop live events // Make sure that stopPropagation doesn't stop live events
submit = 0; div = 0; livea = 0; liveb = 0; submit = 0; div = 0; livea = 0; liveb = 0;
jQuery( "#body" ).on( "click", "div#nothiddendivchild", function( e ) { liveb++; e.stopPropagation(); } ); jQuery( "#body" ).on( "click", "div#nothiddendivchild", function( e ) {
liveb++; e.stopPropagation();
} );
jQuery( "div#nothiddendivchild" ).trigger( "click" ); jQuery( "div#nothiddendivchild" ).trigger( "click" );
assert.equal( submit, 0, "stopPropagation Click on inner div" ); assert.equal( submit, 0, "stopPropagation Click on inner div" );
assert.equal( div, 1, "stopPropagation Click on inner div" ); assert.equal( div, 1, "stopPropagation Click on inner div" );
@ -1591,7 +1625,9 @@ QUnit.test( ".on()/.off()", function( assert ) {
// Test binding with a different context // Test binding with a different context
clicked = 0; clicked = 0;
jQuery( "#qunit-fixture" ).on( "click", "#foo", function() { clicked++; } ); jQuery( "#qunit-fixture" ).on( "click", "#foo", function() {
clicked++;
} );
jQuery( "#qunit-fixture div" ).trigger( "click" ); jQuery( "#qunit-fixture div" ).trigger( "click" );
jQuery( "#foo" ).trigger( "click" ); jQuery( "#foo" ).trigger( "click" );
jQuery( "#qunit-fixture" ).trigger( "click" ); jQuery( "#qunit-fixture" ).trigger( "click" );
@ -1635,14 +1671,18 @@ QUnit.test( ".on()/.off()", function( assert ) {
jQuery( "#body" ).off( "click", "#foo" ); jQuery( "#body" ).off( "click", "#foo" );
// Verify that return false prevents default action // Verify that return false prevents default action
jQuery( "#body" ).on( "click", "#anchor2", function() { return false; } ); jQuery( "#body" ).on( "click", "#anchor2", function() {
return false;
} );
hash = window.location.hash; hash = window.location.hash;
jQuery( "#anchor2" ).trigger( "click" ); jQuery( "#anchor2" ).trigger( "click" );
assert.equal( window.location.hash, hash, "return false worked" ); assert.equal( window.location.hash, hash, "return false worked" );
jQuery( "#body" ).off( "click", "#anchor2" ); jQuery( "#body" ).off( "click", "#anchor2" );
// Verify that .preventDefault() prevents default action // Verify that .preventDefault() prevents default action
jQuery( "#body" ).on( "click", "#anchor2", function( e ) { e.preventDefault(); } ); jQuery( "#body" ).on( "click", "#anchor2", function( e ) {
e.preventDefault();
} );
hash = window.location.hash; hash = window.location.hash;
jQuery( "#anchor2" ).trigger( "click" ); jQuery( "#anchor2" ).trigger( "click" );
assert.equal( window.location.hash, hash, "e.preventDefault() worked" ); assert.equal( window.location.hash, hash, "e.preventDefault() worked" );
@ -1650,7 +1690,9 @@ QUnit.test( ".on()/.off()", function( assert ) {
// Test binding the same handler to multiple points // Test binding the same handler to multiple points
called = 0; called = 0;
function callback() { called++; return false; } function callback() {
called++; return false;
}
jQuery( "#body" ).on( "click", "#nothiddendiv", callback ); jQuery( "#body" ).on( "click", "#nothiddendiv", callback );
jQuery( "#body" ).on( "click", "#anchor2", callback ); jQuery( "#body" ).on( "click", "#anchor2", callback );
@ -1696,8 +1738,14 @@ QUnit.test( ".on()/.off()", function( assert ) {
livec = 0; livec = 0;
jQuery( "#nothiddendivchild" ).html( "<span></span>" ); jQuery( "#nothiddendivchild" ).html( "<span></span>" );
jQuery( "#body" ).on( "click", "#nothiddendivchild", function() { jQuery( "#nothiddendivchild" ).html( "" ); } ); jQuery( "#body" ).on( "click", "#nothiddendivchild", function() {
jQuery( "#body" ).on( "click", "#nothiddendivchild", function( e ) { if ( e.target ) {livec++;} } ); jQuery( "#nothiddendivchild" ).html( "" );
} );
jQuery( "#body" ).on( "click", "#nothiddendivchild", function( e ) {
if ( e.target ) {
livec++;
}
} );
jQuery( "#nothiddendiv span" ).trigger( "click" ); jQuery( "#nothiddendiv span" ).trigger( "click" );
assert.equal( jQuery( "#nothiddendiv span" ).length, 0, "Verify that first handler occurred and modified the DOM." ); assert.equal( jQuery( "#nothiddendiv span" ).length, 0, "Verify that first handler occurred and modified the DOM." );
@ -1712,16 +1760,24 @@ QUnit.test( ".on()/.off()", function( assert ) {
livee = 0; livee = 0;
// bind one pair in one order // bind one pair in one order
jQuery( "#body" ).on( "click", "span#liveSpan1 a", function() { lived++; return false; } ); jQuery( "#body" ).on( "click", "span#liveSpan1 a", function() {
jQuery( "#body" ).on( "click", "span#liveSpan1", function() { livee++; } ); lived++; return false;
} );
jQuery( "#body" ).on( "click", "span#liveSpan1", function() {
livee++;
} );
jQuery( "span#liveSpan1 a" ).trigger( "click" ); jQuery( "span#liveSpan1 a" ).trigger( "click" );
assert.equal( lived, 1, "Verify that only one first handler occurred." ); assert.equal( lived, 1, "Verify that only one first handler occurred." );
assert.equal( livee, 0, "Verify that second handler doesn't." ); assert.equal( livee, 0, "Verify that second handler doesn't." );
// and one pair in inverse // and one pair in inverse
jQuery( "#body" ).on( "click", "span#liveSpan2", function() { livee++; } ); jQuery( "#body" ).on( "click", "span#liveSpan2", function() {
jQuery( "#body" ).on( "click", "span#liveSpan2 a", function() { lived++; return false; } ); livee++;
} );
jQuery( "#body" ).on( "click", "span#liveSpan2 a", function() {
lived++; return false;
} );
lived = 0; lived = 0;
livee = 0; livee = 0;
@ -1747,11 +1803,17 @@ QUnit.test( ".on()/.off()", function( assert ) {
// Work with deep selectors // Work with deep selectors
livee = 0; livee = 0;
function clickB() { livee++; } function clickB() {
livee++;
}
jQuery( "#body" ).on( "click", "#nothiddendiv div", function() { livee++; } ); jQuery( "#body" ).on( "click", "#nothiddendiv div", function() {
livee++;
} );
jQuery( "#body" ).on( "click", "#nothiddendiv div", clickB ); jQuery( "#body" ).on( "click", "#nothiddendiv div", clickB );
jQuery( "#body" ).on( "mouseover", "#nothiddendiv div", function() { livee++; } ); jQuery( "#body" ).on( "mouseover", "#nothiddendiv div", function() {
livee++;
} );
assert.equal( livee, 0, "No clicks, deep selector." ); assert.equal( livee, 0, "No clicks, deep selector." );
@ -1825,6 +1887,7 @@ QUnit.test( "events with type matching an Object.prototype property, cloned elem
elem.appendTo( "#qunit-fixture" ); elem.appendTo( "#qunit-fixture" );
try { try {
// Make sure the original element has some event data. // Make sure the original element has some event data.
elem.on( "click", function() {} ); elem.on( "click", function() {} );
@ -1859,6 +1922,7 @@ QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "delegated event with delegate
.off( "click" ); .off( "click" );
if ( QUnit.jQuerySelectorsPos ) { if ( QUnit.jQuerySelectorsPos ) {
// Positional selector (trac-11315) // Positional selector (trac-11315)
markup.find( "ul" ).eq( 0 ) markup.find( "ul" ).eq( 0 )
.on( "click", ">li>a", function() { .on( "click", ">li>a", function() {
@ -1954,8 +2018,12 @@ QUnit.test( "off all bound delegated events", function( assert ) {
clicks = 0, clicks = 0,
div = jQuery( "#body" ); div = jQuery( "#body" );
div.on( "click submit", "div#nothiddendivchild", function() { count++; } ); div.on( "click submit", "div#nothiddendivchild", function() {
div.on( "click", function() { clicks++; } ); count++;
} );
div.on( "click", function() {
clicks++;
} );
div.off( undefined, "**" ); div.off( undefined, "**" );
jQuery( "div#nothiddendivchild" ).trigger( "click" ); jQuery( "div#nothiddendivchild" ).trigger( "click" );
@ -1974,7 +2042,9 @@ QUnit.test( "on with multiple delegated events", function( assert ) {
var count = 0, var count = 0,
div = jQuery( "#body" ); div = jQuery( "#body" );
div.on( "click submit", "div#nothiddendivchild", function() { count++; } ); div.on( "click submit", "div#nothiddendivchild", function() {
count++;
} );
jQuery( "div#nothiddendivchild" ).trigger( "click" ); jQuery( "div#nothiddendivchild" ).trigger( "click" );
jQuery( "div#nothiddendivchild" ).trigger( "submit" ); jQuery( "div#nothiddendivchild" ).trigger( "submit" );
@ -2329,7 +2399,7 @@ QUnit.test( ".on and .off", function( assert ) {
// We should have removed all the event handlers ... kinda hacky way to check this // We should have removed all the event handlers ... kinda hacky way to check this
data = jQuery.data[ jQuery( "#onandoff" )[ 0 ].expando ] || {}; data = jQuery.data[ jQuery( "#onandoff" )[ 0 ].expando ] || {};
assert.equal( data[ "events" ], undefined, "no events left" ); assert.equal( data.events, undefined, "no events left" );
$onandoff.remove(); $onandoff.remove();
} ); } );
@ -2403,7 +2473,7 @@ QUnit.test( "special on name mapping", function( assert ) {
.trigger( "gutfeeling" ) // This one should not .trigger( "gutfeeling" ) // This one should not
.remove(); .remove();
delete jQuery.event.special[ "gutfeeling" ]; delete jQuery.event.special.gutfeeling;
} ); } );
QUnit.test( ".on and .off, selective mixed removal (trac-10705)", function( assert ) { QUnit.test( ".on and .off, selective mixed removal (trac-10705)", function( assert ) {
@ -2544,7 +2614,9 @@ QUnit.test( "addProp extensions", function( assert ) {
fireNative( $fixture[ 0 ], "click" ); fireNative( $fixture[ 0 ], "click" );
$fixture.off( "click" ); $fixture.off( "click" );
jQuery.event.addProp( "testProperty", function() { return 42; } ); jQuery.event.addProp( "testProperty", function() {
return 42;
} );
// Trigger a native click and ensure the property is set // Trigger a native click and ensure the property is set
$fixture.on( "click", function( event ) { $fixture.on( "click", function( event ) {
@ -3362,6 +3434,7 @@ QUnit.test( "focus change during a focus handler (gh-4382)", function( assert )
} ); } );
jQuery( document ).on( "focusin.focusTests", function( ev ) { jQuery( document ).on( "focusin.focusTests", function( ev ) {
// Support: IE 11+ // Support: IE 11+
// In IE focus is async so focusin on document is fired multiple times, // In IE focus is async so focusin on document is fired multiple times,
// for each of the elements. In other browsers it's fired just once, for // for each of the elements. In other browsers it's fired just once, for

View File

@ -518,6 +518,7 @@ QUnit.test( "Tag name processing respects the HTML Standard (gh-2005)", function
} }
function assertSpecialCharsSupport( method, characters ) { function assertSpecialCharsSupport( method, characters ) {
// Support: Android 4.4 only // Support: Android 4.4 only
// Chromium < 35 incorrectly upper-cases µ; Android 4.4 uses such a version by default // Chromium < 35 incorrectly upper-cases µ; Android 4.4 uses such a version by default
// (and its WebView, being un-updatable, will use it for eternity) so we need to blacklist // (and its WebView, being un-updatable, will use it for eternity) so we need to blacklist
@ -1364,9 +1365,13 @@ QUnit.test( "Empty replaceWith (trac-13401; trac-13596; gh-2204)", function( ass
jQuery.each( tests, function( label, input ) { jQuery.each( tests, function( label, input ) {
$el.html( "<a></a>" ).children().replaceWith( input ); $el.html( "<a></a>" ).children().replaceWith( input );
assert.strictEqual( $el.html(), "", "replaceWith(" + label + ")" ); assert.strictEqual( $el.html(), "", "replaceWith(" + label + ")" );
$el.html( "<b></b>" ).children().replaceWith( function() { return input; } ); $el.html( "<b></b>" ).children().replaceWith( function() {
return input;
} );
assert.strictEqual( $el.html(), "", "replaceWith(function returning " + label + ")" ); assert.strictEqual( $el.html(), "", "replaceWith(function returning " + label + ")" );
$el.html( "<i></i>" ).children().replaceWith( function( i ) { return input; } ); $el.html( "<i></i>" ).children().replaceWith( function( i ) {
return input;
} );
assert.strictEqual( $el.html(), "", "replaceWith(other function returning " + label + ")" ); assert.strictEqual( $el.html(), "", "replaceWith(other function returning " + label + ")" );
$el.html( "<p></p>" ).children().replaceWith( function( i ) { $el.html( "<p></p>" ).children().replaceWith( function( i ) {
return i ? return i ?
@ -1606,7 +1611,9 @@ QUnit.test( "clone(form element) (Bug trac-3879, trac-6655)", function( assert )
element = jQuery( "<select><option>Foo</option><option value='selected' selected>Bar</option></select>" ); element = jQuery( "<select><option>Foo</option><option value='selected' selected>Bar</option></select>" );
assert.equal( element.clone().find( "option" ).filter( function() { return this.selected; } ).val(), "selected", "Selected option cloned correctly" ); assert.equal( element.clone().find( "option" ).filter( function() {
return this.selected;
} ).val(), "selected", "Selected option cloned correctly" );
element = jQuery( "<input type='checkbox' value='foo'>" ).attr( "checked", "checked" ); element = jQuery( "<input type='checkbox' value='foo'>" ).attr( "checked", "checked" );
clone = element.clone(); clone = element.clone();
@ -1805,6 +1812,7 @@ QUnit.test( "html(Function)", function( assert ) {
} ); } );
QUnit[ QUnit[
// Support: Edge 16-18+ // Support: Edge 16-18+
// Edge sometimes doesn't execute module scripts so skip the test there. // Edge sometimes doesn't execute module scripts so skip the test there.
( QUnit.moduleTypeSupported && !/edge\//i.test( navigator.userAgent ) ) ? ( QUnit.moduleTypeSupported && !/edge\//i.test( navigator.userAgent ) ) ?
@ -1833,6 +1841,7 @@ QUnit[
} ); } );
QUnit[ QUnit[
// Support: IE 9-11 only, Android 4.0-4.4 only, iOS 7-10 only // Support: IE 9-11 only, Android 4.0-4.4 only, iOS 7-10 only
// `nomodule` scripts should be executed by legacy browsers only. // `nomodule` scripts should be executed by legacy browsers only.
// iOS 10 supports `<script type="module">` but doesn't support the nomodule attribute // iOS 10 supports `<script type="module">` but doesn't support the nomodule attribute
@ -2266,8 +2275,7 @@ QUnit.test( "domManip plain-text caching (trac-6779)", function( assert ) {
for ( i = 0; i < bad.length; i++ ) { for ( i = 0; i < bad.length; i++ ) {
try { try {
$f.append( bad[ i ] ); $f.append( bad[ i ] );
} } catch ( e ) {}
catch ( e ) {}
} }
assert.equal( $f.text(), bad.join( "" ), "Cached strings that match Object properties" ); assert.equal( $f.text(), bad.join( "" ), "Cached strings that match Object properties" );
$f.remove(); $f.remove();

View File

@ -171,9 +171,9 @@ testIframe( "absolute", "offset/absolute.html", function( assert, $ ) {
// get offset tests // get offset tests
tests = [ tests = [
{ "id": "#absolute-1", "top": 1, "left": 1 }, { "id": "#absolute-1", "top": 1, "left": 1 },
{ "id": "#absolute-1-1", "top": 5, "left": 5 }, { "id": "#absolute-1-1", "top": 5, "left": 5 },
{ "id": "#absolute-1-1-1", "top": 9, "left": 9 }, { "id": "#absolute-1-1-1", "top": 9, "left": 9 },
{ "id": "#absolute-2", "top": 20, "left": 20 } { "id": "#absolute-2", "top": 20, "left": 20 }
]; ];
jQuery.each( tests, function() { jQuery.each( tests, function() {
@ -183,9 +183,9 @@ testIframe( "absolute", "offset/absolute.html", function( assert, $ ) {
// get position // get position
tests = [ tests = [
{ "id": "#absolute-1", "top": 0, "left": 0 }, { "id": "#absolute-1", "top": 0, "left": 0 },
{ "id": "#absolute-1-1", "top": 1, "left": 1 }, { "id": "#absolute-1-1", "top": 1, "left": 1 },
{ "id": "#absolute-1-1-1", "top": 1, "left": 1 }, { "id": "#absolute-1-1-1", "top": 1, "left": 1 },
{ "id": "#absolute-2", "top": 19, "left": 19 } { "id": "#absolute-2", "top": 19, "left": 19 }
]; ];
jQuery.each( tests, function() { jQuery.each( tests, function() {
@ -205,17 +205,17 @@ testIframe( "absolute", "offset/absolute.html", function( assert, $ ) {
{ "id": "#absolute-2", "top": -1, "left": -1 }, { "id": "#absolute-2", "top": -1, "left": -1 },
{ "id": "#absolute-2", "top": 19, "left": 19 }, { "id": "#absolute-2", "top": 19, "left": 19 },
{ "id": "#absolute-1-1-1", "top": 15, "left": 15 }, { "id": "#absolute-1-1-1", "top": 15, "left": 15 },
{ "id": "#absolute-1-1-1", "top": 5, "left": 5 }, { "id": "#absolute-1-1-1", "top": 5, "left": 5 },
{ "id": "#absolute-1-1-1", "top": -1, "left": -1 }, { "id": "#absolute-1-1-1", "top": -1, "left": -1 },
{ "id": "#absolute-1-1-1", "top": 9, "left": 9 }, { "id": "#absolute-1-1-1", "top": 9, "left": 9 },
{ "id": "#absolute-1-1", "top": 10, "left": 10 }, { "id": "#absolute-1-1", "top": 10, "left": 10 },
{ "id": "#absolute-1-1", "top": 0, "left": 0 }, { "id": "#absolute-1-1", "top": 0, "left": 0 },
{ "id": "#absolute-1-1", "top": -1, "left": -1 }, { "id": "#absolute-1-1", "top": -1, "left": -1 },
{ "id": "#absolute-1-1", "top": 5, "left": 5 }, { "id": "#absolute-1-1", "top": 5, "left": 5 },
{ "id": "#absolute-1", "top": 2, "left": 2 }, { "id": "#absolute-1", "top": 2, "left": 2 },
{ "id": "#absolute-1", "top": 0, "left": 0 }, { "id": "#absolute-1", "top": 0, "left": 0 },
{ "id": "#absolute-1", "top": -1, "left": -1 }, { "id": "#absolute-1", "top": -1, "left": -1 },
{ "id": "#absolute-1", "top": 1, "left": 1 } { "id": "#absolute-1", "top": 1, "left": 1 }
]; ];
jQuery.each( tests, function() { jQuery.each( tests, function() {
$( this.id ).offset( { "top": this.top, "left": this.left } ); $( this.id ).offset( { "top": this.top, "left": this.left } );
@ -234,13 +234,13 @@ testIframe( "absolute", "offset/absolute.html", function( assert, $ ) {
$( this.id ) $( this.id )
.offset( { "left": this.left + 2 } ) .offset( { "left": this.left + 2 } )
.offset( { "top": this.top + 2 } ); .offset( { "top": this.top + 2 } );
assert.equal( $( this.id ).offset().top, this.top + 2, "Setting one property at a time." ); assert.equal( $( this.id ).offset().top, this.top + 2, "Setting one property at a time." );
assert.equal( $( this.id ).offset().left, this.left + 2, "Setting one property at a time." ); assert.equal( $( this.id ).offset().left, this.left + 2, "Setting one property at a time." );
$( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) { $( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) {
$( this ).css( { $( this ).css( {
"top": props.top + 1, "top": props.top + 1,
"left": props.left + 1 "left": props.left + 1
} ); } );
} } ); } } );
@ -254,8 +254,8 @@ testIframe( "relative", "offset/relative.html", function( assert, $ ) {
// get offset // get offset
var tests = [ var tests = [
{ "id": "#relative-1", "top": 7, "left": 7 }, { "id": "#relative-1", "top": 7, "left": 7 },
{ "id": "#relative-1-1", "top": 15, "left": 15 }, { "id": "#relative-1-1", "top": 15, "left": 15 },
{ "id": "#relative-2", "top": 142, "left": 27 }, { "id": "#relative-2", "top": 142, "left": 27 },
{ "id": "#relative-2-1", "top": 149, "left": 52 } { "id": "#relative-2-1", "top": 149, "left": 52 }
]; ];
@ -266,8 +266,8 @@ testIframe( "relative", "offset/relative.html", function( assert, $ ) {
// get position // get position
tests = [ tests = [
{ "id": "#relative-1", "top": 6, "left": 6 }, { "id": "#relative-1", "top": 6, "left": 6 },
{ "id": "#relative-1-1", "top": 5, "left": 5 }, { "id": "#relative-1-1", "top": 5, "left": 5 },
{ "id": "#relative-2", "top": 141, "left": 26 }, { "id": "#relative-2", "top": 141, "left": 26 },
{ "id": "#relative-2-1", "top": 5, "left": 5 } { "id": "#relative-2-1", "top": 5, "left": 5 }
]; ];
@ -278,18 +278,18 @@ testIframe( "relative", "offset/relative.html", function( assert, $ ) {
// set offset // set offset
tests = [ tests = [
{ "id": "#relative-2", "top": 200, "left": 50 }, { "id": "#relative-2", "top": 200, "left": 50 },
{ "id": "#relative-2", "top": 100, "left": 10 }, { "id": "#relative-2", "top": 100, "left": 10 },
{ "id": "#relative-2", "top": -5, "left": -5 }, { "id": "#relative-2", "top": -5, "left": -5 },
{ "id": "#relative-2", "top": 142, "left": 27 }, { "id": "#relative-2", "top": 142, "left": 27 },
{ "id": "#relative-1-1", "top": 100, "left": 100 }, { "id": "#relative-1-1", "top": 100, "left": 100 },
{ "id": "#relative-1-1", "top": 5, "left": 5 }, { "id": "#relative-1-1", "top": 5, "left": 5 },
{ "id": "#relative-1-1", "top": -1, "left": -1 }, { "id": "#relative-1-1", "top": -1, "left": -1 },
{ "id": "#relative-1-1", "top": 15, "left": 15 }, { "id": "#relative-1-1", "top": 15, "left": 15 },
{ "id": "#relative-1", "top": 100, "left": 100 }, { "id": "#relative-1", "top": 100, "left": 100 },
{ "id": "#relative-1", "top": 0, "left": 0 }, { "id": "#relative-1", "top": 0, "left": 0 },
{ "id": "#relative-1", "top": -1, "left": -1 }, { "id": "#relative-1", "top": -1, "left": -1 },
{ "id": "#relative-1", "top": 7, "left": 7 } { "id": "#relative-1", "top": 7, "left": 7 }
]; ];
jQuery.each( tests, function() { jQuery.each( tests, function() {
$( this.id ).offset( { "top": this.top, "left": this.left } ); $( this.id ).offset( { "top": this.top, "left": this.left } );
@ -298,7 +298,7 @@ testIframe( "relative", "offset/relative.html", function( assert, $ ) {
$( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) { $( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) {
$( this ).css( { $( this ).css( {
"top": props.top + 1, "top": props.top + 1,
"left": props.left + 1 "left": props.left + 1
} ); } );
} } ); } } );
@ -312,9 +312,9 @@ testIframe( "static", "offset/static.html", function( assert, $ ) {
// get offset // get offset
var tests = [ var tests = [
{ "id": "#static-1", "top": 7, "left": 7 }, { "id": "#static-1", "top": 7, "left": 7 },
{ "id": "#static-1-1", "top": 15, "left": 15 }, { "id": "#static-1-1", "top": 15, "left": 15 },
{ "id": "#static-1-1-1", "top": 23, "left": 23 }, { "id": "#static-1-1-1", "top": 23, "left": 23 },
{ "id": "#static-2", "top": 122, left: 7 } { "id": "#static-2", "top": 122, left: 7 }
]; ];
jQuery.each( tests, function() { jQuery.each( tests, function() {
@ -324,9 +324,9 @@ testIframe( "static", "offset/static.html", function( assert, $ ) {
// get position // get position
tests = [ tests = [
{ "id": "#static-1", "top": 6, "left": 6 }, { "id": "#static-1", "top": 6, "left": 6 },
{ "id": "#static-1-1", "top": 14, "left": 14 }, { "id": "#static-1-1", "top": 14, "left": 14 },
{ "id": "#static-1-1-1", "top": 22, "left": 22 }, { "id": "#static-1-1-1", "top": 22, "left": 22 },
{ "id": "#static-2", "top": 121, "left": 6 } { "id": "#static-2", "top": 121, "left": 6 }
]; ];
jQuery.each( tests, function() { jQuery.each( tests, function() {
@ -338,20 +338,20 @@ testIframe( "static", "offset/static.html", function( assert, $ ) {
tests = [ tests = [
{ "id": "#static-2", "top": 200, "left": 200 }, { "id": "#static-2", "top": 200, "left": 200 },
{ "id": "#static-2", "top": 100, "left": 100 }, { "id": "#static-2", "top": 100, "left": 100 },
{ "id": "#static-2", "top": -2, "left": -2 }, { "id": "#static-2", "top": -2, "left": -2 },
{ "id": "#static-2", "top": 121, "left": 6 }, { "id": "#static-2", "top": 121, "left": 6 },
{ "id": "#static-1-1-1", "top": 50, "left": 50 }, { "id": "#static-1-1-1", "top": 50, "left": 50 },
{ "id": "#static-1-1-1", "top": 10, "left": 10 }, { "id": "#static-1-1-1", "top": 10, "left": 10 },
{ "id": "#static-1-1-1", "top": -1, "left": -1 }, { "id": "#static-1-1-1", "top": -1, "left": -1 },
{ "id": "#static-1-1-1", "top": 22, "left": 22 }, { "id": "#static-1-1-1", "top": 22, "left": 22 },
{ "id": "#static-1-1", "top": 25, "left": 25 }, { "id": "#static-1-1", "top": 25, "left": 25 },
{ "id": "#static-1-1", "top": 10, "left": 10 }, { "id": "#static-1-1", "top": 10, "left": 10 },
{ "id": "#static-1-1", "top": -3, "left": -3 }, { "id": "#static-1-1", "top": -3, "left": -3 },
{ "id": "#static-1-1", "top": 14, "left": 14 }, { "id": "#static-1-1", "top": 14, "left": 14 },
{ "id": "#static-1", "top": 30, "left": 30 }, { "id": "#static-1", "top": 30, "left": 30 },
{ "id": "#static-1", "top": 2, "left": 2 }, { "id": "#static-1", "top": 2, "left": 2 },
{ "id": "#static-1", "top": -2, "left": -2 }, { "id": "#static-1", "top": -2, "left": -2 },
{ "id": "#static-1", "top": 7, "left": 7 } { "id": "#static-1", "top": 7, "left": 7 }
]; ];
jQuery.each( tests, function() { jQuery.each( tests, function() {
$( this.id ).offset( { "top": this.top, "left": this.left } ); $( this.id ).offset( { "top": this.top, "left": this.left } );
@ -360,7 +360,7 @@ testIframe( "static", "offset/static.html", function( assert, $ ) {
$( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) { $( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) {
$( this ).css( { $( this ).css( {
"top": props.top + 1, "top": props.top + 1,
"left": props.left + 1 "left": props.left + 1
} ); } );
} } ); } } );
@ -421,11 +421,11 @@ testIframe( "fixed", "offset/fixed.html", function( assert, $, window ) {
tests = [ tests = [
{ "id": "#fixed-1", "top": 100, "left": 100 }, { "id": "#fixed-1", "top": 100, "left": 100 },
{ "id": "#fixed-1", "top": 0, "left": 0 }, { "id": "#fixed-1", "top": 0, "left": 0 },
{ "id": "#fixed-1", "top": -4, "left": -4 }, { "id": "#fixed-1", "top": -4, "left": -4 },
{ "id": "#fixed-2", "top": 200, "left": 200 }, { "id": "#fixed-2", "top": 200, "left": 200 },
{ "id": "#fixed-2", "top": 0, "left": 0 }, { "id": "#fixed-2", "top": 0, "left": 0 },
{ "id": "#fixed-2", "top": -5, "left": -5 } { "id": "#fixed-2", "top": -5, "left": -5 }
]; ];
jQuery.each( tests, function() { jQuery.each( tests, function() {
@ -436,7 +436,7 @@ testIframe( "fixed", "offset/fixed.html", function( assert, $, window ) {
$( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) { $( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) {
$( this ).css( { $( this ).css( {
"top": props.top + 1, "top": props.top + 1,
"left": props.left + 1 "left": props.left + 1
} ); } );
} } ); } } );
@ -546,7 +546,7 @@ testIframe( "body", "offset/body.html", function( assert, $ ) {
QUnit.test( "chaining", function( assert ) { QUnit.test( "chaining", function( assert ) {
assert.expect( 3 ); assert.expect( 3 );
var coords = { "top": 1, "left": 1 }; var coords = { "top": 1, "left": 1 };
assert.equal( jQuery( "#absolute-1" ).offset( coords ).jquery, jQuery.fn.jquery, "offset(coords) returns jQuery object" ); assert.equal( jQuery( "#absolute-1" ).offset( coords ).jquery, jQuery.fn.jquery, "offset(coords) returns jQuery object" );
assert.equal( jQuery( "#non-existent" ).offset( coords ).jquery, jQuery.fn.jquery, "offset(coords) with empty jQuery set returns jQuery object" ); assert.equal( jQuery( "#non-existent" ).offset( coords ).jquery, jQuery.fn.jquery, "offset(coords) with empty jQuery set returns jQuery object" );
assert.equal( jQuery( "#absolute-1" ).offset( undefined ).jquery, jQuery.fn.jquery, "offset(undefined) returns jQuery object (trac-5571)" ); assert.equal( jQuery( "#absolute-1" ).offset( undefined ).jquery, jQuery.fn.jquery, "offset(undefined) returns jQuery object (trac-5571)" );
@ -586,17 +586,17 @@ QUnit.test( "chaining", function( assert ) {
// Initialize data about page elements // Initialize data about page elements
var expectations = { var expectations = {
"documentElement": htmlProps( htmlPos ), "documentElement": htmlProps( htmlPos ),
"body": bodyProps( bodyPos ), "body": bodyProps( bodyPos ),
"relative": divProps( "relative", "body" ), "relative": divProps( "relative", "body" ),
"relative-relative": divProps( "relative", "relative" ), "relative-relative": divProps( "relative", "relative" ),
"relative-absolute": divProps( "absolute", "relative" ), "relative-absolute": divProps( "absolute", "relative" ),
"absolute": divProps( "absolute", "body" ), "absolute": divProps( "absolute", "body" ),
"absolute-relative": divProps( "relative", "absolute" ), "absolute-relative": divProps( "relative", "absolute" ),
"absolute-absolute": divProps( "absolute", "absolute" ), "absolute-absolute": divProps( "absolute", "absolute" ),
"fixed": divProps( "fixed" ), "fixed": divProps( "fixed" ),
"fixed-relative": divProps( "relative", "fixed" ), "fixed-relative": divProps( "relative", "fixed" ),
"fixed-absolute": divProps( "absolute", "fixed" ) "fixed-absolute": divProps( "absolute", "fixed" )
}; };
// Define position and offset expectations for page elements // Define position and offset expectations for page elements
@ -622,6 +622,7 @@ QUnit.test( "chaining", function( assert ) {
// parent is not offsetParent); offset includes parent offset+border+padding // parent is not offsetParent); offset includes parent offset+border+padding
// static: same as relative // static: same as relative
for ( ; parent; parent = expectations[ parent.parent ] ) { for ( ; parent; parent = expectations[ parent.parent ] ) {
// position:fixed // position:fixed
if ( props.style === "fixed" ) { if ( props.style === "fixed" ) {
break; break;

View File

@ -88,7 +88,9 @@ QUnit.test( "queue() passes in the next item in the queue as a parameter to fx q
div.queue( function( next ) { div.queue( function( next ) {
assert.equal( ++counter, 1, "Dequeueing" ); assert.equal( ++counter, 1, "Dequeueing" );
setTimeout( function() { next(); }, 500 ); setTimeout( function() {
next();
}, 500 );
} ).queue( function( next ) { } ).queue( function( next ) {
assert.equal( ++counter, 2, "Next was called" ); assert.equal( ++counter, 2, "Next was called" );
next(); next();
@ -187,7 +189,9 @@ QUnit.test( "clearQueue() clears the fx queue", function( assert ) {
div.queue( function( next ) { div.queue( function( next ) {
counter++; counter++;
var self = this; var self = this;
setTimeout( function() { jQuery( self ).clearQueue(); next(); }, 50 ); setTimeout( function() {
jQuery( self ).clearQueue(); next();
}, 50 );
} ).queue( function() { } ).queue( function() {
counter++; counter++;
} ); } );

View File

@ -41,8 +41,8 @@ QUnit.test( "empty", function( assert ) {
QUnit.test( "star", function( assert ) { QUnit.test( "star", function( assert ) {
assert.expect( 2 ); assert.expect( 2 );
var good, i; var good, i,
var all = jQuery.find( "*" ); all = jQuery.find( "*" );
assert.ok( all.length >= 30, "Select all" ); assert.ok( all.length >= 30, "Select all" );
good = true; good = true;
@ -57,8 +57,8 @@ QUnit.test( "star", function( assert ) {
QUnit.test( "element", function( assert ) { QUnit.test( "element", function( assert ) {
assert.expect( 37 ); assert.expect( 37 );
var i, lengthtest, siblingTest, html; var i, lengthtest, siblingTest, html,
var fixture = document.getElementById( "qunit-fixture" ); fixture = document.getElementById( "qunit-fixture" );
assert.deepEqual( jQuery( "p", fixture ).get(), q( "firstp", "ap", "sndp", "en", "sap", "first" ), "Finding elements with a Node context." ); assert.deepEqual( jQuery( "p", fixture ).get(), q( "firstp", "ap", "sndp", "en", "sap", "first" ), "Finding elements with a Node context." );
assert.deepEqual( jQuery( "p", "#qunit-fixture" ).get(), q( "firstp", "ap", "sndp", "en", "sap", "first" ), "Finding elements with a selector context." ); assert.deepEqual( jQuery( "p", "#qunit-fixture" ).get(), q( "firstp", "ap", "sndp", "en", "sap", "first" ), "Finding elements with a selector context." );
@ -892,6 +892,7 @@ QUnit.test( "pseudo - nth-child", function( assert ) {
"Seeded nth-child" "Seeded nth-child"
); );
} else { } else {
// Support: Chrome 75+, Firefox 67+ // Support: Chrome 75+, Firefox 67+
// Some browsers mark disconnected elements as matching `:nth-child(n)` // Some browsers mark disconnected elements as matching `:nth-child(n)`
// so let's skip the test. // so let's skip the test.
@ -948,6 +949,7 @@ QUnit.test( "pseudo - nth-last-child", function( assert ) {
"Seeded nth-last-child" "Seeded nth-last-child"
); );
} else { } else {
// Support: Chrome 75+, Firefox 67+ // Support: Chrome 75+, Firefox 67+
// Some browsers mark disconnected elements as matching `:nth-last-child(n)` // Some browsers mark disconnected elements as matching `:nth-last-child(n)`
// so let's skip the test. // so let's skip the test.
@ -1084,6 +1086,7 @@ QUnit.test( "pseudo - misc", function( assert ) {
tmp = document.createElement( "div" ); tmp = document.createElement( "div" );
tmp.id = "tmp_input"; tmp.id = "tmp_input";
tmp.innerHTML = "<span>Hello I am focusable.</span>"; tmp.innerHTML = "<span>Hello I am focusable.</span>";
// Setting tabIndex should make the element focusable // Setting tabIndex should make the element focusable
// http://dev.w3.org/html5/spec/single-page.html#focus-management // http://dev.w3.org/html5/spec/single-page.html#focus-management
document.body.appendChild( tmp ); document.body.appendChild( tmp );
@ -1140,6 +1143,7 @@ QUnit.test( "pseudo - misc", function( assert ) {
); );
if ( QUnit.jQuerySelectors ) { if ( QUnit.jQuerySelectors ) {
// Tokenization edge cases // Tokenization edge cases
assert.t( "Sequential pseudos", "#qunit-fixture p:has(:contains(mark)):has(code)", [ "ap" ] ); assert.t( "Sequential pseudos", "#qunit-fixture p:has(:contains(mark)):has(code)", [ "ap" ] );
assert.t( "Sequential pseudos", "#qunit-fixture p:has(:contains(mark)):has(code):contains(This link)", [ "ap" ] ); assert.t( "Sequential pseudos", "#qunit-fixture p:has(:contains(mark)):has(code):contains(This link)", [ "ap" ] );
@ -1205,6 +1209,7 @@ QUnit.test( "pseudo - :not", function( assert ) {
assert.t( ":not() failing interior", "#qunit-fixture p:not(div#blargh)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] ); assert.t( ":not() failing interior", "#qunit-fixture p:not(div#blargh)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
assert.t( ":not() failing interior", "#qunit-fixture p:not(p#blargh)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] ); assert.t( ":not() failing interior", "#qunit-fixture p:not(p#blargh)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
} else { } else {
// Support: Chrome 75+, Firefox 67+ // Support: Chrome 75+, Firefox 67+
// Chrome/Firefox don't support `:not(complex selector)`. // Chrome/Firefox don't support `:not(complex selector)`.
assert.ok( "skip", ":not(complex selector) not supported in selector-native" ); assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
@ -1225,6 +1230,7 @@ QUnit.test( "pseudo - :not", function( assert ) {
assert.t( ":not Multiple", "p:not(p,a)", [] ); assert.t( ":not Multiple", "p:not(p,a)", [] );
assert.t( ":not Multiple", "p:not(a,p,b)", [] ); assert.t( ":not Multiple", "p:not(a,p,b)", [] );
} else { } else {
// Support: Chrome 75+, Firefox 67+ // Support: Chrome 75+, Firefox 67+
// Chrome/Firefox don't support `:not(complex selector)`. // Chrome/Firefox don't support `:not(complex selector)`.
assert.ok( "skip", ":not(complex selector) not supported in selector-native" ); assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
@ -1254,6 +1260,7 @@ QUnit.test( "pseudo - :not", function( assert ) {
if ( QUnit.jQuerySelectors || this.safari ) { if ( QUnit.jQuerySelectors || this.safari ) {
assert.t( ":not() Multiple Class", "#foo a:not(.blog.link)", [ "yahoo", "anchor2" ] ); assert.t( ":not() Multiple Class", "#foo a:not(.blog.link)", [ "yahoo", "anchor2" ] );
} else { } else {
// Support: Chrome 75+, Firefox 67+ // Support: Chrome 75+, Firefox 67+
// Chrome/Firefox don't support `:not(complex selector)`. // Chrome/Firefox don't support `:not(complex selector)`.
assert.ok( "skip", ":not(complex selector) not supported in selector-native" ); assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
@ -1830,8 +1837,8 @@ QUnit[
"Shadow DOM nodes supported as root", function( assert ) { "Shadow DOM nodes supported as root", function( assert ) {
assert.expect( 2 ); assert.expect( 2 );
var shadowHost = jQuery( "<div/>" ).appendTo( "#qunit-fixture" )[ 0 ]; var shadowHost = jQuery( "<div/>" ).appendTo( "#qunit-fixture" )[ 0 ],
var shadowRoot = shadowHost.attachShadow( { mode: "open" } ); shadowRoot = shadowHost.attachShadow( { mode: "open" } );
shadowRoot.innerHTML = "<div class='vagabond'><p></p></div>"; shadowRoot.innerHTML = "<div class='vagabond'><p></p></div>";
assert.equal( jQuery( shadowRoot ).find( ".vagabond" ).length, 1, assert.equal( jQuery( shadowRoot ).find( ".vagabond" ).length, 1,
@ -1843,7 +1850,7 @@ QUnit[
testIframe( testIframe(
"attributes - jQuery.attr", "attributes - jQuery.attr",
"selector/html5_selector.html", "selector/html5_selector.html",
function( assert, jQuery, window, document ) { function( assert, jQuery, _window, document ) {
assert.expect( 38 ); assert.expect( 38 );
/** /**
@ -1916,7 +1923,7 @@ testIframe(
// Enumerated attributes (these are not boolean content attributes) // Enumerated attributes (these are not boolean content attributes)
jQuery.expandedEach = jQuery.each; jQuery.expandedEach = jQuery.each;
jQuery.expandedEach( [ "draggable", "contenteditable", "aria-disabled" ], function( i, val ) { jQuery.expandedEach( [ "draggable", "contenteditable", "aria-disabled" ], function( _i, val ) {
t( "Enumerated attribute", "[" + val + "]", [ "div1" ] ); t( "Enumerated attribute", "[" + val + "]", [ "div1" ] );
} ); } );
t( "Enumerated attribute", "[spellcheck]", [ "span1" ] ); t( "Enumerated attribute", "[spellcheck]", [ "span1" ] );
@ -2123,7 +2130,7 @@ QUnit.test( "uniqueSort()", function( assert ) {
testIframe( testIframe(
"jQuery.uniqueSort works cross-window (trac-14381)", "jQuery.uniqueSort works cross-window (trac-14381)",
"selector/mixed_sort.html", "selector/mixed_sort.html",
function( assert, jQuery, window, document, actual, expected ) { function( assert, _jQuery, _window, _document, actual, expected ) {
assert.expect( 1 ); assert.expect( 1 );
assert.deepEqual( actual, expected, "Mixed array was sorted correctly" ); assert.deepEqual( actual, expected, "Mixed array was sorted correctly" );
@ -2292,10 +2299,12 @@ function testAttr( doc, assert ) {
var el; var el;
if ( doc ) { if ( doc ) {
// XML // XML
el = doc.createElement( "input" ); el = doc.createElement( "input" );
el.setAttribute( "type", "checkbox" ); el.setAttribute( "type", "checkbox" );
} else { } else {
// Set checked on creation by creating with a fragment // Set checked on creation by creating with a fragment
// See https://jsfiddle.net/8sVgA/1/show/light in oldIE // See https://jsfiddle.net/8sVgA/1/show/light in oldIE
el = jQuery( "<input type='checkbox' checked='checked' />" )[ 0 ]; el = jQuery( "<input type='checkbox' checked='checked' />" )[ 0 ];
@ -2423,6 +2432,7 @@ QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "backwards-compatible custom p
var count = argument == null || argument === "" ? 3 : +argument; var count = argument == null || argument === "" ? 3 : +argument;
return elements.slice( 0, count ); return elements.slice( 0, count );
}; };
// Using TAG as the first token here forces this setMatcher into a fail state // Using TAG as the first token here forces this setMatcher into a fail state
// Where the descendent combinator was lost // Where the descendent combinator was lost
assert.t( "Custom setFilter", "form#form :PODIUM", [ "label-for", "text1", "text2" ] ); assert.t( "Custom setFilter", "form#form :PODIUM", [ "label-for", "text1", "text2" ] );
@ -2550,7 +2560,7 @@ QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "jQuery.find.select with pre-c
"#qunit-fixture #first", "#qunit-fixture #first",
"ol#listWithTabIndex > li[tabindex]", "ol#listWithTabIndex > li[tabindex]",
"#liveSpan1" "#liveSpan1"
], function( i, selector ) { ], function( _i, selector ) {
var compiled = jQuery.find.compile( selector ); var compiled = jQuery.find.compile( selector );
assert.equal( jQuery.find.select( compiled, document ).length, assert.equal( jQuery.find.select( compiled, document ).length,
1, "Should match using a compiled selector function" ); 1, "Should match using a compiled selector function" );

View File

@ -5,10 +5,10 @@ QUnit.test( "jQuery.param()", function( assert ) {
var params; var params;
params = { "foo":"bar", "baz":42, "quux":"All your base are belong to us" }; params = { "foo": "bar", "baz": 42, "quux": "All your base are belong to us" };
assert.equal( jQuery.param( params ), "foo=bar&baz=42&quux=All%20your%20base%20are%20belong%20to%20us", "simple" ); assert.equal( jQuery.param( params ), "foo=bar&baz=42&quux=All%20your%20base%20are%20belong%20to%20us", "simple" );
params = { "string":"foo", "null":null, "undefined":undefined }; params = { "string": "foo", "null": null, "undefined": undefined };
assert.equal( jQuery.param( params ), "string=foo&null=&undefined=", "handle nulls and undefineds properly" ); assert.equal( jQuery.param( params ), "string=foo&null=&undefined=", "handle nulls and undefineds properly" );
params = { "someName": [ 1, 2, 3 ], "regularThing": "blah" }; params = { "someName": [ 1, 2, 3 ], "regularThing": "blah" };
@ -23,13 +23,13 @@ QUnit.test( "jQuery.param()", function( assert ) {
params = { "foo": { "bar": "baz", "beep": 42, "quux": "All your base are belong to us" } }; params = { "foo": { "bar": "baz", "beep": 42, "quux": "All your base are belong to us" } };
assert.equal( jQuery.param( params ), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All%20your%20base%20are%20belong%20to%20us", "even more arrays" ); assert.equal( jQuery.param( params ), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All%20your%20base%20are%20belong%20to%20us", "even more arrays" );
params = { a:[ 1, 2 ], b:{ c:3, d:[ 4, 5 ], e:{ x:[ 6 ], y:7, z:[ 8, 9 ] }, f:true, g:false, h:undefined }, i:[ 10, 11 ], j:true, k:false, l:[ undefined, 0 ], m:"cowboy hat?" }; params = { a: [ 1, 2 ], b: { c: 3, d: [ 4, 5 ], e: { x: [ 6 ], y: 7, z: [ 8, 9 ] }, f: true, g: false, h: undefined }, i: [ 10, 11 ], j: true, k: false, l: [ undefined, 0 ], m: "cowboy hat?" };
assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy hat?", "huge structure" ); assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy hat?", "huge structure" );
params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, "d": 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, "d": 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] };
assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=0&a[1][]=1&a[1][]=2&a[2][]=3&a[2][1][]=4&a[2][1][]=5&a[2][2][]=6&a[3][b][]=7&a[3][b][1][]=8&a[3][b][1][]=9&a[3][b][2][0][c]=10&a[3][b][2][0][d]=11&a[3][b][3][0][]=12&a[3][b][4][0][0][]=13&a[3][b][5][e][f][g][]=14&a[3][b][5][e][f][g][1][]=15&a[3][b][]=16&a[]=17", "nested arrays" ); assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=0&a[1][]=1&a[1][]=2&a[2][]=3&a[2][1][]=4&a[2][1][]=5&a[2][2][]=6&a[3][b][]=7&a[3][b][1][]=8&a[3][b][1][]=9&a[3][b][2][0][c]=10&a[3][b][2][0][d]=11&a[3][b][3][0][]=12&a[3][b][4][0][0][]=13&a[3][b][5][e][f][g][]=14&a[3][b][5][e][f][g][1][]=15&a[3][b][]=16&a[]=17", "nested arrays" );
params = { "a":[ 1, 2 ], "b":{ "c":3, "d":[ 4, 5 ], "e":{ "x":[ 6 ], "y":7, "z":[ 8, 9 ] }, "f":true, "g":false, "h":undefined }, "i":[ 10, 11 ], "j":true, "k":false, "l":[ undefined, 0 ], "m":"cowboy hat?" }; params = { "a": [ 1, 2 ], "b": { "c": 3, "d": [ 4, 5 ], "e": { "x": [ 6 ], "y": 7, "z": [ 8, 9 ] }, "f": true, "g": false, "h": undefined }, "i": [ 10, 11 ], "j": true, "k": false, "l": [ undefined, 0 ], "m": "cowboy hat?" };
assert.equal( jQuery.param( params, true ), "a=1&a=2&b=%5Bobject%20Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy%20hat%3F", "huge structure, forced traditional" ); assert.equal( jQuery.param( params, true ), "a=1&a=2&b=%5Bobject%20Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy%20hat%3F", "huge structure, forced traditional" );
assert.equal( decodeURIComponent( jQuery.param( { "a": [ 1, 2, 3 ], "b[]": [ 4, 5, 6 ], "c[d]": [ 7, 8, 9 ], "e": { "f": [ 10 ], "g": [ 11, 12 ], "h": 13 } } ) ), "a[]=1&a[]=2&a[]=3&b[]=4&b[]=5&b[]=6&c[d][]=7&c[d][]=8&c[d][]=9&e[f][]=10&e[g][]=11&e[g][]=12&e[h]=13", "Make sure params are not double-encoded." ); assert.equal( decodeURIComponent( jQuery.param( { "a": [ 1, 2, 3 ], "b[]": [ 4, 5, 6 ], "c[d]": [ 7, 8, 9 ], "e": { "f": [ 10 ], "g": [ 11, 12 ], "h": 13 } } ) ), "a[]=1&a[]=2&a[]=3&b[]=4&b[]=5&b[]=6&c[d][]=7&c[d][]=8&c[d][]=9&e[f][]=10&e[g][]=11&e[g][]=12&e[h]=13", "Make sure params are not double-encoded." );
@ -37,7 +37,7 @@ QUnit.test( "jQuery.param()", function( assert ) {
// trac-7945 // trac-7945
assert.equal( jQuery.param( { "jquery": "1.4.2" } ), "jquery=1.4.2", "Check that object with a jQuery property get serialized correctly" ); assert.equal( jQuery.param( { "jquery": "1.4.2" } ), "jquery=1.4.2", "Check that object with a jQuery property get serialized correctly" );
params = { "foo":"bar", "baz":42, "quux":"All your base are belong to us" }; params = { "foo": "bar", "baz": 42, "quux": "All your base are belong to us" };
assert.equal( jQuery.param( params, true ), "foo=bar&baz=42&quux=All%20your%20base%20are%20belong%20to%20us", "simple" ); assert.equal( jQuery.param( params, true ), "foo=bar&baz=42&quux=All%20your%20base%20are%20belong%20to%20us", "simple" );
params = { "someName": [ 1, 2, 3 ], "regularThing": "blah" }; params = { "someName": [ 1, 2, 3 ], "regularThing": "blah" };
@ -46,25 +46,27 @@ QUnit.test( "jQuery.param()", function( assert ) {
params = { "foo": [ "a", "b", "c" ] }; params = { "foo": [ "a", "b", "c" ] };
assert.equal( jQuery.param( params, true ), "foo=a&foo=b&foo=c", "with array of strings" ); assert.equal( jQuery.param( params, true ), "foo=a&foo=b&foo=c", "with array of strings" );
params = { "foo[]":[ "baz", 42, "All your base are belong to us" ] }; params = { "foo[]": [ "baz", 42, "All your base are belong to us" ] };
assert.equal( jQuery.param( params, true ), "foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All%20your%20base%20are%20belong%20to%20us", "more array" ); assert.equal( jQuery.param( params, true ), "foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All%20your%20base%20are%20belong%20to%20us", "more array" );
params = { "foo[bar]":"baz", "foo[beep]":42, "foo[quux]":"All your base are belong to us" }; params = { "foo[bar]": "baz", "foo[beep]": 42, "foo[quux]": "All your base are belong to us" };
assert.equal( jQuery.param( params, true ), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All%20your%20base%20are%20belong%20to%20us", "even more arrays" ); assert.equal( jQuery.param( params, true ), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All%20your%20base%20are%20belong%20to%20us", "even more arrays" );
params = { a:[ 1, 2 ], b:{ c:3, d:[ 4, 5 ], e:{ x:[ 6 ], y:7, z:[ 8, 9 ] }, f:true, g:false, h:undefined }, i:[ 10, 11 ], j:true, k:false, l:[ undefined, 0 ], m:"cowboy hat?" }; params = { a: [ 1, 2 ], b: { c: 3, d: [ 4, 5 ], e: { x: [ 6 ], y: 7, z: [ 8, 9 ] }, f: true, g: false, h: undefined }, i: [ 10, 11 ], j: true, k: false, l: [ undefined, 0 ], m: "cowboy hat?" };
assert.equal( jQuery.param( params, true ), "a=1&a=2&b=%5Bobject%20Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy%20hat%3F", "huge structure" ); assert.equal( jQuery.param( params, true ), "a=1&a=2&b=%5Bobject%20Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy%20hat%3F", "huge structure" );
params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, d: 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, d: 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] };
assert.equal( jQuery.param( params, true ), "a=0&a=1%2C2&a=3%2C4%2C5%2C6&a=%5Bobject%20Object%5D&a=17", "nested arrays (not possible when traditional == true)" ); assert.equal( jQuery.param( params, true ), "a=0&a=1%2C2&a=3%2C4%2C5%2C6&a=%5Bobject%20Object%5D&a=17", "nested arrays (not possible when traditional == true)" );
params = { a:[ 1, 2 ], b:{ c:3, d:[ 4, 5 ], e:{ x:[ 6 ], y:7, z:[ 8, 9 ] }, f:true, g:false, h:undefined }, i:[ 10, 11 ], j:true, k:false, l:[ undefined, 0 ], m:"cowboy hat?" }; params = { a: [ 1, 2 ], b: { c: 3, d: [ 4, 5 ], e: { x: [ 6 ], y: 7, z: [ 8, 9 ] }, f: true, g: false, h: undefined }, i: [ 10, 11 ], j: true, k: false, l: [ undefined, 0 ], m: "cowboy hat?" };
assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy hat?", "huge structure, forced not traditional" ); assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy hat?", "huge structure, forced not traditional" );
params = { "param1": null }; params = { "param1": null };
assert.equal( jQuery.param( params ), "param1=", "Make sure that null params aren't traversed." ); assert.equal( jQuery.param( params ), "param1=", "Make sure that null params aren't traversed." );
params = { "param1": function() {}, "param2": function() { return null; } }; params = { "param1": function() {}, "param2": function() {
return null;
} };
assert.equal( jQuery.param( params, false ), "param1=&param2=", "object with function property that returns null value" ); assert.equal( jQuery.param( params, false ), "param1=&param2=", "object with function property that returns null value" );
params = { "test": { "length": 3, "foo": "bar" } }; params = { "test": { "length": 3, "foo": "bar" } };

View File

@ -310,7 +310,9 @@ QUnit.test( "filter(Function)", function( assert ) {
return !jQuery( "a", this ).length; return !jQuery( "a", this ).length;
} ).get(), q( "sndp", "first" ), "filter(Function)" ); } ).get(), q( "sndp", "first" ), "filter(Function)" );
assert.deepEqual( jQuery( "#qunit-fixture p" ).filter( function( i, elem ) { return !jQuery( "a", elem ).length; } ).get(), q( "sndp", "first" ), "filter(Function) using arg" ); assert.deepEqual( jQuery( "#qunit-fixture p" ).filter( function( i, elem ) {
return !jQuery( "a", elem ).length;
} ).get(), q( "sndp", "first" ), "filter(Function) using arg" );
} ); } );
QUnit.test( "filter(Element)", function( assert ) { QUnit.test( "filter(Element)", function( assert ) {
@ -505,7 +507,9 @@ QUnit.test( "not(Element)", function( assert ) {
QUnit.test( "not(Function)", function( assert ) { QUnit.test( "not(Function)", function( assert ) {
assert.expect( 1 ); assert.expect( 1 );
assert.deepEqual( jQuery( "#qunit-fixture p" ).not( function() { return jQuery( "a", this ).length; } ).get(), q( "sndp", "first" ), "not(Function)" ); assert.deepEqual( jQuery( "#qunit-fixture p" ).not( function() {
return jQuery( "a", this ).length;
} ).get(), q( "sndp", "first" ), "not(Function)" );
} ); } );
QUnit.test( "not(Array)", function( assert ) { QUnit.test( "not(Array)", function( assert ) {