diff --git a/.csslintrc b/.csslintrc index 4273f5cc65f..227cda5158b 100644 --- a/.csslintrc +++ b/.csslintrc @@ -7,6 +7,7 @@ "import": false, "important": false, "outline-none": false, + "order-alphabetical": false, "overqualified-elements": false, "text-indent": false } diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000000..8026d53f744 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +dist/**/* +external/**/* +ui/vendor/**/* diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000000..e7d67eb0e51 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "root": true, + + "extends": "jquery", + + // Uncomment to find useless comment disable directives + // "reportUnusedDisableDirectives": true, + + "parserOptions": { + "ecmaVersion": 2018 + }, + + "env": { + "es6": true, + "node": true + }, + + "rules": { + "strict": [ "error", "global" ] + } +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..6fff16c7942 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: monthly diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000000..a513e67538f --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,59 @@ +name: Grunt tests + +on: [push, pull_request] + +jobs: + grunt: + name: Grunt based tests with Node.js ${{ matrix.node-version }} + + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [12.x, 14.x] + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + + - name: Get npm cache directory + id: npm-cache-dir + run: | + echo "::set-output name=dir::$(npm config get cache)" + + - name: Cache npm dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.npm-cache-dir.outputs.dir }} + key: ${{ runner.os }}-node-${{ matrix.node-version }}-npm-${{ hashFiles('**/package.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.node-version }}-npm- + ${{ runner.os }}-node-${{ matrix.node-version }}- + ${{ runner.os }}-node- + ${{ runner.os }}- + + - name: Install npm dependencies + run: npm install + + # Keep these steps in sync with the default command tasks in our Gruntfile! + - name: Run lint + run: node_modules/.bin/grunt lint + + - name: Run RequireJS + run: node_modules/.bin/grunt requirejs + + - name: Run Qunit + run: node_modules/.bin/grunt test + + valid: + name: Build & tests + + needs: grunt + + runs-on: ubuntu-latest + + steps: + - name: Grunt based tests passed + run: echo "✅" diff --git a/.gitignore b/.gitignore index a8423b6077f..1c93c0f2a1d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ dist bower_components node_modules .sizecache.json +package-lock.json diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index 81de6df1c7b..00000000000 --- a/.jscsrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "preset": "jquery", - - // This is currently unenforcable see https://github.com/jscs-dev/node-jscs/issues/1686 - "requireCapitalizedComments": null, - - // Until we drop IE8 this prevents things like warning on float keyword - "es3": true, - - // We want to output all errors - "maxErrors": 1000000 -} diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index e79eeee472e..00000000000 --- a/.jshintrc +++ /dev/null @@ -1,16 +0,0 @@ -{ - "boss": true, - "curly": true, - "eqeqeq": true, - "eqnull": true, - "expr": true, - "immed": true, - "noarg": true, - "quotmark": "double", - "smarttabs": true, - "trailing": true, - "undef": true, - "unused": true, - - "node": true -} diff --git a/.mailmap b/.mailmap index 0b18e41798a..867c841da1d 100644 --- a/.mailmap +++ b/.mailmap @@ -34,6 +34,7 @@ Eric Hynds Ethan Romba EungJun Yi Eyal Kobrigo +Felix Nagel Filippo Cavallarin Florian Gutmann Genie <386@mail.com> @@ -78,6 +79,7 @@ Max Schnur Michael Hollis Michael Stay Michael Wu +Michał Gołębiowski-Owczarek Mike Alsup Milan Broum Mohamed Cherif Bouchelaghem diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000000..fc25be14136 --- /dev/null +++ b/.npmignore @@ -0,0 +1,10 @@ +demos +/dist/cdn +tests +.editorconfig +.eslintrc.json +.eslintignore +.mailmap +Gruntfile.js +.csslintrc +.gitattributes diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7143893d2d8..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -sudo: required -dist: trusty -language: node_js -node_js: - - "0.12" diff --git a/AUTHORS.txt b/AUTHORS.txt index a75056b9414..0ee3fb31ebe 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -312,7 +312,7 @@ Mani Mishra Hannah Methvin Leonardo Balter Benjamin Albert -Michał Gołębiowski +Michał Gołębiowski-Owczarek Alyosha Pushak Fahad Ahmad Matt Brundage @@ -331,3 +331,42 @@ Peter Dave Hello Johannes Schäfer Ville Skyttä Ryan Oriecuia +Sergei Ratnikov +milk54 +Evelyn Masso +Robin +Simon Asika +Kevin Cupp +Jeremy Mickelson +Kyle Rosenberg +Petri Partio +pallxk +Luke Brookhart +claudi +Eirik Sletteberg +Albert Johansson +A. Wells +Robert Brignull +Horus68 +Maksymenkov Eugene +OskarNS +Gez Quinn +jigar gala +Florian Wegscheider +Fatér Zsolt +Szabolcs Szabolcsi-Toth +Jérémy Munsch +Hrvoje Novosel +Paul Capron +Micah Miller +sakshi87 <53863764+sakshi87@users.noreply.github.com> +Mikolaj Wolicki +Patrick McKay +c-lambert <58025159+c-lambert@users.noreply.github.com> +Josep Sanz +Ben Mullins +Christian Oliff +dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +Adam Lidén Hällgren +James Hinderks +Denny Septian Panggabean <97607754+ddevsr@users.noreply.github.com> diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 53922478dfa..4542658a430 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,10 +12,6 @@ There are a number of ways to get involved with the development of jQuery UI. Ev This is the best way to contribute to jQuery UI. Please read through the full guide detailing [How to Report Bugs](http://contribute.jquery.org/bug-reports/). -### Weekly Meetings - -Every week (unless otherwise noted) the jQuery UI team has a meeting to discuss the progress of current work and to bring forward possible new blockers for discussion. The meeting is held on [IRC](http://irc.jquery.org) in the #jquery-meeting channel at [Noon EST](http://www.timeanddate.com/worldclock/fixedtime.html?month=1&day=17&year=2011&hour=12&min=0&sec=0&p1=43) on Wednesdays. Meeting notes are posted on http://meetings.jquery.org/category/ui/ after each meeting. - ## Tips for Getting Started ### Environment: Minimum Required @@ -53,10 +49,10 @@ cd jquery-ui git remote add upstream git://github.com/jquery/jquery-ui.git ``` -* Get in the habit of pulling in the "upstream" master to stay up to date as jQuery UI receives new commits. +* Get in the habit of pulling in the "upstream" main branch to stay up to date as jQuery UI receives new commits. ```bash -git pull upstream master +git pull upstream main ``` ### Environment: Recommended Setup diff --git a/Gruntfile.js b/Gruntfile.js index be423b531de..402c30b750e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,26 +1,28 @@ -module.exports = function( grunt ) { - "use strict"; +module.exports = function( grunt ) { + var + glob = require( "glob" ), + // files coreFiles = [ "core.js", "widget.js", - "mouse.js", - "draggable.js", - "droppable.js", - "resizable.js", - "selectable.js", - "sortable.js", + "widgets/mouse.js", + "widgets/draggable.js", + "widgets/droppable.js", + "widgets/resizable.js", + "widgets/selectable.js", + "widgets/sortable.js", "effect.js" ], - uiFiles = coreFiles.map(function( file ) { + uiFiles = coreFiles.map( function( file ) { return "ui/" + file; - }).concat( expandFiles( "ui/*.js" ).filter(function( file ) { + } ).concat( expandFiles( "ui/**/*.js" ).filter( function( file ) { return coreFiles.indexOf( file.substring( 3 ) ) === -1; - }) ), + } ) ), allI18nFiles = expandFiles( "ui/i18n/*.js" ), @@ -45,9 +47,9 @@ var "tabs", "tooltip", "theme" - ].map(function( component ) { + ].map( function( component ) { return "themes/base/" + component + ".css"; - }), + } ), // minified files minify = { @@ -92,12 +94,12 @@ function mapMinFile( file ) { } function expandFiles( files ) { - return grunt.util._.pluck( grunt.file.expandMapping( files ), "src" ).map(function( values ) { + return grunt.util._.map( grunt.file.expandMapping( files ), "src" ).map( function( values ) { return values[ 0 ]; - }); + } ); } -uiFiles.concat( allI18nFiles ).forEach(function( file ) { +uiFiles.concat( allI18nFiles ).forEach( function( file ) { minify[ file ] = { options: { banner: createBanner() @@ -105,15 +107,17 @@ uiFiles.concat( allI18nFiles ).forEach(function( file ) { files: {} }; minify[ file ].files[ mapMinFile( file ) ] = file; -}); +} ); + +uiFiles.forEach( function( file ) { -uiFiles.forEach(function( file ) { // TODO this doesn't do anything until https://github.com/rwldrn/grunt-compare-size/issues/13 compareFiles[ file ] = [ file, mapMinFile( file ) ]; -}); +} ); // grunt plugins require( "load-grunt-tasks" )( grunt ); + // local testswarm and build tasks grunt.loadTasks( "build/tasks" ); @@ -122,17 +126,18 @@ function stripDirectory( file ) { } function createBanner( files ) { + // strip folders var fileNames = files && files.map( stripDirectory ); return "/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - " + "<%= grunt.template.today('isoDate') %>\n" + "<%= pkg.homepage ? '* ' + pkg.homepage + '\\n' : '' %>" + - (files ? "* Includes: " + fileNames.join(", ") + "\n" : "") + + ( files ? "* Includes: " + fileNames.join( ", " ) + "\n" : "" ) + "* Copyright <%= pkg.author.name %>;" + - " Licensed <%= _.pluck(pkg.licenses, 'type').join(', ') %> */\n"; + " Licensed <%= _.map(pkg.licenses, 'type').join(', ') %> */\n"; } -grunt.initConfig({ +grunt.initConfig( { pkg: grunt.file.readJSON( "package.json" ), files: { dist: "<%= pkg.name %>-<%= pkg.version %>" @@ -166,31 +171,12 @@ grunt.initConfig({ include: expandFiles( [ "ui/**/*.js", "!ui/core.js", "!ui/i18n/*" ] ), out: "dist/jquery-ui.js", wrap: { - start: createBanner( uiFiles ), + start: createBanner( uiFiles ) } } } }, - jscs: { - ui: { - options: { - config: true - }, - files: { - src: [ "demos/**/*.js", "build/**/*.js", "ui/**/*.js" ] - } - }, - tests: { - options: { - config: true, - maximumLineLength: null - }, - files: { - src: [ "tests/**/*.js" ] - } - } - }, uglify: minify, htmllint: { good: { @@ -198,9 +184,9 @@ grunt.initConfig({ ignore: [ /The text content of element “script” was not in the required format: Expected space, tab, newline, or slash but found “.” instead/ ] }, - src: [ "demos/**/*.html", "tests/**/*.html" ].concat( htmllintBad.map( function( file ) { - return "!" + file; - } ) ) + src: glob.sync( "{demos,tests}/**/*.html", { + ignore: htmllintBad + } ) }, bad: { options: { @@ -208,29 +194,39 @@ grunt.initConfig({ /Start tag seen without seeing a doctype first/, /Element “head” is missing a required instance of child element “title”/, /Element “object” is missing one or more of the following/, - /The “codebase” attribute on the “object” element is obsolete/ + /The “codebase” attribute on the “object” element is obsolete/, + /Consider adding a “lang” attribute to the “html” start tag/, + /This document appears to be written in .*. Consider adding “lang=".*"” \(or variant\) to the “html” start tag/ ] }, src: htmllintBad } }, qunit: { - files: expandFiles( "tests/unit/" + component + "/*.html" ).filter(function( file ) { + files: expandFiles( "tests/unit/" + component + "/*.html" ).filter( function( file ) { return !( /(all|index|test)\.html$/ ).test( file ); - }), + } ), options: { - inject: false, + puppeteer: { + ignoreDefaultArgs: true, + args: [ + "--headless", + "--disable-web-security", + "--allow-file-access-from-files" + ] + }, + inject: [ + require.resolve( "grunt-contrib-qunit/chrome/bridge" ) + ], page: { viewportSize: { width: 700, height: 500 } } } }, - jshint: { - options: { - jshintrc: true - }, + eslint: { all: [ - "ui/*.js", + "ui/**/*.js", + "!ui/vendor/**/*.js", "Gruntfile.js", "build/**/*.js", "tests/unit/**/*.js", @@ -248,6 +244,17 @@ grunt.initConfig({ }, bowercopy: { + inlineVendors: { + options: { + clean: true, + destPrefix: "ui/vendor" + }, + files: { + "jquery-color/jquery.color.js": "jquery-color/dist/jquery.color.js", + "jquery-color/LICENSE.txt": "jquery-color/LICENSE.txt" + } + }, + all: { options: { clean: true, @@ -259,10 +266,12 @@ grunt.initConfig({ "qunit/qunit.css": "qunit/qunit/qunit.css", "qunit/LICENSE.txt": "qunit/LICENSE.txt", - "qunit-assert-classes/qunit-assert-classes.js": "qunit-assert-classes/qunit-assert-classes.js", + "qunit-assert-classes/qunit-assert-classes.js": + "qunit-assert-classes/qunit-assert-classes.js", "qunit-assert-classes/LICENSE.txt": "qunit-assert-classes/LICENSE", - "qunit-assert-close/qunit-assert-close.js": "qunit-assert-close/qunit-assert-close.js", + "qunit-assert-close/qunit-assert-close.js": + "qunit-assert-close/qunit-assert-close.js", "qunit-assert-close/MIT-LICENSE.txt": "qunit-assert-close/MIT-LICENSE.txt", "qunit-composite/qunit-composite.js": "qunit-composite/qunit-composite.js", @@ -277,20 +286,8 @@ grunt.initConfig({ "jquery-simulate/jquery.simulate.js": "jquery-simulate/jquery.simulate.js", "jquery-simulate/LICENSE.txt": "jquery-simulate/LICENSE.txt", - "jshint/jshint.js": "jshint/dist/jshint.js", - "jshint/LICENSE": "jshint/LICENSE", - - "jquery/jquery.js": "jquery-1.x/dist/jquery.js", - "jquery/LICENSE.txt": "jquery-1.x/LICENSE.txt", - - "jquery-1.7.0/jquery.js": "jquery-1.7.0/jquery.js", - "jquery-1.7.0/MIT-LICENSE.txt": "jquery-1.7.0/MIT-LICENSE.txt", - - "jquery-1.7.1/jquery.js": "jquery-1.7.1/jquery.js", - "jquery-1.7.1/MIT-LICENSE.txt": "jquery-1.7.1/MIT-LICENSE.txt", - - "jquery-1.7.2/jquery.js": "jquery-1.7.2/jquery.js", - "jquery-1.7.2/MIT-LICENSE.txt": "jquery-1.7.2/MIT-LICENSE.txt", + "jquery/jquery.js": "jquery-3.x/dist/jquery.js", + "jquery/LICENSE.txt": "jquery-3.x/LICENSE.txt", "jquery-1.8.0/jquery.js": "jquery-1.8.0/jquery.js", "jquery-1.8.0/MIT-LICENSE.txt": "jquery-1.8.0/MIT-LICENSE.txt", @@ -392,7 +389,45 @@ grunt.initConfig({ "jquery-3.0.0/LICENSE.txt": "jquery-3.0.0/LICENSE.txt", "jquery-3.1.0/jquery.js": "jquery-3.1.0/dist/jquery.js", - "jquery-3.1.0/LICENSE.txt": "jquery-3.1.0/LICENSE.txt" + "jquery-3.1.0/LICENSE.txt": "jquery-3.1.0/LICENSE.txt", + + "jquery-3.1.1/jquery.js": "jquery-3.1.1/dist/jquery.js", + "jquery-3.1.1/LICENSE.txt": "jquery-3.1.1/LICENSE.txt", + + "jquery-3.2.0/jquery.js": "jquery-3.2.0/dist/jquery.js", + "jquery-3.2.0/LICENSE.txt": "jquery-3.2.0/LICENSE.txt", + + "jquery-3.2.1/jquery.js": "jquery-3.2.1/dist/jquery.js", + "jquery-3.2.1/LICENSE.txt": "jquery-3.2.1/LICENSE.txt", + + "jquery-3.3.0/jquery.js": "jquery-3.3.0/dist/jquery.js", + "jquery-3.3.0/LICENSE.txt": "jquery-3.3.0/LICENSE.txt", + + "jquery-3.3.1/jquery.js": "jquery-3.3.1/dist/jquery.js", + "jquery-3.3.1/LICENSE.txt": "jquery-3.3.1/LICENSE.txt", + + "jquery-3.4.0/jquery.js": "jquery-3.4.0/dist/jquery.js", + "jquery-3.4.0/LICENSE.txt": "jquery-3.4.0/LICENSE.txt", + + "jquery-3.4.1/jquery.js": "jquery-3.4.1/dist/jquery.js", + "jquery-3.4.1/LICENSE.txt": "jquery-3.4.1/LICENSE.txt", + + "jquery-3.5.0/jquery.js": "jquery-3.5.0/dist/jquery.js", + "jquery-3.5.0/LICENSE.txt": "jquery-3.5.0/LICENSE.txt", + + "jquery-3.5.1/jquery.js": "jquery-3.5.1/dist/jquery.js", + "jquery-3.5.1/LICENSE.txt": "jquery-3.5.1/LICENSE.txt", + + "jquery-3.6.0/jquery.js": "jquery-3.6.0/dist/jquery.js", + "jquery-3.6.0/LICENSE.txt": "jquery-3.6.0/LICENSE.txt", + + "jquery-migrate-1.4.1/jquery-migrate.js": + "jquery-migrate-1.4.1/dist/jquery-migrate.js", + "jquery-migrate-1.4.1/LICENSE.txt": "jquery-migrate-1.4.1/LICENSE.txt", + + "jquery-migrate-3.3.2/jquery-migrate.js": + "jquery-migrate-3.3.2/dist/jquery-migrate.js", + "jquery-migrate-3.3.2/LICENSE.txt": "jquery-migrate-3.3.2/LICENSE.txt" } } }, @@ -423,13 +458,13 @@ grunt.initConfig({ "Bohdan Ganicky " ] } -}); +} ); grunt.registerTask( "update-authors", function() { var getAuthors = require( "grunt-git-authors" ).getAuthors, done = this.async(); - getAuthors({ + getAuthors( { priorAuthors: grunt.config( "authors.prior" ) }, function( error, authors ) { if ( error ) { @@ -437,7 +472,7 @@ grunt.registerTask( "update-authors", function() { return done( false ); } - authors = authors.map(function( author ) { + authors = authors.map( function( author ) { if ( author.match( /^Jacek Jędrzejewski =1.6" + "jquery": ">=1.8.0 <4.0.0" }, "devDependencies": { + "jquery-color": "2.2.0", "jquery-mousewheel": "3.1.12", - "jquery-simulate": "1.0.0", - "jshint": "2.4.4", + "jquery-simulate": "1.1.1", "qunit": "1.18.0", "qunit-assert-classes": "1.0.2", "qunit-assert-close": "JamesMGreene/qunit-assert-close#v1.1.1", "qunit-composite": "JamesMGreene/qunit-composite#v1.1.0", "requirejs": "2.1.14", - - "jquery-1.7.0": "jquery#1.7.0", - "jquery-1.7.1": "jquery#1.7.1", - "jquery-1.7.2": "jquery#1.7.2", "jquery-1.8.0": "jquery#1.8.0", "jquery-1.8.1": "jquery#1.8.1", "jquery-1.8.2": "jquery#1.8.2", @@ -42,7 +38,7 @@ "jquery-1.12.2": "jquery#1.12.2", "jquery-1.12.3": "jquery#1.12.3", "jquery-1.12.4": "jquery#1.12.4", - "jquery-1.x": "jquery#1.12.4", + "jquery-3.x": "jquery#3.6.0", "jquery-2.0.0": "jquery#2.0.0", "jquery-2.0.1": "jquery#2.0.1", "jquery-2.0.2": "jquery#2.0.2", @@ -58,6 +54,19 @@ "jquery-2.2.3": "jquery#2.2.3", "jquery-2.2.4": "jquery#2.2.4", "jquery-3.0.0": "jquery#3.0.0", - "jquery-3.1.0": "jquery#3.1.0" - } + "jquery-3.1.0": "jquery#3.1.0", + "jquery-3.1.1": "jquery#3.1.1", + "jquery-3.2.0": "jquery#3.2.0", + "jquery-3.2.1": "jquery#3.2.1", + "jquery-3.3.0": "jquery#3.3.0", + "jquery-3.3.1": "jquery#3.3.1", + "jquery-3.4.0": "jquery#3.4.0", + "jquery-3.4.1": "jquery#3.4.1", + "jquery-3.5.0": "jquery#3.5.0", + "jquery-3.5.1": "jquery#3.5.1", + "jquery-3.6.0": "jquery#3.6.0", + "jquery-migrate-1.4.1": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-1.4.1.tgz", + "jquery-migrate-3.3.2": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-3.3.2.tgz" + }, + "version": "1.13.2" } diff --git a/build/release-test.js b/build/release-test.js index be5227a43a7..083f1a6c538 100644 --- a/build/release-test.js +++ b/build/release-test.js @@ -1,3 +1,5 @@ +"use strict"; + var shell = require( "shelljs" ); var Release = { define: function( props ) { @@ -35,7 +37,7 @@ script( Release ); // Ignores actual version installed, should be good enough for a test if ( shell.exec( "npm ls --depth 0 | grep download.jqueryui.com" ).code === 1 ) { - shell.exec( "npm install " + script.dependencies.join( " " ) ); + shell.exec( "npm install --no-save " + script.dependencies.join( " " ) ); } // If AUTHORS.txt is outdated, this will update it diff --git a/build/release.js b/build/release.js index 99b26833bdb..0323a20bd3c 100644 --- a/build/release.js +++ b/build/release.js @@ -1,3 +1,5 @@ +"use strict"; + module.exports = function( Release ) { var crypto = require( "crypto" ); @@ -35,7 +37,7 @@ function replaceAtVersion() { return matches; } -function removeExternals ( packager ) { +function removeExternals( packager ) { Object.keys( packager.builtFiles ).forEach( function( filepath ) { if ( /^external\//.test( filepath ) ) { delete packager.builtFiles[ filepath ]; @@ -57,8 +59,21 @@ function addManifest( packager ) { function buildCDNPackage( callback ) { console.log( "Building CDN package" ); var JqueryUi = require( "download.jqueryui.com/lib/jquery-ui" ); - var Package = require( "download.jqueryui.com/lib/package-1-12-themes" ); + var PackageWithoutThemes = require( "download.jqueryui.com/lib/package-1-13" ); + var PackageOfThemes = require( "download.jqueryui.com/lib/package-1-13-themes" ); var Packager = require( "node-packager" ); + + // PackageOfThemes doesn't contain JS files, PackageWithoutThemes doesn't contain themes; + // we need both. + function Package() { + + // PackageOfThemes invokes PackageWithoutThemes's constructor in its own so we don't + // need to do it by ourselves; we just need to handle prototypes that way. + PackageOfThemes.apply( this, arguments ); + } + + Object.assign( Package.prototype, PackageWithoutThemes.prototype, PackageOfThemes.prototype ); + var jqueryUi = new JqueryUi( path.resolve( "." ) ); var target = fs.createWriteStream( "../" + jqueryUi.pkg.name + "-" + jqueryUi.pkg.version + "-cdn.zip" ); @@ -69,24 +84,27 @@ function buildCDNPackage( callback ) { jqueryUi: jqueryUi, themeVars: null } ); - packager.ready.then( function() { - removeExternals( packager ); - addManifest( packager ); - packager.toZip( target, { - basedir: "" - }, function( error ) { - if ( error ) { - Release.abort( "Failed to zip CDN package", error ); - } - callback(); + packager.ready + .then( function() { + removeExternals( packager ); + addManifest( packager ); + packager.toZip( target, { + basedir: "" + }, function( error ) { + if ( error ) { + Release.abort( "Failed to zip the CDN package", error ); + } + callback(); + } ); + } ) + .catch( function( error ) { + Release.abort( "Failed to create the CDN package", error ); } ); - } ); } Release.define( { npmPublish: true, - issueTracker: "trac", - contributorReportId: 22, + issueTracker: "github", changelogShell: function() { var monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], @@ -113,6 +131,20 @@ Release.define( { shell.mkdir( "-p", "dist/cdn" ); shell.cp( tmpFolder + "/jquery-ui*.js", "dist/cdn" ); shell.cp( "-r", tmpFolder + "/themes", "dist/cdn" ); + + // Copy all the files to be published on the CDN to the dist directory + // as well. + shell.cp( "dist/cdn/jquery-ui.js", "dist" ); + shell.cp( "dist/cdn/jquery-ui.min.js", "dist" ); + shell.cp( "-r", "dist/cdn/themes", "dist" ); + + Release.exec( "git add --force dist/jquery-ui.js", + "Error adding dist/jquery-ui.js." ); + Release.exec( "git add --force dist/jquery-ui.min.js", + "Error adding dist/jquery-ui.min.js." ); + Release.exec( "git add --force dist/themes", + "Error adding dist/themes." ); + fn( files ); } ); } @@ -121,7 +153,7 @@ Release.define( { }; module.exports.dependencies = [ - "download.jqueryui.com@2.1.2", + "download.jqueryui.com@2.2.7", "node-packager@0.0.6", - "shelljs@0.2.6" + "shelljs@0.8.4" ]; diff --git a/build/tasks/build.js b/build/tasks/build.js index 77ae2545daf..48feb7aba1d 100644 --- a/build/tasks/build.js +++ b/build/tasks/build.js @@ -1,7 +1,7 @@ -module.exports = function( grunt ) { - "use strict"; +module.exports = function( grunt ) { + grunt.registerTask( "clean", function() { require( "rimraf" ).sync( "dist" ); } ); diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js index daf36838e56..ebc2c49ee52 100644 --- a/build/tasks/testswarm.js +++ b/build/tasks/testswarm.js @@ -1,10 +1,16 @@ -module.exports = function( grunt ) { - "use strict"; +module.exports = function( grunt ) { + var versions = { "git": "git", - "3.1": "3.1.0", + "3.x-git": "3.x-git", + "3.6": "3.6.0", + "3.5": "3.5.1", + "3.4": "3.4.1", + "3.3": "3.3.1", + "3.2": "3.2.1", + "3.1": "3.1.1", "3.0": "3.0.0", "2.2": "2.2.4", "2.1": "2.1.4", @@ -13,8 +19,7 @@ var versions = { "1.11": "1.11.3", "1.10": "1.10.2", "1.9": "1.9.1", - "1.8": "1.8.3", - "1.7": "1.7.2" + "1.8": "1.8.3" }, tests = { "Accordion": "accordion/accordion.html", @@ -43,20 +48,20 @@ var versions = { "Widget": "widget/widget.html" }; -function submit( commit, runs, configFile, extra, done ) { +function submit( commit, runs, configFile, browserSets, extra, done ) { var testName, testswarm = require( "testswarm" ), config = grunt.file.readJSON( configFile ).jqueryui, - browserSets = config.browserSets, commitUrl = "https://github.com/jquery/jquery-ui/commit/" + commit; - if ( extra ) { + browserSets = browserSets || config.browserSets; + if ( browserSets[ 0 ] === "[" ) { - // jQuery >= 2.0.0 don't support IE 8. - if ( extra.substring( 0, 6 ) !== "core 1" ) { - browserSets = "jquery-ui-future"; - } + // We got an array, parse it + browserSets = JSON.parse( browserSets ); + } + if ( extra ) { extra = " (" + extra + ")"; } @@ -86,23 +91,23 @@ function submit( commit, runs, configFile, extra, done ) { } ); } -grunt.registerTask( "testswarm", function( commit, configFile ) { +grunt.registerTask( "testswarm", function( commit, configFile, browserSets ) { var test, latestTests = {}; for ( test in tests ) { - latestTests[ test ] = tests[ test ] + "?nojshint=true"; + latestTests[ test ] = tests[ test ]; } - submit( commit, latestTests, configFile, "", this.async() ); + submit( commit, latestTests, configFile, browserSets, "", this.async() ); } ); -grunt.registerTask( "testswarm-multi-jquery", function( commit, configFile, minor ) { +grunt.registerTask( "testswarm-multi-jquery", function( commit, configFile, minor, browserSets ) { var allTests = {}; versions[ minor ].split( " " ).forEach( function( version ) { for ( var test in tests ) { - allTests[ test + "-" + version ] = tests[ test ] + "?nojshint=true&jquery=" + version; + allTests[ test + "-" + version ] = tests[ test ] + "?jquery=" + version; } } ); - submit( commit, allTests, configFile, "core " + minor, this.async() ); + submit( commit, allTests, configFile, browserSets, "core " + minor, this.async() ); } ); }; diff --git a/demos/.eslintrc.json b/demos/.eslintrc.json new file mode 100644 index 00000000000..da1cb6b909b --- /dev/null +++ b/demos/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "root": true, + + "extends": "../ui/.eslintrc.json" +} diff --git a/demos/autocomplete/combobox.html b/demos/autocomplete/combobox.html index 403c48550c8..32c69b97a0b 100644 --- a/demos/autocomplete/combobox.html +++ b/demos/autocomplete/combobox.html @@ -48,7 +48,7 @@ .autocomplete({ delay: 0, minLength: 0, - source: $.proxy( this, "_source" ) + source: this._source.bind( this ) }) .tooltip({ classes: { diff --git a/demos/autocomplete/search.php b/demos/autocomplete/search.php index 489b30c1e31..6ab404ccbd0 100644 --- a/demos/autocomplete/search.php +++ b/demos/autocomplete/search.php @@ -586,7 +586,10 @@ $output = json_encode($result); if ($_GET["callback"]) { - $output = $_GET["callback"] . "($output);"; + // Escape special characters to avoid XSS attacks via direct loads of this + // page with a callback that contains HTML. This is a lot easier than validating + // the callback name. + $output = htmlspecialchars($_GET["callback"]) . "($output);"; } echo $output; diff --git a/demos/autocomplete/xml.html b/demos/autocomplete/xml.html index 95235753124..d86ca156355 100644 --- a/demos/autocomplete/xml.html +++ b/demos/autocomplete/xml.html @@ -25,7 +25,8 @@ var data = $( "geoname", xmlResponse ).map(function() { return { value: $( "name", this ).text() + ", " + - ( $.trim( $( "countryName", this ).text() ) || "(unknown country)" ), + ( String.prototype.trim.call( $( "countryName", this ).text() ) || + "(unknown country)" ), id: $( "geonameId", this ).text() }; }).get(); diff --git a/demos/bootstrap.js b/demos/bootstrap.js index 9a82071c797..9b046802815 100644 --- a/demos/bootstrap.js +++ b/demos/bootstrap.js @@ -1,5 +1,6 @@ /* globals window, document */ ( function() { +"use strict"; // Find the script element var scripts = document.getElementsByTagName( "script" ); diff --git a/demos/button/default.html b/demos/button/default.html index 644dcd22541..7ac6a325d05 100644 --- a/demos/button/default.html +++ b/demos/button/default.html @@ -9,7 +9,7 @@ diff --git a/demos/controlgroup/splitbutton.html b/demos/controlgroup/splitbutton.html index ec2b78876d6..27f9498160a 100644 --- a/demos/controlgroup/splitbutton.html +++ b/demos/controlgroup/splitbutton.html @@ -21,7 +21,7 @@ } }); $( ".controlgroup" ).controlgroup(); - $( "button" ).click(function() { + $( "button" ).on( "click", function() { $( ".output" ).append( "
  • Running Last Action...
  • " ); }); diff --git a/demos/effect/easing.html b/demos/effect/easing.html index b22c6958089..4bee1c41f14 100644 --- a/demos/effect/easing.html +++ b/demos/effect/easing.html @@ -34,7 +34,7 @@ canvas.width = width; canvas.height = height; var drawHeight = height * 0.8, - cradius = 10; + cradius = 10, ctx = canvas.getContext( "2d" ); ctx.fillStyle = "black"; diff --git a/demos/position/cycler.html b/demos/position/cycler.html index 910b0050cfa..49616b3806a 100644 --- a/demos/position/cycler.html +++ b/demos/position/cycler.html @@ -49,24 +49,24 @@ }); } - left( $( "img:eq(0)" ) ); - center( $( "img:eq(1)" ) ); - right( $( "img:eq(2)" ) ); + left( $( "img" ).eq( 0 ) ); + center( $( "img" ).eq( 1 ) ); + right( $( "img" ).eq( 2 ) ); function animate( to ) { $( this ).stop( true, false ).animate( to ); } function next( event ) { event.preventDefault(); - center( $( "img:eq(2)" ), animate ); - left( $( "img:eq(1)" ), animate ); - right( $( "img:eq(0)" ).appendTo( "#container" ) ); + center( $( "img" ).eq( 2 ), animate ); + left( $( "img" ).eq( 1 ), animate ); + right( $( "img" ).eq( 0 ).appendTo( "#container" ) ); } function previous( event ) { event.preventDefault(); - center( $( "img:eq(0)" ), animate ); - right( $( "img:eq(1)" ), animate ); - left( $( "img:eq(2)" ).prependTo( "#container" ) ); + center( $( "img" ).eq( 0 ), animate ); + right( $( "img" ).eq( 1 ), animate ); + left( $( "img" ).eq( 2 ).prependTo( "#container" ) ); } $( "#previous" ).on( "click", previous ); $( "#next" ).on( "click", next ); @@ -76,9 +76,9 @@ }); $( window ).on( "resize", function() { - left( $( "img:eq(0)" ), animate ); - center( $( "img:eq(1)" ), animate ); - right( $( "img:eq(2)" ), animate ); + left( $( "img" ).eq( 0 ), animate ); + center( $( "img" ).eq( 1 ), animate ); + right( $( "img" ).eq( 2 ), animate ); }); diff --git a/demos/selectmenu/images/24-video-square.png b/demos/selectmenu/images/24-video-square.png index 54b6455aed2..8e7f5438f96 100644 Binary files a/demos/selectmenu/images/24-video-square.png and b/demos/selectmenu/images/24-video-square.png differ diff --git a/demos/sortable/default.html b/demos/sortable/default.html index f37a23c44af..b3ce9860d0f 100644 --- a/demos/sortable/default.html +++ b/demos/sortable/default.html @@ -14,7 +14,6 @@ diff --git a/demos/tabs/sortable.html b/demos/tabs/sortable.html index 051663ed4e9..81ae22a2546 100644 --- a/demos/tabs/sortable.html +++ b/demos/tabs/sortable.html @@ -9,10 +9,21 @@ diff --git a/demos/tooltip/video-player.html b/demos/tooltip/video-player.html index e1ebac24f32..74db642aa1f 100644 --- a/demos/tooltip/video-player.html +++ b/demos/tooltip/video-player.html @@ -37,7 +37,9 @@ ", + nextText: "", + currentText: "", + closeText: "", + buttonText: "", + appendText: "" + } ); + + var dp = $( "#ui-datepicker-div" ); + + testHelper.onFocus( inp, function() { + assert.equal( dp.find( ".ui-datepicker-prev" ).text().trim(), + "", + "prevText escaped" ); + assert.equal( dp.find( ".ui-datepicker-next" ).text().trim(), + "", + "nextText escaped" ); + assert.equal( dp.find( ".ui-datepicker-current" ).text().trim(), + "", + "currentText escaped" ); + assert.equal( dp.find( ".ui-datepicker-close" ).text().trim(), + "", + "closeText escaped" ); + + assert.equal( qf.find( ".ui-datepicker-trigger" ).text().trim(), + "", + "buttonText escaped" ); + assert.equal( qf.find( ".ui-datepicker-append" ).text().trim(), + "", + "appendText escaped" ); + + assert.deepEqual( window.uiGlobalXss, [], "No XSS" ); + + delete window.uiGlobalXss; + inp.datepicker( "hide" ).datepicker( "destroy" ); + done(); + } ); +} ); + } ); diff --git a/tests/unit/dialog/core.js b/tests/unit/dialog/core.js index 3b89a66388e..cb0ee53e0a1 100644 --- a/tests/unit/dialog/core.js +++ b/tests/unit/dialog/core.js @@ -1,11 +1,13 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/dialog" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -// TODO add teardown callback to remove dialogs -QUnit.module( "dialog: core" ); +// TODO add afterEach callback to remove dialogs +QUnit.module( "dialog: core", { afterEach: helper.moduleAfterEach } ); QUnit.test( "markup structure", function( assert ) { assert.expect( 11 ); @@ -118,13 +120,33 @@ QUnit.test( "focus tabbable", function( assert ) { function step1() { checkFocus( "
    ", options, function( done ) { - var input = element.find( "input:last" ).trigger( "focus" ).trigger( "blur" ); - element.dialog( "instance" )._focusTabbable(); - setTimeout( function() { - assert.equal( document.activeElement, input[ 0 ], - "1. an element that was focused previously." ); - done(); - } ); + var input = element.find( "input" ).last().trigger( "focus" ).trigger( "blur" ); + + // Support: IE 11+ + // In IE in jQuery 3.4+ a sequence: + // $( inputNode ).trigger( "focus" ).trigger( "blur" ).trigger( "focus" ) + // doesn't end up with a focused input. See: + // https://github.com/jquery/jquery/issues/4856 + // However, in this test we only want to check that the last focused + // input receives the focus back when `_focusTabbable()` is called + // which in reality doesn't happen so quickly so let's avoid the issue + // by waiting a bit. + if ( document.documentMode ) { + setTimeout( function() { + focusTabbableAndAssert(); + }, 500 ); + } else { + focusTabbableAndAssert(); + } + + function focusTabbableAndAssert() { + element.dialog( "instance" )._focusTabbable(); + setTimeout( function() { + assert.equal( document.activeElement, input[ 0 ], + "1. an element that was focused previously." ); + done(); + } ); + } }, step2 ); } @@ -188,8 +210,7 @@ QUnit.test( "focus tabbable", function( assert ) { function( done ) { var inputs = element.find( "input" ); - assert.equal - ( document.activeElement, inputs[ 1 ], "Focus starts on second input" ); + assert.equal( document.activeElement, inputs[ 1 ], "Focus starts on second input" ); inputs.last().simulate( "keydown", { keyCode: $.ui.keyCode.TAB } ); setTimeout( function() { assert.equal( document.activeElement, inputs[ 0 ], @@ -254,7 +275,7 @@ QUnit.test( "#9048: multiple modal dialogs opened and closed in different order" function( assert ) { var ready = assert.async(); assert.expect( 1 ); - $( "#dialog1, #dialog2" ).dialog( { autoOpen: false, modal:true } ); + $( "#dialog1, #dialog2" ).dialog( { autoOpen: false, modal: true } ); $( "#dialog1" ).dialog( "open" ); $( "#dialog2" ).dialog( "open" ); $( "#dialog1" ).dialog( "close" ); @@ -290,9 +311,7 @@ QUnit.test( "interaction between overlay and other dialogs", function( assert ) // Wait for the modal to init setTimeout( function() { - second. - testWidget - ( "open" ); + second.testWidget( "open" ); // Simulate user tabbing from address bar to an element outside the dialog $( "#favorite-animal" ).trigger( "focus" ); diff --git a/tests/unit/dialog/deprecated.js b/tests/unit/dialog/deprecated.js index 973a90893a1..b8cf7a9a585 100644 --- a/tests/unit/dialog/deprecated.js +++ b/tests/unit/dialog/deprecated.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/dialog" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "dialog (deprecated): options" ); +QUnit.module( "dialog (deprecated): options", { afterEach: helper.moduleAfterEach } ); QUnit.test( "dialogClass", function( assert ) { assert.expect( 5 ); @@ -50,7 +52,7 @@ QUnit.test( "buttons - deprecated options", function( assert ) { buttons = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" ); assert.equal( buttons.length, 1, "correct number of buttons" ); assert.equal( buttons.attr( "id" ), "my-button-id", "correct id" ); - assert.equal( $.trim( buttons.text() ), "a button", "correct label" ); + assert.equal( String.prototype.trim.call( buttons.text() ), "a button", "correct label" ); assert.hasClasses( buttons, "additional-class" ); assert.deepEqual( buttons.button( "option", "icon" ), "ui-icon-cancel" ); assert.equal( buttons.button( "option", "showLabel" ), false ); diff --git a/tests/unit/dialog/events.js b/tests/unit/dialog/events.js index a5030a9f4f4..eb77de2ff85 100644 --- a/tests/unit/dialog/events.js +++ b/tests/unit/dialog/events.js @@ -4,8 +4,9 @@ define( [ "./helper", "ui/widgets/dialog" ], function( QUnit, $, testHelper ) { +"use strict"; -QUnit.module( "dialog: events" ); +QUnit.module( "dialog: events", { afterEach: testHelper.moduleAfterEach } ); QUnit.test( "open", function( assert ) { assert.expect( 13 ); diff --git a/tests/unit/dialog/helper.js b/tests/unit/dialog/helper.js index ac013ecfc6a..55555626af9 100644 --- a/tests/unit/dialog/helper.js +++ b/tests/unit/dialog/helper.js @@ -4,6 +4,7 @@ define( [ "lib/helper", "ui/widgets/dialog" ], function( QUnit, $, helper ) { +"use strict"; return $.extend( helper, { drag: function( element, handle, dx, dy ) { diff --git a/tests/unit/dialog/methods.js b/tests/unit/dialog/methods.js index a3e63ce7ad0..5d01f223d6c 100644 --- a/tests/unit/dialog/methods.js +++ b/tests/unit/dialog/methods.js @@ -1,12 +1,15 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/dialog" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; QUnit.module( "dialog: methods", { afterEach: function() { $( "body>.ui-dialog" ).remove(); + return helper.moduleAfterEach.apply( this, arguments ); } } ); @@ -66,7 +69,7 @@ QUnit.test( "destroy", function( assert ) { assert.equal( $( ".ui-widget-overlay" ).length, 0, "overlay does not exist" ); assert.equal( $( document ).data( "ui-dialog-overlays" ), undefined, "ui-dialog-overlays equals the number of open overlays" ); - element = $( "#dialog1" ).dialog( { modal: true } ), + element = $( "#dialog1" ).dialog( { modal: true } ); element2 = $( "#dialog2" ).dialog( { modal: true } ); assert.equal( $( ".ui-widget-overlay" ).length, 2, "overlays created when dialogs are open" ); assert.equal( $( document ).data( "ui-dialog-overlays" ), 2, "ui-dialog-overlays equals the number of open overlays" ); @@ -84,7 +87,7 @@ QUnit.test( "destroy", function( assert ) { QUnit.test( "#9000: Dialog leaves broken event handler after close/destroy in certain cases", function( assert ) { var ready = assert.async(); assert.expect( 1 ); - $( "#dialog1" ).dialog( { modal:true } ).dialog( "close" ).dialog( "destroy" ); + $( "#dialog1" ).dialog( { modal: true } ).dialog( "close" ).dialog( "destroy" ); setTimeout( function() { $( "#favorite-animal" ).trigger( "focus" ); assert.ok( true, "close and destroy modal dialog before its really opened" ); diff --git a/tests/unit/dialog/options.js b/tests/unit/dialog/options.js index 1be2888e340..2de788a4461 100644 --- a/tests/unit/dialog/options.js +++ b/tests/unit/dialog/options.js @@ -1,13 +1,15 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/dialog", "ui/effects/effect-blind", "ui/effects/effect-explode" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "dialog: options" ); +QUnit.module( "dialog: options", { afterEach: helper.moduleAfterEach } ); QUnit.test( "appendTo", function( assert ) { assert.expect( 16 ); @@ -166,7 +168,7 @@ QUnit.test( "buttons - advanced", function( assert ) { buttons = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" ); assert.equal( buttons.length, 1, "correct number of buttons" ); assert.equal( buttons.attr( "id" ), "my-button-id", "correct id" ); - assert.equal( $.trim( buttons.text() ), "a button", "correct label" ); + assert.equal( String.prototype.trim.call( buttons.text() ), "a button", "correct label" ); assert.hasClasses( buttons, "additional-class" ); assert.deepEqual( buttons.button( "option", "icon" ), "ui-icon-cancel" ); assert.equal( buttons.button( "option", "showLabel" ), false ); @@ -210,22 +212,22 @@ QUnit.test( "closeText", function( assert ) { assert.expect( 4 ); var element = $( "
    " ).dialog(); - assert.equal( $.trim( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "Close", + assert.equal( String.prototype.trim.call( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "Close", "default close text" ); element.remove(); element = $( "
    " ).dialog( { closeText: "foo" } ); - assert.equal( $.trim( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "foo", + assert.equal( String.prototype.trim.call( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "foo", "closeText on init" ); element.remove(); element = $( "
    " ).dialog().dialog( "option", "closeText", "bar" ); - assert.equal( $.trim( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "bar", + assert.equal( String.prototype.trim.call( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "bar", "closeText via option method" ); element.remove(); element = $( "
    " ).dialog( { closeText: "foo" } ); - assert.equal( $.trim( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "foo", + assert.equal( String.prototype.trim.call( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "foo", "closeText is escaped" ); element.remove(); } ); @@ -251,21 +253,25 @@ QUnit.test( "height", function( assert ) { assert.expect( 4 ); var element = $( "
    " ).dialog(); - assert.equal( element.dialog( "widget" ).outerHeight(), 150, "default height" ); + assert.ok( Math.abs( element.dialog( "widget" ).outerHeight() - 150 ) < 0.25, + "default height within 0.25 from expected" ); element.remove(); element = $( "
    " ).dialog( { height: 237 } ); - assert.equal( element.dialog( "widget" ).outerHeight(), 237, "explicit height" ); + assert.ok( Math.abs( element.dialog( "widget" ).outerHeight() - 237 ) < 0.25, + "explicit height within 0.25 from expected" ); element.remove(); element = $( "
    " ).dialog(); element.dialog( "option", "height", 238 ); - assert.equal( element.dialog( "widget" ).outerHeight(), 238, "explicit height set after init" ); + assert.ok( Math.abs( element.dialog( "widget" ).outerHeight() - 238 ) < 0.25, + "explicit height set after init within 0.25 from expected" ); element.remove(); element = $( "
    " ).css( "padding", "20px" ) .dialog( { height: 240 } ); - assert.equal( element.dialog( "widget" ).outerHeight(), 240, "explicit height with padding" ); + assert.ok( Math.abs( element.dialog( "widget" ).outerHeight() - 240 ) < 0.25, + "explicit height with padding within 0.25 from expected" ); element.remove(); } ); diff --git a/tests/unit/draggable/core.js b/tests/unit/draggable/core.js index 1dd6f572a98..9cfbb185393 100644 --- a/tests/unit/draggable/core.js +++ b/tests/unit/draggable/core.js @@ -1,13 +1,15 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/draggable", "ui/widgets/droppable", "ui/widgets/resizable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "draggable: core" ); +QUnit.module( "draggable: core", { afterEach: helper.moduleAfterEach } ); QUnit.test( "element types", function( assert ) { var typeNames = ( diff --git a/tests/unit/draggable/events.js b/tests/unit/draggable/events.js index f8c4a655122..97ec912ae45 100644 --- a/tests/unit/draggable/events.js +++ b/tests/unit/draggable/events.js @@ -1,8 +1,10 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/draggable" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; var element; @@ -12,6 +14,7 @@ QUnit.module( "draggable: events", { }, afterEach: function() { element.draggable( "destroy" ); + return helper.moduleAfterEach.apply( this, arguments ); } } ); diff --git a/tests/unit/draggable/helper.js b/tests/unit/draggable/helper.js index de5dc4a6b36..c1920f23bb8 100644 --- a/tests/unit/draggable/helper.js +++ b/tests/unit/draggable/helper.js @@ -4,6 +4,7 @@ define( [ "lib/helper", "ui/widgets/draggable" ], function( QUnit, $, helper ) { +"use strict"; return $.extend( helper, { diff --git a/tests/unit/draggable/methods.js b/tests/unit/draggable/methods.js index 8e95dac30ed..93f826faf98 100644 --- a/tests/unit/draggable/methods.js +++ b/tests/unit/draggable/methods.js @@ -1,9 +1,11 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/draggable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var element; @@ -13,6 +15,7 @@ QUnit.module( "draggable: methods", { }, afterEach: function() { element.remove(); + return helper.moduleAfterEach.apply( this, arguments ); } } ); diff --git a/tests/unit/draggable/options.js b/tests/unit/draggable/options.js index 656df621f0f..499454a6500 100644 --- a/tests/unit/draggable/options.js +++ b/tests/unit/draggable/options.js @@ -1,13 +1,15 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/draggable", "ui/widgets/droppable", "ui/widgets/sortable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "draggable: options" ); +QUnit.module( "draggable: options", { afterEach: helper.moduleAfterEach } ); // TODO: This doesn't actually test whether append happened, possibly remove QUnit.test( "{ appendTo: 'parent' }, default, no clone", function( assert ) { @@ -252,9 +254,9 @@ QUnit.test( "cancelement, default, switching after initialization", function( as } ); QUnit.test( "connectToSortable, dragging out of a sortable", function( assert ) { - assert.expect( 4 ); + assert.expect( 5 ); - var sortItem, dragHelper, + var sortItem, dragHelper, result, element = $( "#draggableSortable" ).draggable( { scroll: false, connectToSortable: "#sortable" @@ -280,7 +282,12 @@ QUnit.test( "connectToSortable, dragging out of a sortable", function( assert ) // http://bugs.jqueryui.com/ticket/8809 // Position issue when connected to sortable - assert.deepEqual( ui.helper.offset(), offsetExpected, "draggable offset is correct" ); + result = ui.helper.offset(); + + // Support: Chrome <=45 - 73+ + // In recent Chrome these values differ a little. + assert.ok( Math.abs( result.top - offsetExpected.top ) < 0.25, "draggable offset is within 0.25 of expected" ); + assert.ok( Math.abs( result.left - offsetExpected.left ) < 0.25, "draggable offset is within 0.25 of expected" ); // Http://bugs.jqueryui.com/ticket/7734 // HTML IDs are removed when dragging to a Sortable @@ -296,6 +303,9 @@ QUnit.test( "connectToSortable, dragging out of a sortable", function( assert ) dx: dx, dy: dy } ); + + // Cleanup + element.stop( true ); } ); QUnit.test( "connectToSortable, dragging clone into sortable", function( assert ) { @@ -1460,7 +1470,7 @@ QUnit.test( "zIndex, default, switching after initialization", function( assert } ); QUnit.test( "iframeFix", function( assert ) { - assert.expect( 5 ); + assert.expect( 6 ); var element = $( "
    " ).appendTo( "#qunit-fixture" ).draggable( { iframeFix: true } ), element2 = $( "
    " ).appendTo( "#qunit-fixture" ).draggable( { iframeFix: ".iframe" } ), @@ -1476,14 +1486,22 @@ QUnit.test( "iframeFix", function( assert ) { } ); element.one( "drag", function() { - var div = $( this ).children().not( "iframe" ); + var divOffset, iframeOffset, + div = $( this ).children().not( "iframe" ); // http://bugs.jqueryui.com/ticket/9671 // iframeFix doesn't handle iframes that move assert.equal( div.length, 1, "blocking div added as sibling" ); assert.equal( div.outerWidth(), iframe.outerWidth(), "blocking div is wide enough" ); assert.equal( div.outerHeight(), iframe.outerHeight(), "blocking div is tall enough" ); - assert.deepEqual( div.offset(), iframe.offset(), "blocking div is tall enough" ); + + divOffset = div.offset(); + iframeOffset = iframe.offset(); + + // Support: Edge <79 only + // In Edge Legacy these values differ a little. + assert.ok( Math.abs( divOffset.top - iframeOffset.top ) < 0.25, "Check top within 0.25 of expected" ); + assert.ok( Math.abs( divOffset.left - iframeOffset.left ) < 0.25, "Check left within 0.25 of expected" ); } ); element.simulate( "drag", { diff --git a/tests/unit/droppable/core.js b/tests/unit/droppable/core.js index 3d41e5db838..5cc6771f9d7 100644 --- a/tests/unit/droppable/core.js +++ b/tests/unit/droppable/core.js @@ -1,11 +1,13 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/droppable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "droppable: core" ); +QUnit.module( "droppable: core", { afterEach: helper.moduleAfterEach } ); QUnit.test( "element types", function( assert ) { var typeNames = ( "p,h1,h2,h3,h4,h5,h6,blockquote,ol,ul,dl,div,form" + @@ -19,7 +21,9 @@ QUnit.test( "element types", function( assert ) { var typeName = typeNames[ i ], el = $( document.createElement( typeName ) ).appendTo( "body" ); - ( typeName === "table" && el.append( "content" ) ); + if ( typeName === "table" ) { + el.append( "content" ); + } el.droppable(); testHelper.shouldDrop( assert ); el.droppable( "destroy" ); diff --git a/tests/unit/droppable/events.js b/tests/unit/droppable/events.js index 8ccd7c87c9d..8b2bbd38e9b 100644 --- a/tests/unit/droppable/events.js +++ b/tests/unit/droppable/events.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/droppable" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "droppable: events" ); +QUnit.module( "droppable: events", { afterEach: helper.moduleAfterEach } ); QUnit.test( "droppable destruction/recreation on drop event", function( assert ) { assert.expect( 1 ); diff --git a/tests/unit/droppable/helper.js b/tests/unit/droppable/helper.js index f6bf9e411d8..2cf1b5c53f0 100644 --- a/tests/unit/droppable/helper.js +++ b/tests/unit/droppable/helper.js @@ -3,6 +3,7 @@ define( [ "jquery", "lib/helper" ], function( QUnit, $, helper ) { +"use strict"; return $.extend( helper, { shouldDrop: function( assert ) { diff --git a/tests/unit/droppable/methods.js b/tests/unit/droppable/methods.js index 433615d1657..96df6ea4028 100644 --- a/tests/unit/droppable/methods.js +++ b/tests/unit/droppable/methods.js @@ -1,11 +1,13 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/droppable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "droppable: methods" ); +QUnit.module( "droppable: methods", { afterEach: helper.moduleAfterEach } ); QUnit.test( "init", function( assert ) { assert.expect( 5 ); @@ -60,7 +62,7 @@ QUnit.test( "enable", function( assert ) { assert.equal( el.droppable( "option", "disabled" ), false, "disabled option setter" ); testHelper.shouldDrop( assert ); - expected = $( "
    " ).droppable(), + expected = $( "
    " ).droppable(); actual = expected.droppable( "enable" ); assert.equal( actual, expected, "enable is chainable" ); } ); diff --git a/tests/unit/droppable/options.js b/tests/unit/droppable/options.js index 1c164495b97..7cc765cf534 100644 --- a/tests/unit/droppable/options.js +++ b/tests/unit/droppable/options.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/droppable" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "droppable: options" ); +QUnit.module( "droppable: options", { afterEach: helper.moduleAfterEach } ); /* Test( "{ accept '*' }, default ", function() { @@ -79,6 +81,7 @@ QUnit.test( "scope", function( assert ) { assert.equal( draggableOffset.left, oldDraggableOffset.left ); assert.equal( draggableOffset.top, oldDraggableOffset.top ); } ); + /* Test( "greedy", function() { ok(false, 'missing test - untested code is broken code'); diff --git a/tests/unit/effects/core.js b/tests/unit/effects/core.js index 9863cd8ca81..187f5355ad9 100644 --- a/tests/unit/effects/core.js +++ b/tests/unit/effects/core.js @@ -2,6 +2,7 @@ define( [ "qunit", "jquery", "lib/common", + "lib/helper", "ui/effect", "ui/effects/effect-blind", "ui/effects/effect-bounce", @@ -18,7 +19,8 @@ define( [ "ui/effects/effect-size", "ui/effects/effect-slide", "ui/effects/effect-transfer" -], function( QUnit, $, common ) { +], function( QUnit, $, common, helper ) { +"use strict"; QUnit.assert.present = function( value, array, message ) { this.push( jQuery.inArray( value, array ) !== -1, value, array, message ); @@ -34,7 +36,7 @@ var minDuration = 60, // Duration is used for "long" animates where we plan on testing properties during animation duration = 200; -QUnit.module( "effects.core" ); +QUnit.module( "effects.core", { afterEach: helper.moduleAfterEach } ); // TODO: test all signatures of .show(), .hide(), .toggle(). // Look at core's signatures and UI's signatures. @@ -97,7 +99,7 @@ QUnit.test( "removeClass", function( assert ) { assert.equal( "", element[ 0 ].className ); } ); -QUnit.module( "effects.core: animateClass" ); +QUnit.module( "effects.core: animateClass", { afterEach: helper.moduleAfterEach } ); QUnit.test( "animateClass works with borderStyle", function( assert ) { var ready = assert.async(); @@ -145,12 +147,9 @@ QUnit.test( "animateClass works with colors", function( assert ) { QUnit.test( "animateClass calls step option", function( assert ) { assert.expect( 1 ); - var ready = assert.async(); var test = jQuery( "div.animateClass" ), step = function() { assert.ok( true, "Step Function Called" ); - test.stop(); - ready(); step = $.noop; }; test.toggleClass( "testChangeBackground", { @@ -158,6 +157,8 @@ QUnit.test( "animateClass calls step option", function( assert ) { step(); } } ); + + test.stop( true, true ); } ); QUnit.test( "animateClass works with children", function( assert ) { @@ -210,7 +211,7 @@ QUnit.test( "animateClass clears style properties when stopped", function( asser .stop( true, true ) .promise() .then( function() { - assert.equal( orig, $.trim( style.cssText ), "cssText is the same after stopping animation midway" ); + assert.equal( orig, String.prototype.trim.call( style.cssText ), "cssText is the same after stopping animation midway" ); ready(); } ); } ); @@ -268,12 +269,12 @@ QUnit.test( "createPlaceholder: preserves layout affecting properties", function assert.deepEqual( before.position.top - position, placeholder.position().top, "position top preserved" ); assert.deepEqual( before.position.left - position, placeholder.position().left, "position left preserved" ); - assert.deepEqual( before[ "float" ], placeholder.css( "float" ), "float preserved" ); + assert.deepEqual( before.float, placeholder.css( "float" ), "float preserved" ); assert.deepEqual( before.outerWidth, placeholder.outerWidth( true ), "width preserved" ); assert.deepEqual( before.outerHeight, placeholder.outerHeight( true ), "height preserved" ); } ); -QUnit.module( "transfer" ); +QUnit.module( "transfer", { afterEach: helper.moduleAfterEach } ); QUnit.test( "transfer() without callback", function( assert ) { var ready = assert.async(); @@ -304,8 +305,6 @@ QUnit.test( "transfer() with callback", function( assert ) { $.each( $.effects.effect, function( effect ) { QUnit.module( "effects." + effect ); - common.testJshint( "effects/effect-" + effect ); - if ( effect === "transfer" ) { return; } @@ -378,8 +377,10 @@ $.each( $.effects.effect, function( effect ) { assert.equal( test[ 0 ].style.height, cssHeight, "Inline CSS Height has been rest after animation ended" ); ready(); } ); - assert.equal( test.width(), width, "Width is the same px after animation started" ); - assert.equal( test.height(), height, "Height is the same px after animation started" ); + assert.ok( Math.abs( test.width() - width ) / width < 0.05, + "Width is close to the value when animation started" ); + assert.ok( Math.abs( test.height() - height ) / height < 0.05, + "Height is close to the value when animation started" ); } ); } ); diff --git a/tests/unit/effects/scale.js b/tests/unit/effects/scale.js index 44a59234b80..e5300028d81 100644 --- a/tests/unit/effects/scale.js +++ b/tests/unit/effects/scale.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/effects/effect-scale" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "effect.scale: Scale" ); +QUnit.module( "effect.scale: Scale", { afterEach: helper.moduleAfterEach } ); function run( position, v, h, vo, ho ) { var desc = "End Position Correct: " + position + " (" + v + "," + h + ") - origin: (" + vo + "," + ho + ")"; @@ -33,8 +35,20 @@ function run( position, v, h, vo, ho ) { css[ h ] = 33; css[ v ] = 33; - target[ h ] = h === ho ? css[ h ] : ho === "center" ? css[ h ] - 35 : css[ h ] - 70; - target[ v ] = v === vo ? css[ v ] : vo === "middle" ? css[ v ] - 35 : css[ v ] - 70; + if ( h === ho ) { + target[ h ] = css[ h ]; + } else if ( ho === "center" ) { + target[ h ] = css[ h ] - 35; + } else { + target[ h ] = css[ h ] - 70; + } + if ( v === vo ) { + target[ v ] = css[ v ]; + } else if ( vo === "middle" ) { + target[ v ] = css[ v ] - 35; + } else { + target[ v ] = css[ v ] - 70; + } if ( relative && h === "right" ) { target[ h ] += 70; } @@ -50,6 +64,7 @@ function suite( position ) { run( position, "top", "left", "top", "left" ); run( position, "top", "left", "middle", "center" ); run( position, "top", "left", "bottom", "right" ); + /* Firefox is currently not capable of supporting detection of bottom and right.... run( position, "bottom", "right", "top", "left" ); run( position, "bottom", "right", "middle", "center" ); diff --git a/tests/unit/form-reset-mixin/core.js b/tests/unit/form-reset-mixin/core.js index 643f3912bf4..aca84ef0c59 100644 --- a/tests/unit/form-reset-mixin/core.js +++ b/tests/unit/form-reset-mixin/core.js @@ -2,9 +2,11 @@ define( [ "qunit", "jquery", "lib/common", + "lib/helper", "ui/widget", "ui/form-reset-mixin" -], function( QUnit, $, common ) { +], function( QUnit, $, common, helper ) { +"use strict"; QUnit.module( "widget factory", { beforeEach: function() { @@ -26,11 +28,10 @@ QUnit.module( "widget factory", { afterEach: function() { delete $.ui.testWidget; delete $.fn.testWidget; + return helper.moduleAfterEach.apply( this, arguments ); } } ); -common.testJshint( "form-reset-mixin" ); - QUnit.test( "form reset", function( assert ) { var ready = assert.async(); assert.expect( 2 ); diff --git a/tests/unit/menu/core.js b/tests/unit/menu/core.js index 6742aa53e34..84add3cfb00 100644 --- a/tests/unit/menu/core.js +++ b/tests/unit/menu/core.js @@ -1,11 +1,13 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/menu" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "menu: core" ); +QUnit.module( "menu: core", { afterEach: helper.moduleAfterEach } ); QUnit.test( "markup structure", function( assert ) { assert.expect( 11 ); @@ -87,8 +89,8 @@ QUnit.test( "active menu item styling", function( assert ) { } $.ui.menu.prototype.delay = 0; var element = $( "#menu4" ).menu(); - var parentItem = element.children( "li:eq(1)" ); - var childItem = parentItem.find( "li:eq(0)" ); + var parentItem = element.children( "li" ).eq( 1 ); + var childItem = parentItem.find( "li" ).eq( 0 ); element.menu( "focus", null, parentItem ); setTimeout( function() { isActive( parentItem ); @@ -96,7 +98,7 @@ QUnit.test( "active menu item styling", function( assert ) { setTimeout( function() { isActive( parentItem ); isActive( childItem ); - element.blur(); + element.trigger( "blur" ); setTimeout( function() { isInactive( parentItem ); isInactive( childItem ); diff --git a/tests/unit/menu/events.js b/tests/unit/menu/events.js index a8ccb028214..caac7e74171 100644 --- a/tests/unit/menu/events.js +++ b/tests/unit/menu/events.js @@ -1,9 +1,11 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/menu" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var log = testHelper.log, logOutput = testHelper.logOutput, @@ -12,7 +14,8 @@ var log = testHelper.log, QUnit.module( "menu: events", { beforeEach: function() { testHelper.clearLog(); - } + }, + afterEach: helper.moduleAfterEach } ); QUnit.test( "handle click on menu", function( assert ) { @@ -176,12 +179,12 @@ QUnit.test( "handle submenu auto collapse: mouseleave, default markup", function function menumouseleave1() { assert.equal( element.find( "ul[aria-expanded='true']" ).length, 1, "first submenu expanded" ); - element.menu( "focus", event, element.find( "li:nth-child(7) li:first" ) ); + element.menu( "focus", event, element.find( "li:nth-child(7) li" ).first() ); setTimeout( menumouseleave2, 25 ); } function menumouseleave2() { assert.equal( element.find( "ul[aria-expanded='true']" ).length, 2, "second submenu expanded" ); - element.find( "ul[aria-expanded='true']:first" ).trigger( "mouseleave" ); + element.find( "ul[aria-expanded='true']" ).first().trigger( "mouseleave" ); setTimeout( menumouseleave3, 25 ); } function menumouseleave3() { @@ -213,7 +216,7 @@ QUnit.test( "handle submenu auto collapse: mouseleave, custom markup", function( } function menumouseleave2() { assert.equal( element.find( "div[aria-expanded='true']" ).length, 2, "second submenu expanded" ); - element.find( "div[aria-expanded='true']:first" ).trigger( "mouseleave" ); + element.find( "div[aria-expanded='true']" ).first().trigger( "mouseleave" ); setTimeout( menumouseleave3, 25 ); } function menumouseleave3() { @@ -306,7 +309,7 @@ QUnit.test( "handle keyboard navigation on menu without scroll and with submenus log( $( ui.item[ 0 ] ).text() ); }, focus: function( event ) { - log( $( event.target ).find( ".ui-menu-item-wrapper.ui-state-active:last" ).parent().index() ); + log( $( event.target ).find( ".ui-menu-item-wrapper.ui-state-active" ).last().parent().index() ); } } ); @@ -427,7 +430,7 @@ QUnit.test( "handle keyboard navigation on menu with scroll and without submenus log( $( ui.item[ 0 ] ).text() ); }, focus: function( event ) { - log( $( event.target ).find( ".ui-menu-item-wrapper.ui-state-active:last" ).parent().index() ); + log( $( event.target ).find( ".ui-menu-item-wrapper.ui-state-active" ).last().parent().index() ); } } ); @@ -503,7 +506,7 @@ QUnit.test( "handle keyboard navigation on menu with scroll and with submenus", log( $( ui.item[ 0 ] ).text() ); }, focus: function( event ) { - log( $( event.target ).find( ".ui-menu-item-wrapper.ui-state-active:last" ).parent().index() ); + log( $( event.target ).find( ".ui-menu-item-wrapper.ui-state-active" ).last().parent().index() ); } } ); @@ -670,7 +673,9 @@ QUnit.test( "handle keyboard navigation and mouse click on menu with dividers an element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - assert.equal( logOutput(), "keydown,3,4,7", "Keydown focus skips divider and group label" ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + assert.equal( logOutput(), "keydown,1,2,3,4,7", "Keydown focus skips divider and group label" ); ready(); } } ); @@ -755,4 +760,26 @@ QUnit.test( "#10571: When typing in a menu, only menu-items should be focused", } ); } ); +QUnit.test( "#15157: Must not focus menu dividers with the keyboard", function( assert ) { + var ready = assert.async(); + assert.expect( 6 ); + + var element = $( "#menu-with-dividers" ).menu( { + focus: function( event, ui ) { + assert.hasClasses( ui.item, "ui-menu-item", "Should have menu item class" ); + log( ui.item.text() ); + } + } ); + + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); + setTimeout( function() { + assert.equal( logOutput(), "beginning,middle,end,beginning,end", "Should wrap around items" ); + ready(); + } ); +} ); + } ); diff --git a/tests/unit/menu/helper.js b/tests/unit/menu/helper.js index 4456639857c..748dfe773c2 100644 --- a/tests/unit/menu/helper.js +++ b/tests/unit/menu/helper.js @@ -14,7 +14,7 @@ return $.extend( helper, { if ( message === undefined ) { message = lastItem; } - log.push( $.trim( message ) ); + log.push( String.prototype.trim.call( message ) ); }, logOutput: function() { @@ -27,7 +27,8 @@ return $.extend( helper, { click: function( menu, item ) { lastItem = item; - menu.children( ":eq(" + item + ")" ) + menu.children() + .eq( item ) .children( ".ui-menu-item-wrapper" ) .trigger( "click" ); } diff --git a/tests/unit/menu/menu.html b/tests/unit/menu/menu.html index 2d871a4b327..8d70b19dfee 100644 --- a/tests/unit/menu/menu.html +++ b/tests/unit/menu/menu.html @@ -323,6 +323,16 @@
  • Addyston
  • Adelphi
  • + +
    diff --git a/tests/unit/menu/methods.js b/tests/unit/menu/methods.js index 48eaa33cd44..3c304c2644c 100644 --- a/tests/unit/menu/methods.js +++ b/tests/unit/menu/methods.js @@ -1,9 +1,11 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/menu" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var log = testHelper.log, logOutput = testHelper.logOutput, @@ -12,7 +14,8 @@ var log = testHelper.log, QUnit.module( "menu: methods", { beforeEach: function() { testHelper.clearLog(); - } + }, + afterEach: helper.moduleAfterEach } ); QUnit.test( "destroy", function( assert ) { @@ -51,33 +54,33 @@ QUnit.test( "refresh", function( assert ) { assert.equal( element.find( ".ui-menu-item" ).length, 5, "Incorrect number of menu items" ); element.append( "
  • test item
  • " ).menu( "refresh" ); assert.equal( element.find( ".ui-menu-item" ).length, 6, "Incorrect number of menu items" ); - element.find( ".ui-menu-item:last" ).remove().end().menu( "refresh" ); + element.find( ".ui-menu-item" ).last().remove().end().end().menu( "refresh" ); assert.equal( element.find( ".ui-menu-item" ).length, 5, "Incorrect number of menu items" ); element.append( "
  • ---
  • " ).menu( "refresh" ); assert.equal( element.find( ".ui-menu-item" ).length, 5, "Incorrect number of menu items" ); - element.children( ":last" ).remove().end().menu( "refresh" ); + element.children().last().remove().end().end().menu( "refresh" ); assert.equal( element.find( ".ui-menu-item" ).length, 5, "Incorrect number of menu items" ); } ); QUnit.test( "refresh submenu", function( assert ) { assert.expect( 2 ); var element = $( "#menu2" ).menu(); - assert.equal( element.find( "ul:first .ui-menu-item" ).length, 3 ); + assert.equal( element.find( "ul" ).first().find( ".ui-menu-item" ).length, 3 ); element.find( "ul" ).addBack().append( "
  • New Item
  • " ); element.menu( "refresh" ); - assert.equal( element.find( "ul:first .ui-menu-item" ).length, 4 ); + assert.equal( element.find( "ul" ).first().find( ".ui-menu-item" ).length, 4 ); } ); QUnit.test( "refresh icons (see #9377)", function( assert ) { assert.expect( 3 ); var element = $( "#menu1" ).menu(); assert.lacksClasses( element, "ui-menu-icons" ); - element.find( "li:first .ui-menu-item-wrapper" ) + element.find( "li" ).first().find( ".ui-menu-item-wrapper" ) .html( "Save" ); element.menu( "refresh" ); assert.hasClasses( element, "ui-menu-icons" ); - element.find( "li:first .ui-menu-item-wrapper" ).html( "Save" ); + element.find( "li" ).first().find( ".ui-menu-item-wrapper" ).html( "Save" ); element.menu( "refresh" ); assert.lacksClasses( element, "ui-menu-icons" ); } ); diff --git a/tests/unit/menu/options.js b/tests/unit/menu/options.js index 8479b719c37..edbfec44789 100644 --- a/tests/unit/menu/options.js +++ b/tests/unit/menu/options.js @@ -1,9 +1,11 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/menu" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var log = testHelper.log, logOutput = testHelper.logOutput, @@ -12,7 +14,8 @@ var log = testHelper.log, QUnit.module( "menu: options", { beforeEach: function() { testHelper.clearLog(); - } + }, + afterEach: helper.moduleAfterEach } ); QUnit.test( "{ disabled: true }", function( assert ) { diff --git a/tests/unit/position/core.js b/tests/unit/position/core.js index 42615a78752..dac56f5b906 100644 --- a/tests/unit/position/core.js +++ b/tests/unit/position/core.js @@ -2,8 +2,10 @@ define( [ "qunit", "jquery", "lib/common", + "lib/helper", "ui/position" -], function( QUnit, $, common ) { +], function( QUnit, $, common, helper ) { +"use strict"; var win = $( window ), scrollTopSupport = function() { @@ -18,11 +20,10 @@ var win = $( window ), QUnit.module( "position", { beforeEach: function() { win.scrollTop( 0 ).scrollLeft( 0 ); - } + }, + afterEach: helper.moduleAfterEach } ); -common.testJshint( "position" ); - QUnit.test( "my, at, of", function( assert ) { assert.expect( 4 ); @@ -111,7 +112,9 @@ QUnit.test( "positions", function( assert ) { } ); QUnit.test( "of", function( assert ) { - assert.expect( 9 + ( scrollTopSupport() ? 1 : 0 ) ); + assert.expect( 10 + ( scrollTopSupport() ? 1 : 0 ) ); + + var done = assert.async(); var event; @@ -223,6 +226,21 @@ QUnit.test( "of", function( assert ) { top: 600, left: 400 }, "event - left top, right bottom" ); + + try { + $( "#elx" ).position( { + my: "left top", + at: "right bottom", + of: "", + collision: "none" + } ); + } catch ( e ) {} + + setTimeout( function() { + assert.equal( window.globalOf, undefined, "of treated as a selector" ); + delete window.globalOf; + done(); + }, 500 ); } ); QUnit.test( "offsets", function( assert ) { @@ -332,6 +350,7 @@ QUnit.test( "using", function( assert ) { assert.deepEqual( position, expectedPosition, "correct position for call #" + count ); assert.deepEqual( feedback.element.element[ 0 ], elems[ count ] ); delete feedback.element.element; + delete feedback.target.element.prevObject; assert.deepEqual( feedback, expectedFeedback ); count++; } @@ -638,7 +657,13 @@ QUnit.test( "within", function( assert ) { }, "flipfit - left top" ); } ); -QUnit.test( "with scrollbars", function( assert ) { +// jQuery 3.2 incorrectly handle scrollbars in WebKit/Blink-based browsers. +// This is fixed in version 3.3, see https://github.com/jquery/jquery/issues/3589. +// As the data here comes from jQuery directly and the changes to fix it +// are non-trivial: https://github.com/jquery/jquery/pull/3656, just accept +// that scrollbar data in this jQuery version is inaccurate. +QUnit[ jQuery.fn.jquery.substring( 0, 4 ) === "3.2." ? "skip" : "test" ]( + "with scrollbars", function( assert ) { assert.expect( 4 ); $( "#scrollx" ).css( { diff --git a/tests/unit/progressbar/core.js b/tests/unit/progressbar/core.js index b25032a407f..b79ee1f6308 100644 --- a/tests/unit/progressbar/core.js +++ b/tests/unit/progressbar/core.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/progressbar" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "progressbar: core" ); +QUnit.module( "progressbar: core", { afterEach: helper.moduleAfterEach } ); QUnit.test( "markup structure", function( assert ) { assert.expect( 7 ); diff --git a/tests/unit/progressbar/events.js b/tests/unit/progressbar/events.js index be43378a766..3bdcd2bba4f 100644 --- a/tests/unit/progressbar/events.js +++ b/tests/unit/progressbar/events.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/progressbar" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "progressbar: events" ); +QUnit.module( "progressbar: events", { afterEach: helper.moduleAfterEach } ); QUnit.test( "create", function( assert ) { assert.expect( 1 ); diff --git a/tests/unit/progressbar/methods.js b/tests/unit/progressbar/methods.js index 51554937275..4d6f3a039b5 100644 --- a/tests/unit/progressbar/methods.js +++ b/tests/unit/progressbar/methods.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/progressbar" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "progressbar: methods" ); +QUnit.module( "progressbar: methods", { afterEach: helper.moduleAfterEach } ); QUnit.test( "destroy", function( assert ) { assert.expect( 1 ); diff --git a/tests/unit/progressbar/options.js b/tests/unit/progressbar/options.js index 7ad4c2603d4..bb7450db085 100644 --- a/tests/unit/progressbar/options.js +++ b/tests/unit/progressbar/options.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/progressbar" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "progressbar: options" ); +QUnit.module( "progressbar: options", { afterEach: helper.moduleAfterEach } ); QUnit.test( "{ value: 0 }, default", function( assert ) { assert.expect( 1 ); diff --git a/tests/unit/resizable/core.js b/tests/unit/resizable/core.js index 8c58405e3e9..b3c61514a98 100644 --- a/tests/unit/resizable/core.js +++ b/tests/unit/resizable/core.js @@ -1,11 +1,13 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/resizable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "resizable: core" ); +QUnit.module( "resizable: core", { afterEach: helper.moduleAfterEach } ); /* Test("element types", function() { diff --git a/tests/unit/resizable/events.js b/tests/unit/resizable/events.js index 4e396872612..1822247f505 100644 --- a/tests/unit/resizable/events.js +++ b/tests/unit/resizable/events.js @@ -1,11 +1,13 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/resizable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "resizable: events" ); +QUnit.module( "resizable: events", { afterEach: helper.moduleAfterEach } ); QUnit.test( "start", function( assert ) { diff --git a/tests/unit/resizable/helper.js b/tests/unit/resizable/helper.js index 2b8c2b46da9..0c9c139592e 100644 --- a/tests/unit/resizable/helper.js +++ b/tests/unit/resizable/helper.js @@ -3,6 +3,7 @@ define( [ "jquery", "lib/helper" ], function( QUnit, $, helper ) { +"use strict"; return $.extend( helper, { drag: function( el, dx, dy ) { diff --git a/tests/unit/resizable/methods.js b/tests/unit/resizable/methods.js index 7ee49eee69e..c00687b58f3 100644 --- a/tests/unit/resizable/methods.js +++ b/tests/unit/resizable/methods.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/resizable" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "resizable: methods" ); +QUnit.module( "resizable: methods", { afterEach: helper.moduleAfterEach } ); QUnit.test( "disable", function( assert ) { assert.expect( 5 ); diff --git a/tests/unit/resizable/options.js b/tests/unit/resizable/options.js index 03c40ff9898..d8584056202 100644 --- a/tests/unit/resizable/options.js +++ b/tests/unit/resizable/options.js @@ -1,11 +1,13 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/resizable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "resizable: options" ); +QUnit.module( "resizable: options", { afterEach: helper.moduleAfterEach } ); QUnit.test( "alsoResize", function( assert ) { assert.expect( 2 ); @@ -155,6 +157,28 @@ QUnit.test( "aspectRatio: Resizing can move objects", function( assert ) { assert.equal( target.position().top, 0, "compare top - no movement" ); } ); +QUnit.test( "aspectRatio: aspectRatio can be changed after initialization", function( assert ) { + assert.expect( 4 ); + + var target = $( "#resizable1" ) + .resizable( { aspectRatio: 1 } ) + .resizable( "option", "aspectRatio", false ); + + var handle = ".ui-resizable-e"; + + testHelper.drag( handle, 80 ); + + assert.equal( target.width(), 180, "compare width - size change" ); + assert.equal( target.height(), 100, "compare height - no size change" ); + + target.resizable( "option", "aspectRatio", 2 ); + + testHelper.drag( handle, -40 ); + + assert.equal( target.width(), 140, "compare width - size change" ); + assert.equal( target.height(), 70, "compare height - size change in proper relation" ); +} ); + QUnit.test( "containment", function( assert ) { assert.expect( 4 ); @@ -412,11 +436,22 @@ QUnit.test( "zIndex, applied to all handles", function( assert ) { } ); QUnit.test( "setOption handles", function( assert ) { - assert.expect( 11 ); - - var target = $( "
    " ).resizable(); - - function checkHandles( expectedHandles ) { + assert.expect( 19 ); + + // https://bugs.jqueryui.com/ticket/3423 + // https://bugs.jqueryui.com/ticket/15084 + var target = $( "
    " ).resizable(), + target2 = $( "
    " + + "
    " + + "
    " + + "
    " ).resizable( { + handles: { + "e": "ui-resizable-e", + "w": "ui-resizable-w" + } + } ); + + function checkHandles( target, expectedHandles ) { expectedHandles = $.map( expectedHandles, function( value ) { return ".ui-resizable-" + value; } ); @@ -429,13 +464,22 @@ QUnit.test( "setOption handles", function( assert ) { } ); } - checkHandles( [ "e", "s", "se" ] ); + checkHandles( target, [ "e", "s", "se" ] ); target.resizable( "option", "handles", "n, w, nw" ); - checkHandles( [ "n", "w", "nw" ] ); + checkHandles( target, [ "n", "w", "nw" ] ); target.resizable( "option", "handles", "s, w" ); - checkHandles( [ "s", "w" ] ); + checkHandles( target, [ "s", "w" ] ); + + target2.resizable( "option", "handles", "e, s, w" ); + checkHandles( target2, [ "e", "s", "w" ] ); + + target.resizable( "destroy" ); + checkHandles( target, [ ] ); + + target2.resizable( "destroy" ); + checkHandles( target2, [ "e", "w" ] ); } ); QUnit.test( "alsoResize + containment", function( assert ) { diff --git a/tests/unit/selectable/events.js b/tests/unit/selectable/events.js index 7f8e2baee8a..5f1a512bff7 100644 --- a/tests/unit/selectable/events.js +++ b/tests/unit/selectable/events.js @@ -4,8 +4,9 @@ define( [ "lib/helper", "ui/widgets/selectable" ], function( QUnit, $, testHelpers ) { +"use strict"; -QUnit.module( "selectable: events" ); +QUnit.module( "selectable: events", { afterEach: testHelpers.moduleAfterEach } ); QUnit.test( "start", function( assert ) { assert.expect( 2 ); diff --git a/tests/unit/selectable/methods.js b/tests/unit/selectable/methods.js index c56c228bcd0..377ac6150f5 100644 --- a/tests/unit/selectable/methods.js +++ b/tests/unit/selectable/methods.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/selectable" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "selectable: methods" ); +QUnit.module( "selectable: methods", { afterEach: helper.moduleAfterEach } ); QUnit.test( "init", function( assert ) { assert.expect( 5 ); @@ -52,7 +54,9 @@ QUnit.test( "enable", function( assert ) { el.selectable( { disabled: true, - start: function() { fired = true; } + start: function() { + fired = true; + } } ); el.simulate( "drag", { dx: 20, diff --git a/tests/unit/selectable/options.js b/tests/unit/selectable/options.js index 58d4b6eb573..6c9e84901be 100644 --- a/tests/unit/selectable/options.js +++ b/tests/unit/selectable/options.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/selectable" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "selectable: options" ); +QUnit.module( "selectable: options", { afterEach: helper.moduleAfterEach } ); QUnit.test( "autoRefresh", function( assert ) { assert.expect( 3 ); @@ -12,7 +14,9 @@ QUnit.test( "autoRefresh", function( assert ) { var actual = 0, el = $( "#selectable1" ), sel = $( "*", el ), - selected = function() { actual += 1; }; + selected = function() { + actual += 1; + }; el = $( "#selectable1" ).selectable( { autoRefresh: false, selected: selected } ); sel.hide(); @@ -50,7 +54,9 @@ QUnit.test( "filter", function( assert ) { var actual = 0, el = $( "#selectable1" ), sel = $( "*", el ), - selected = function() { actual += 1; }; + selected = function() { + actual += 1; + }; el = $( "#selectable1" ).selectable( { filter: ".special", selected: selected } ); el.simulate( "drag", { diff --git a/tests/unit/selectmenu/core.js b/tests/unit/selectmenu/core.js index a5bc68e0f83..f32cec9b99a 100644 --- a/tests/unit/selectmenu/core.js +++ b/tests/unit/selectmenu/core.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/selectmenu" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "selectmenu: core" ); +QUnit.module( "selectmenu: core", { afterEach: helper.moduleAfterEach } ); QUnit.test( "markup structure", function( assert ) { assert.expect( 7 ); @@ -95,7 +97,7 @@ QUnit.test( "_renderButtonItem()", function( assert ) { element.selectmenu( "refresh" ); option = element.find( "option:selected" ); assert.equal( - $.trim( button.text() ), + String.prototype.trim.call( button.text() ), option.text() + element[ 0 ].selectedIndex, "refresh: button item text" ); @@ -104,7 +106,7 @@ QUnit.test( "_renderButtonItem()", function( assert ) { menu.find( "li" ).last().simulate( "mouseover" ).trigger( "click" ); option = element.find( "option" ).last(); assert.equal( - $.trim( button.text() ), + String.prototype.trim.call( button.text() ), option.text() + element[ 0 ].selectedIndex, "click: button item text" ); @@ -153,7 +155,7 @@ $.each( [ selected.val(), "original select state" ); - assert.equal( $.trim( button.text() ), selected.text(), "button text" ); + assert.equal( String.prototype.trim.call( button.text() ), selected.text(), "button text" ); ready(); } ); } ); @@ -189,7 +191,7 @@ $.each( [ selected.val(), "original select state" ); - assert.equal( $.trim( button.text() ), selected.text(), "button text" ); + assert.equal( String.prototype.trim.call( button.text() ), selected.text(), "button text" ); ready(); }, 1 ); } ); @@ -231,7 +233,7 @@ $.each( [ "button aria-activedescendant" ); assert.equal( element.find( "option:selected" ).val(), options.eq( 1 ).val(), "original select state" ); - assert.equal( $.trim( button.text() ), options.eq( 1 ).text(), "button text" ); + assert.equal( String.prototype.trim.call( button.text() ), options.eq( 1 ).text(), "button text" ); ready(); } ); } ); @@ -251,13 +253,13 @@ $.each( [ wrappers = menu.find( "li.ui-menu-item .ui-menu-item-wrapper" ); button.trigger( "click" ); - wrappers.first().simulate( "mouseover" ).trigger( "click" ); + wrappers.first().simulate( "mouseover", { clientX: 2, clientY: 2 } ).trigger( "click" ); assert.equal( element[ 0 ].selectedIndex, 0, "First item is selected" ); button.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); assert.equal( element[ 0 ].selectedIndex, 0, "No looping beyond first item" ); button.trigger( "click" ); - wrappers.last().simulate( "mouseover" ).trigger( "click" ); + wrappers.last().simulate( "mouseover", { clientX: 3, clientY: 3 } ).trigger( "click" ); assert.equal( element[ 0 ].selectedIndex, wrappers.length - 1, "Last item is selected" ); button.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); assert.equal( element[ 0 ].selectedIndex, wrappers.length - 1, "No looping behind last item" ); @@ -352,10 +354,10 @@ QUnit.test( "Selectmenu should reset when its parent form resets", function( ass element.val( "Slower" ); element.selectmenu( "refresh" ); - assert.equal( $.trim( widget.text() ), "Slower" ); + assert.equal( String.prototype.trim.call( widget.text() ), "Slower" ); form[ 0 ].reset(); setTimeout( function() { - assert.equal( $.trim( widget.text() ), initialValue ); + assert.equal( String.prototype.trim.call( widget.text() ), initialValue ); ready(); } ); } ); @@ -376,4 +378,60 @@ QUnit.test( "Number pad input should change value", function( assert ) { } ); } ); +QUnit.test( "Options with hidden attribute should not be rendered", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + + var button, menu, options, + element = $( "#speed" ); + + element.find( "option" ).eq( 1 ).prop( "hidden", true ); + element.selectmenu(); + button = element.selectmenu( "widget" ); + menu = element.selectmenu( "menuWidget" ); + + button.simulate( "focus" ); + setTimeout( function() { + button.trigger( "click" ); + options = menu.children() + .map( function() { + return $( this ).text(); + } ) + .get(); + assert.deepEqual( options, [ "Slower", "Medium", "Fast", "Faster" ], "correct elements" ); + + ready(); + } ); +} ); + +QUnit.test( "extra listeners created after selection (trac-15078, trac-15152)", function( assert ) { + assert.expect( 3 ); + + var origRemoveListenersCount; + var element = $( "#speed" ).selectmenu(); + var menu = element.selectmenu( "widget" ); + + element.val( "Slow" ); + element.selectmenu( "refresh" ); + origRemoveListenersCount = jQuery._data( menu[ 0 ], "events" ).remove.length; + + element.val( "Fast" ); + element.selectmenu( "refresh" ); + assert.equal( jQuery._data( menu[ 0 ], "events" ).remove.length, + origRemoveListenersCount, + "No extra listeners after typing multiple letters" ); + + element.val( "Faster" ); + element.selectmenu( "refresh" ); + assert.equal( jQuery._data( menu[ 0 ], "events" ).remove.length, + origRemoveListenersCount, + "No extra listeners after typing multiple letters" ); + + element.val( "Slow" ); + element.selectmenu( "refresh" ); + assert.equal( jQuery._data( menu[ 0 ], "events" ).remove.length, + origRemoveListenersCount, + "No extra listeners after typing multiple letters" ); +} ); + } ); diff --git a/tests/unit/selectmenu/events.js b/tests/unit/selectmenu/events.js index 4aed70ac80b..108ac500b6c 100644 --- a/tests/unit/selectmenu/events.js +++ b/tests/unit/selectmenu/events.js @@ -1,13 +1,16 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/selectmenu" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; QUnit.module( "selectmenu: events", { beforeEach: function() { this.element = $( "#speed" ); - } + }, + afterEach: helper.moduleAfterEach } ); QUnit.test( "change", function( assert ) { @@ -89,9 +92,9 @@ QUnit.test( "focus", function( assert ) { button.trigger( "click" ); links = menu.find( "li.ui-menu-item" ); optionIndex = 0; - links.eq( optionIndex ).simulate( "mouseover" ); + links.eq( optionIndex ).simulate( "mouseover", { clientX: 2, clientY: 2 } ); optionIndex += 1; - links.eq( optionIndex ).simulate( "mouseover" ); + links.eq( optionIndex ).simulate( "mouseover", { clientX: 3, clientY: 3 } ); // This tests for unwanted, additional focus event on close that.element.selectmenu( "close" ); diff --git a/tests/unit/selectmenu/methods.js b/tests/unit/selectmenu/methods.js index c25d01af520..31c2a2a2b35 100644 --- a/tests/unit/selectmenu/methods.js +++ b/tests/unit/selectmenu/methods.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/selectmenu" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "selectmenu: methods" ); +QUnit.module( "selectmenu: methods", { afterEach: helper.moduleAfterEach } ); QUnit.test( "destroy", function( assert ) { assert.expect( 1 ); @@ -83,21 +85,21 @@ QUnit.test( "refresh - change selected option", function( assert ) { var element = $( "#speed" ).selectmenu(), button = element.selectmenu( "widget" ); - assert.equal( $.trim( button.text() ), "Medium", "button text after init" ); + assert.equal( String.prototype.trim.call( button.text() ), "Medium", "button text after init" ); button.simulate( "focus" ); setTimeout( function() { - assert.equal( $.trim( button.text() ), "Medium", "button text after focus" ); + assert.equal( String.prototype.trim.call( button.text() ), "Medium", "button text after focus" ); element[ 0 ].selectedIndex = 0; element.selectmenu( "refresh" ); - assert.equal( $.trim( button.text() ), "Slower", "button text after changing selected option" ); + assert.equal( String.prototype.trim.call( button.text() ), "Slower", "button text after changing selected option" ); element.find( "option" ).prop( "selected", false ); element.append( "" ); element.selectmenu( "refresh" ); - assert.equal( $.trim( button.text() ), "Selected option", "button text after adding selected option" ); + assert.equal( String.prototype.trim.call( button.text() ), "Selected option", "button text after adding selected option" ); ready(); } ); diff --git a/tests/unit/selectmenu/options.js b/tests/unit/selectmenu/options.js index 193ea688e88..4a070f4eb18 100644 --- a/tests/unit/selectmenu/options.js +++ b/tests/unit/selectmenu/options.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/selectmenu" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "selectmenu: options" ); +QUnit.module( "selectmenu: options", { afterEach: helper.moduleAfterEach } ); QUnit.test( "appendTo: null", function( assert ) { assert.expect( 1 ); diff --git a/tests/unit/slider/core.js b/tests/unit/slider/core.js index 8031367f0ba..933a68eff95 100644 --- a/tests/unit/slider/core.js +++ b/tests/unit/slider/core.js @@ -1,8 +1,10 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/slider" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; var element, options; @@ -11,7 +13,7 @@ function handle() { } // Slider Tests -QUnit.module( "slider: core" ); +QUnit.module( "slider: core", { afterEach: helper.moduleAfterEach } ); QUnit.test( "markup structure", function( assert ) { assert.expect( 4 ); @@ -67,7 +69,7 @@ QUnit.test( "keydown HOME on handle sets value to min", function( assert ) { element.slider( "value", 0 ); handle().simulate( "keydown", { keyCode: $.ui.keyCode.HOME } ); - assert.equal( element.slider( "value" ), options.min ) ; + assert.equal( element.slider( "value" ), options.min ); element.slider( "destroy" ); } ); @@ -86,7 +88,7 @@ QUnit.test( "keydown END on handle sets value to max", function( assert ) { element.slider( "value", 0 ); handle().simulate( "keydown", { keyCode: $.ui.keyCode.END } ); - assert.equal( element.slider( "value" ), options.max ) ; + assert.equal( element.slider( "value" ), options.max ); element.slider( "destroy" ); diff --git a/tests/unit/slider/events.js b/tests/unit/slider/events.js index d0459db64a4..3b283d28162 100644 --- a/tests/unit/slider/events.js +++ b/tests/unit/slider/events.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/slider" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "slider: events" ); +QUnit.module( "slider: events", { afterEach: helper.moduleAfterEach } ); //Specs from http://wiki.jqueryui.com/Slider#specs //"change callback: triggers when the slider has stopped moving and has a new @@ -123,16 +125,16 @@ QUnit.test( "mouse based interaction part two: when handles overlap", function( start: function( event, ui ) { assert.equal( handles.index( ui.handle ), 0, "leftmost handle activated when overlapping at maximum" ); } - } ), - handles = element.find( ".ui-slider-handle" ); + } ); + handles = element.find( ".ui-slider-handle" ); handles.eq( 0 ).simulate( "drag", { dx: -10 } ); element.slider( "destroy" ); element = $( "#slider1" ) .slider( { values: [ 19, 20 ] - } ), - handles = element.find( ".ui-slider-handle" ); + } ); + handles = element.find( ".ui-slider-handle" ); handles.eq( 0 ).simulate( "drag", { dx: 10 } ); element.one( "slidestart", function( event, ui ) { assert.equal( handles.index( ui.handle ), 0, "left handle activated if left was moved last" ); @@ -143,8 +145,8 @@ QUnit.test( "mouse based interaction part two: when handles overlap", function( element = $( "#slider1" ) .slider( { values: [ 19, 20 ] - } ), - handles = element.find( ".ui-slider-handle" ); + } ); + handles = element.find( ".ui-slider-handle" ); handles.eq( 1 ).simulate( "drag", { dx: -10 } ); element.one( "slidestart", function( event, ui ) { assert.equal( handles.index( ui.handle ), 1, "right handle activated if right was moved last (#3467)" ); @@ -157,8 +159,8 @@ QUnit.test( "mouse based interaction part two: when handles overlap", function( min: 0, max: 100, values: [ 0, 50 ] - } ), - handles = element.find( ".ui-slider-handle" ); + } ); + handles = element.find( ".ui-slider-handle" ); element.slider( "option", { values: [ 100, 100 ] } ); handles.eq( 0 ).simulate( "drag", { dx: -10 } ); diff --git a/tests/unit/slider/methods.js b/tests/unit/slider/methods.js index ea058cef22b..b6808c3b29b 100644 --- a/tests/unit/slider/methods.js +++ b/tests/unit/slider/methods.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/slider" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "slider: methods" ); +QUnit.module( "slider: methods", { afterEach: helper.moduleAfterEach } ); QUnit.test( "init", function( assert ) { assert.expect( 5 ); diff --git a/tests/unit/slider/options.js b/tests/unit/slider/options.js index d1eb2b374d6..40b6bab2214 100644 --- a/tests/unit/slider/options.js +++ b/tests/unit/slider/options.js @@ -1,8 +1,10 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/slider" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; var element, options; @@ -10,7 +12,7 @@ function handle() { return element.find( ".ui-slider-handle" ); } -QUnit.module( "slider: options" ); +QUnit.module( "slider: options", { afterEach: helper.moduleAfterEach } ); QUnit.test( "disabled", function( assert ) { assert.expect( 8 ); @@ -146,7 +148,7 @@ QUnit.test( "orientation", function( assert ) { assert.equal( element.find( ".ui-slider-handle" )[ 0 ].style.bottom, "", "CSS bottom reset" ); assert.equal( handle()[ 0 ].style.left, percentVal + "%", "horizontal slider handle is positioned with left: %" ); - element.slider( "destroy" ) ; + element.slider( "destroy" ); options = { max: 2, diff --git a/tests/unit/sortable/core.js b/tests/unit/sortable/core.js index 2bb11edbe2c..2224f04ecc4 100644 --- a/tests/unit/sortable/core.js +++ b/tests/unit/sortable/core.js @@ -1,11 +1,13 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/sortable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "sortable: core" ); +QUnit.module( "sortable: core", { afterEach: helper.moduleAfterEach } ); QUnit.test( "#9314: Sortable: Items cannot be dragged directly into bottom position", function( assert ) { assert.expect( 1 ); @@ -24,8 +26,8 @@ QUnit.test( "ui-sortable-handle applied to appropriate element", function( asser .sortable() .appendTo( "#qunit-fixture" ); - assert.hasClasses( el.find( "li:first" ), "ui-sortable-handle" ); - assert.hasClasses( el.find( "li:last" ), "ui-sortable-handle" ); + assert.hasClasses( el.find( "li" ).first(), "ui-sortable-handle" ); + assert.hasClasses( el.find( "li" ).last(), "ui-sortable-handle" ); el.sortable( "option", "handle", "p" ); assert.lacksClasses( el.find( "li" )[ 0 ], "ui-sortable-handle" ); @@ -34,10 +36,63 @@ QUnit.test( "ui-sortable-handle applied to appropriate element", function( asser assert.hasClasses( el.find( "p" )[ 1 ], "ui-sortable-handle" ); el.append( item ).sortable( "refresh" ); - assert.hasClasses( el.find( "p:last" ), "ui-sortable-handle" ); + assert.hasClasses( el.find( "p" ).last(), "ui-sortable-handle" ); el.sortable( "destroy" ); assert.equal( el.find( ".ui-sortable-handle" ).length, 0, "class name removed on destroy" ); } ); +// gh-1998 +QUnit.test( "drag & drop works with a zero-height container", function( assert ) { + var ready = assert.async(); + assert.expect( 3 ); + + var el = $( "
      \n" + + " \n" + + "
    • Item 1
    • \n" + + "
    • Item 2
    • \n" + + "
    • Item 3
    • \n" + + "
    " ) + .sortable() + .appendTo( "#qunit-fixture" ); + + function step1() { + el.find( "li" ).eq( 0 ).simulate( "drag", { + dx: 100, + dy: 3, + moves: 3 + } ); + setTimeout( step2 ); + } + + function step2() { + el.find( "li" ).eq( 2 ).simulate( "drag", { + dx: -200, + dy: -3, + moves: 3 + } ); + setTimeout( step3 ); + } + + function step3() { + assert.equal( el.find( "li" ).eq( 0 ).text(), "Item 3" ); + assert.equal( el.find( "li" ).eq( 1 ).text(), "Item 2" ); + assert.equal( el.find( "li" ).eq( 2 ).text(), "Item 1" ); + ready(); + } + + step1(); +} ); + } ); diff --git a/tests/unit/sortable/events.js b/tests/unit/sortable/events.js index 4973abef0bd..0e26603d29d 100644 --- a/tests/unit/sortable/events.js +++ b/tests/unit/sortable/events.js @@ -1,12 +1,14 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/sortable", "ui/widgets/draggable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "sortable: events" ); +QUnit.module( "sortable: events", { afterEach: helper.moduleAfterEach } ); QUnit.test( "start", function( assert ) { assert.expect( 7 ); @@ -16,7 +18,7 @@ QUnit.test( "start", function( assert ) { start: function( e, ui ) { hash = ui; } - } ).find( "li:eq(0)" ).simulate( "drag", { + } ).find( "li" ).eq( 0 ).simulate( "drag", { dy: 10 } ); @@ -39,7 +41,7 @@ QUnit.test( "sort", function( assert ) { sort: function( e, ui ) { hash = ui; } - } ).find( "li:eq(0)" ).simulate( "drag", { + } ).find( "li" ).eq( 0 ).simulate( "drag", { dy: 10 } ); @@ -61,7 +63,7 @@ QUnit.test( "change", function( assert ) { change: function( e, ui ) { hash = ui; } - } ).find( "li:eq(0)" ).simulate( "drag", { + } ).find( "li" ).eq( 0 ).simulate( "drag", { dx: 1, dy: 1 } ); @@ -72,7 +74,7 @@ QUnit.test( "change", function( assert ) { change: function( e, ui ) { hash = ui; } - } ).find( "li:eq(0)" ).simulate( "drag", { + } ).find( "li" ).eq( 0 ).simulate( "drag", { dy: 22 } ); @@ -94,7 +96,7 @@ QUnit.test( "beforeStop", function( assert ) { beforeStop: function( e, ui ) { hash = ui; } - } ).find( "li:eq(0)" ).simulate( "drag", { + } ).find( "li" ).eq( 0 ).simulate( "drag", { dy: 20 } ); @@ -116,7 +118,7 @@ QUnit.test( "stop", function( assert ) { stop: function( e, ui ) { hash = ui; } - } ).find( "li:eq(0)" ).simulate( "drag", { + } ).find( "li" ).eq( 0 ).simulate( "drag", { dy: 20 } ); @@ -138,7 +140,7 @@ QUnit.test( "update", function( assert ) { update: function( e, ui ) { hash = ui; } - } ).find( "li:eq(0)" ).simulate( "drag", { + } ).find( "li" ).eq( 0 ).simulate( "drag", { dx: 1, dy: 1 } ); @@ -149,7 +151,7 @@ QUnit.test( "update", function( assert ) { update: function( e, ui ) { hash = ui; } - } ).find( "li:eq(0)" ).simulate( "drag", { + } ).find( "li" ).eq( 0 ).simulate( "drag", { dy: 22 } ); @@ -182,7 +184,9 @@ QUnit.test( "#4752: link event firing on sortable with connect list", function( assert.expect( 10 ); var fired = {}, - hasFired = function( type ) { return ( type in fired ) && ( true === fired[ type ] ); }; + hasFired = function( type ) { + return ( type in fired ) && ( true === fired[ type ] ); + }; $( "#sortable" ).clone().attr( "id", "sortable2" ).insertAfter( "#sortable" ); @@ -203,13 +207,13 @@ QUnit.test( "#4752: link event firing on sortable with connect list", function( fired.click = true; } ); - $( "#sortable li:eq(0)" ).simulate( "click" ); + $( "#sortable li" ).eq( 0 ).simulate( "click" ); assert.ok( !hasFired( "change" ), "Click only, change event should not have fired" ); assert.ok( hasFired( "click" ), "Click event should have fired" ); // Drag an item within the first list fired = {}; - $( "#sortable li:eq(0)" ).simulate( "drag", { dx: 0, dy: 40 } ); + $( "#sortable li" ).eq( 0 ).simulate( "drag", { dx: 0, dy: 40 } ); assert.ok( hasFired( "change" ), "40px drag, change event should have fired" ); assert.ok( !hasFired( "receive" ), "Receive event should not have fired" ); assert.ok( !hasFired( "remove" ), "Remove event should not have fired" ); @@ -217,7 +221,7 @@ QUnit.test( "#4752: link event firing on sortable with connect list", function( // Drag an item from the first list to the second, connected list fired = {}; - $( "#sortable li:eq(0)" ).simulate( "drag", { dx: 0, dy: 150 } ); + $( "#sortable li" ).eq( 0 ).simulate( "drag", { dx: 0, dy: 150 } ); assert.ok( hasFired( "change" ), "150px drag, change event should have fired" ); assert.ok( hasFired( "receive" ), "Receive event should have fired" ); assert.ok( hasFired( "remove" ), "Remove event should have fired" ); @@ -245,7 +249,7 @@ QUnit.test( "over", function( assert ) { hash = ui; overCount++; } - } ).find( "li:eq(0)" ).simulate( "drag", { + } ).find( "li" ).eq( 0 ).simulate( "drag", { dy: 20 } ); @@ -301,7 +305,7 @@ QUnit.test( "over, with connected sortable", function( assert ) { hash = ui; overCount++; } ); - $( "#sortable" ).find( "li:eq(0)" ).simulate( "drag", { + $( "#sortable" ).find( "li" ).eq( 0 ).simulate( "drag", { dy: 102 } ); @@ -329,7 +333,7 @@ QUnit.test( "out, with connected sortable", function( assert ) { hash = ui; outCount++; } ); - $( "#sortable" ).find( "li:last" ).simulate( "drag", { + $( "#sortable" ).find( "li" ).last().simulate( "drag", { dy: 40 } ); @@ -357,7 +361,7 @@ QUnit.test( "repeated out & over between connected sortables", function( assert } } } ); - $( "#sortable" ).find( "li:last" ).simulate( "drag", { + $( "#sortable" ).find( "li" ).last().simulate( "drag", { dy: 40 } ).simulate( "drag", { dy: -40 diff --git a/tests/unit/sortable/methods.js b/tests/unit/sortable/methods.js index b52d641ed25..534dd53b1f4 100644 --- a/tests/unit/sortable/methods.js +++ b/tests/unit/sortable/methods.js @@ -1,11 +1,13 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/sortable" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; -QUnit.module( "sortable: methods" ); +QUnit.module( "sortable: methods", { afterEach: helper.moduleAfterEach } ); QUnit.test( "init", function( assert ) { assert.expect( 5 ); @@ -61,7 +63,7 @@ QUnit.test( "enable", function( assert ) { testHelper.sort( assert, $( "li", el )[ 0 ], 0, 44, 2, ".sortable('option', 'disabled', false)" ); - expected = $( "
    " ).sortable(), + expected = $( "
    " ).sortable(); actual = expected.sortable( "enable" ); assert.equal( actual, expected, "enable is chainable" ); } ); diff --git a/tests/unit/sortable/options.js b/tests/unit/sortable/options.js index fa0c487b720..0905de73cf1 100644 --- a/tests/unit/sortable/options.js +++ b/tests/unit/sortable/options.js @@ -1,10 +1,12 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/sortable" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "sortable: options" ); +QUnit.module( "sortable: options", { afterEach: helper.moduleAfterEach } ); /* Test("{ appendTo: 'parent' }, default", function() { @@ -104,6 +106,10 @@ QUnit.test( "#7415: Incorrect revert animation with axis: 'y'", function( assert var top = parseFloat( item.css( "top" ) ); assert.equal( item.css( "left" ), expectedLeft, "left not animated" ); assert.ok( top > 0 && top < 300, "top is animated" ); + + // Cleanup + item.stop( true ); + ready(); }, 100 ); } ); @@ -136,7 +142,7 @@ QUnit.test( "#8792: issues with floated items in connected lists", function( ass } } ); - element = $( "#qunit-fixture li:eq(0)" ); + element = $( "#qunit-fixture li" ).eq( 0 ); // Move the first li to the right of the second li in the first ul element.simulate( "drag", { @@ -255,15 +261,65 @@ test("{ dropOnEmpty: true }, default", function() { test("{ dropOnEmpty: false }", function() { ok(false, "missing test - untested code is broken code."); }); +*/ -test("{ forcePlaceholderSize: false }, default", function() { - ok(false, "missing test - untested code is broken code."); -}); +QUnit.test( "{ forcePlaceholderSize: false } table rows", function( assert ) { + assert.expect( 1 ); -test("{ forcePlaceholderSize: true }", function() { - ok(false, "missing test - untested code is broken code."); -}); + var element = $( "#sortable-table2 tbody" ); + + element.sortable( { + placeholder: "test", + forcePlaceholderSize: false, + start: function( event, ui ) { + assert.notEqual( ui.placeholder.height(), ui.item.height(), + "placeholder is same height as item" ); + } + } ); + + // This row has a non-standard height + $( "tr", element ).eq( 0 ).simulate( "drag", { + dy: 1 + } ); +} ); + +QUnit.test( "{ forcePlaceholderSize: true } table rows", function( assert ) { + assert.expect( 2 ); + + // Table should have the placeholder's height set the same as the row we're dragging + var element = $( "#sortable-table2 tbody" ), + jqMinor = $.fn.jquery.substring( 0, 4 ); + + element.sortable( { + placeholder: "test", + forcePlaceholderSize: true, + start: function( event, ui ) { + // Support: IE 11+, Edge <79 only + // In IE & Edge Legacy these values may differ a little + // when jQuery >=3.0 <3.2 is used. + if ( jqMinor === "3.0." || jqMinor === "3.1." ) { + assert.ok( Math.abs( ui.placeholder.height() - ui.item.height() ) < 0.25, + "placeholder height is within 0.25 px of item's" ); + } else { + assert.equal( ui.placeholder.height(), ui.item.height(), + "placeholder is same height as item" ); + } + } + } ); + + // First row has a non-standard height + $( "tr", element ).eq( 0 ).simulate( "drag", { + dy: 1 + } ); + + // Second row's height is normal + $( "tr", element ).eq( 1 ).simulate( "drag", { + dy: 1 + } ); +} ); + +/* test("{ forceHelperSize: false }, default", function() { ok(false, "missing test - untested code is broken code."); }); @@ -332,7 +388,8 @@ test("{ placeholder: false }, default", function() { QUnit.test( "{ placeholder: false } img", function( assert ) { assert.expect( 3 ); - var element = $( "#sortable-images" ).sortable( { + var done = assert.async(), + element = $( "#sortable-images" ).sortable( { start: function( event, ui ) { assert.ok( ui.placeholder.attr( "src" ).indexOf( "images/jqueryui_32x32.png" ) > 0, "placeholder img has correct src" ); assert.equal( ui.placeholder.height(), 32, "placeholder has correct height" ); @@ -340,9 +397,14 @@ QUnit.test( "{ placeholder: false } img", function( assert ) { } } ); - element.find( "img" ).eq( 0 ).simulate( "drag", { - dy: 1 - } ); + // Give browsers some time to load the image if cache is disabled. + // This resolves a frequent issue in Chrome/Safari. + setTimeout( function() { + element.find( "img" ).eq( 0 ).simulate( "drag", { + dy: 1 + } ); + done(); + }, 500 ); } ); QUnit.test( "{ placeholder: String }", function( assert ) { @@ -407,7 +469,7 @@ QUnit.test( "{ placholder: String } tbody", function( assert ) { assert.equal( ui.placeholder.children( "tr" ).length, 1, "placeholder's child is tr" ); assert.equal( ui.placeholder.find( "> tr" ).children().length, - dragBody.find( "> tr:first" ).children().length, + dragBody.find( "> tr" ).first().children().length, "placeholder's tr has correct number of cells" ); assert.equal( ui.placeholder.find( "> tr" ).children().html(), $( " " ).html(), @@ -426,6 +488,63 @@ QUnit.test( "{ placholder: String } tbody", function( assert ) { } ); } ); +// gh-2001 +// Sortable: Draggable items moved into a sortable had incorrect position +QUnit.test( "{ connectToSortable: Selector } positioning (gh-2001)", function( assert ) { + assert.expect( 1 ); + + // Code from jQuery Simulate with minor modifications. + function findCenter( elem ) { + var offset, + document = $( elem[ 0 ].ownerDocument ); + offset = elem.offset(); + + return { + x: Math.floor( offset.left + elem.outerWidth() / 2 - document.scrollLeft() ), + y: Math.floor( offset.top + elem.outerHeight() / 2 - document.scrollTop( ) ) + }; + } + + var sortableElem = $( "#sortable" ); + + sortableElem.css( "position", "relative" ); + + var item = $( "
    " ) + .text( "6" ) + .insertBefore( "#sortable" ); + + // Padding + $( "
    " ) + .css( { + width: "100px", + height: "100px" + } ) + .insertBefore( "#sortable" ); + + item.draggable( { + connectToSortable: "#sortable" + } ); + sortableElem.sortable(); + + // Simulate a drag without a drop. + var center = findCenter( item ); + item.simulate( "mousedown", { + clientX: center.x, + clientY: center.y + } ); + item.simulate( "mousemove", { + clientX: center.x, + clientY: center.y + 60 + } ); + item.simulate( "mousemove", { + clientX: center.x, + clientY: center.y + 120 + } ); + + assert.ok( item.offset().top > sortableElem.children().eq( 0 ).offset().top, + "Draggable offset correct after moving into a sortable" ); +} ); + /* Test("{ revert: false }, default", function() { ok(false, "missing test - untested code is broken code."); diff --git a/tests/unit/sortable/sortable.html b/tests/unit/sortable/sortable.html index 8bfbd337088..4ea5b0fc627 100644 --- a/tests/unit/sortable/sortable.html +++ b/tests/unit/sortable/sortable.html @@ -22,7 +22,8 @@ border-width: 0; height:19px; } - #sortable-table { + #sortable-table, + #sortable-table2 { width: 100%; } @@ -105,6 +106,24 @@ + + + + + + + + + + + + + + + + +
    1
    1
    1
    22
    33
    +
    diff --git a/tests/unit/spinner/core.js b/tests/unit/spinner/core.js index 6d817134ae1..e9f7bc3d218 100644 --- a/tests/unit/spinner/core.js +++ b/tests/unit/spinner/core.js @@ -1,13 +1,15 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/spinner" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var simulateKeyDownUp = testHelper.simulateKeyDownUp; -QUnit.module( "spinner: core" ); +QUnit.module( "spinner: core", { afterEach: helper.moduleAfterEach } ); QUnit.test( "markup structure", function( assert ) { assert.expect( 6 ); @@ -162,23 +164,39 @@ QUnit.test( "mouse click on up button, increases value not greater than max", fu } ); QUnit.test( "mousewheel on input", function( assert ) { - assert.expect( 4 ); + var ready = assert.async(); + assert.expect( 5 ); var element = $( "#spin" ).val( 0 ).spinner( { step: 2 } ); - element.trigger( "mousewheel" ); - assert.equal( element.val(), 0, "mousewheel event without delta does not change value" ); + element.simulate( "focus" ); + setTimeout( step1 ); - element.trigger( "mousewheel", 1 ); - assert.equal( element.val(), 2 ); + function step1() { + element.trigger( "mousewheel" ); + assert.equal( element.val(), 0, "mousewheel event without delta does not change value" ); - element.trigger( "mousewheel", -0.2 ); - assert.equal( element.val(), 0 ); + element.trigger( "mousewheel", 1 ); + assert.equal( element.val(), 2, "delta 1" ); + + element.trigger( "mousewheel", -0.2 ); + assert.equal( element.val(), 0, "delta -0.2" ); + + element.trigger( "mousewheel", -15 ); + assert.equal( element.val(), -2, "delta -15" ); - element.trigger( "mousewheel", -15 ); - assert.equal( element.val(), -2 ); + element.simulate( "blur" ); + setTimeout( step2 ); + } + + function step2() { + element.trigger( "mousewheel", 1 ); + assert.equal( element.val(), -2, "mousewheel when not focused" ); + + ready(); + } } ); QUnit.test( "reading HTML5 attributes", function( assert ) { diff --git a/tests/unit/spinner/deprecated.js b/tests/unit/spinner/deprecated.js index baa36acf340..79700d11608 100644 --- a/tests/unit/spinner/deprecated.js +++ b/tests/unit/spinner/deprecated.js @@ -1,8 +1,10 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/spinner" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; var originalSpinner = $.ui.spinner.prototype; QUnit.module( "spinner: deprecated", { @@ -26,6 +28,7 @@ QUnit.module( "spinner: deprecated", { afterEach: function() { $.ui.spinner.prototype = originalSpinner; + return helper.moduleAfterEach.apply( this, arguments ); } } ); diff --git a/tests/unit/spinner/events.js b/tests/unit/spinner/events.js index 9c69470ab3c..833b12adf73 100644 --- a/tests/unit/spinner/events.js +++ b/tests/unit/spinner/events.js @@ -1,13 +1,15 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/spinner" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var simulateKeyDownUp = testHelper.simulateKeyDownUp; -QUnit.module( "spinner: events" ); +QUnit.module( "spinner: events", { afterEach: helper.moduleAfterEach } ); QUnit.test( "start", function( assert ) { assert.expect( 10 ); diff --git a/tests/unit/spinner/methods.js b/tests/unit/spinner/methods.js index a7af2956db3..3ba8b69d16c 100644 --- a/tests/unit/spinner/methods.js +++ b/tests/unit/spinner/methods.js @@ -1,13 +1,15 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/spinner" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var simulateKeyDownUp = testHelper.simulateKeyDownUp; -QUnit.module( "spinner: methods" ); +QUnit.module( "spinner: methods", { afterEach: helper.moduleAfterEach } ); QUnit.test( "destroy", function( assert ) { assert.expect( 1 ); diff --git a/tests/unit/spinner/options.js b/tests/unit/spinner/options.js index 381e1b7fad6..51d8589fd31 100644 --- a/tests/unit/spinner/options.js +++ b/tests/unit/spinner/options.js @@ -1,30 +1,32 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widgets/spinner", "globalize", "globalize/ja-JP" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; -QUnit.module( "spinner: options" ); +QUnit.module( "spinner: options", { afterEach: helper.moduleAfterEach } ); // Culture is tested after numberFormat, since it depends on numberFormat QUnit.test( "icons: default ", function( assert ) { assert.expect( 4 ); var element = $( "#spin" ).val( 0 ).spinner(); - assert.hasClasses( element.spinner( "widget" ).find( ".ui-icon:first" ), + assert.hasClasses( element.spinner( "widget" ).find( ".ui-icon" ).first(), "ui-icon ui-icon-triangle-1-n" ); - assert.hasClasses( element.spinner( "widget" ).find( ".ui-icon:last" ), + assert.hasClasses( element.spinner( "widget" ).find( ".ui-icon" ).last(), "ui-icon ui-icon-triangle-1-s" ); element.spinner( "option", "icons", { up: "ui-icon-caret-1-n", down: "ui-icon-caret-1-s" } ); - assert.hasClasses( element.spinner( "widget" ).find( ".ui-icon:first" ), + assert.hasClasses( element.spinner( "widget" ).find( ".ui-icon" ).first(), "ui-icon ui-icon-caret-1-n" ); - assert.hasClasses( element.spinner( "widget" ).find( ".ui-icon:last" ), + assert.hasClasses( element.spinner( "widget" ).find( ".ui-icon" ).last(), "ui-icon ui-icon-caret-1-s" ); } ); @@ -36,8 +38,8 @@ QUnit.test( "icons: custom ", function( assert ) { up: "custom-up" } } ).spinner( "widget" ); - assert.hasClasses( element.find( ".ui-icon:first" ), "ui-icon custom-up" ); - assert.hasClasses( element.find( ".ui-icon:last" ), "ui-icon custom-down" ); + assert.hasClasses( element.find( ".ui-icon" ).first(), "ui-icon custom-up" ); + assert.hasClasses( element.find( ".ui-icon" ).last(), "ui-icon custom-down" ); } ); QUnit.test( "incremental, false", function( assert ) { diff --git a/tests/unit/subsuite.js b/tests/unit/subsuite.js index 0880c6fcd5c..8d594588cee 100644 --- a/tests/unit/subsuite.js +++ b/tests/unit/subsuite.js @@ -1,7 +1,7 @@ ( function() { +"use strict"; var versions = [ - "1.7.0", "1.7.1", "1.7.2", "1.8.0", "1.8.1", "1.8.2", "1.8.3", "1.9.0", "1.9.1", "1.10.0", "1.10.1", "1.10.2", @@ -11,8 +11,13 @@ var versions = [ "2.1.0", "2.1.1", "2.1.2", "2.1.3", "2.1.4", "2.2.0", "2.2.1", "2.2.2", "2.2.3", "2.2.4", "3.0.0", - "3.1.0", - "git", "custom" + "3.1.0", "3.1.1", + "3.2.0", "3.2.1", + "3.3.0", "3.3.1", + "3.4.0", "3.4.1", + "3.5.0", "3.5.1", + "3.6.0", + "3.x-git", "git", "custom" ], additionalTests = { @@ -29,4 +34,4 @@ window.testAllVersions = function( widget ) { } ) ); }; -}() ); +} )(); diff --git a/tests/unit/tabs/core.js b/tests/unit/tabs/core.js index f367b098e18..37dd3d4e301 100644 --- a/tests/unit/tabs/core.js +++ b/tests/unit/tabs/core.js @@ -1,13 +1,15 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/tabs" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var state = testHelper.state; -QUnit.module( "tabs: core" ); +QUnit.module( "tabs: core", { afterEach: helper.moduleAfterEach } ); QUnit.test( "markup structure", function( assert ) { assert.expect( 20 ); @@ -101,7 +103,7 @@ QUnit.test( "aria-controls", function( assert ) { } ); QUnit.test( "accessibility", function( assert ) { - assert.expect( 49 ); + assert.expect( 46 ); var element = $( "#tabs1" ).tabs( { active: 1, disabled: [ 2 ] @@ -118,7 +120,6 @@ QUnit.test( "accessibility", function( assert ) { panel = panels.eq( index ); assert.equal( tab.attr( "role" ), "tab", "tab " + index + " role" ); assert.equal( tab.attr( "aria-labelledby" ), anchorId, "tab " + index + " aria-labelledby" ); - assert.equal( anchor.attr( "role" ), "presentation", "anchor " + index + " role" ); assert.equal( anchor.attr( "tabindex" ), -1, "anchor " + index + " tabindex" ); assert.equal( panel.attr( "role" ), "tabpanel", "panel " + index + " role" ); assert.equal( panel.attr( "aria-labelledby" ), anchorId, "panel " + index + " aria-labelledby" ); @@ -187,7 +188,13 @@ QUnit.test( "keyboard support - LEFT, RIGHT, UP, DOWN, HOME, END, SPACE, ENTER", } ), tabs = element.find( ".ui-tabs-nav li" ), panels = element.find( ".ui-tabs-panel" ), - keyCode = $.ui.keyCode; + keyCode = $.ui.keyCode, + + // Support: IE 11 with jQuery 1.8. + // In IE with jQuery 1.8 focusout may not happen immediately so some checks + // need to be done later. + isFocusoutImmediate = !( document.documentMode && + jQuery.fn.jquery.indexOf( "1.8." ) === 0 ); element.tabs( "instance" ).delay = 1; @@ -202,7 +209,9 @@ QUnit.test( "keyboard support - LEFT, RIGHT, UP, DOWN, HOME, END, SPACE, ENTER", tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.DOWN } ); assert.hasClasses( tabs.eq( 1 ), "ui-state-focus", "DOWN moves focus to next tab" ); - assert.lacksClasses( tabs.eq( 0 ), "ui-state-focus", "first tab is no longer focused" ); + if ( isFocusoutImmediate ) { + assert.lacksClasses( tabs.eq( 0 ), "ui-state-focus", "first tab is no longer focused" ); + } assert.equal( tabs.eq( 1 ).attr( "aria-selected" ), "true", "second tab has aria-selected=true" ); assert.equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" ); assert.ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" ); @@ -247,6 +256,9 @@ QUnit.test( "keyboard support - LEFT, RIGHT, UP, DOWN, HOME, END, SPACE, ENTER", // Left, home, space function step2() { + if ( !isFocusoutImmediate ) { + assert.lacksClasses( tabs.eq( 0 ), "ui-state-focus", "first tab is no longer focused" ); + } assert.equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" ); assert.equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" ); assert.ok( panels.eq( 2 ).is( ":visible" ), "third panel is visible" ); @@ -663,4 +675,56 @@ QUnit.test( "#4033 - IE expands hash to full url and misinterprets tab as ajax", state( assert, element, 1 ); } ); + +QUnit.test( "extra listeners created when tabs are added/removed (trac-15136)", function( assert ) { + assert.expect( 3 ); + + var origRemoveListenersCount; + var element = $( "#tabs1" ).tabs(); + var tabCounter = 10; + + function addTab() { + var label = "Tab " + tabCounter; + var id = "tabs-" + tabCounter; + var li = $( + "
  • " + + " " + label + " " + + " Remove Tab" + + "
  • " + ); + var tabContentHtml = "Tab " + tabCounter + " content."; + + element.find( ".ui-tabs-nav" ).append( li ); + element.append( "

    " + tabContentHtml + "

    " ); + element.tabs( "refresh" ); + tabCounter++; + } + + function removeLastTab() { + element.find( ".ui-icon-close" ).last().trigger( "click" ); + } + + origRemoveListenersCount = jQuery._data( element[ 0 ], "events" ).remove.length; + + addTab(); + assert.equal( jQuery._data( element[ 0 ], "events" ).remove.length, + origRemoveListenersCount, + "No extra listeners after adding a new tab" ); + + addTab(); + addTab(); + addTab(); + assert.equal( jQuery._data( element[ 0 ], "events" ).remove.length, + origRemoveListenersCount, + "No extra listeners after adding multiple tabs" ); + + removeLastTab(); + removeLastTab(); + removeLastTab(); + removeLastTab(); + assert.equal( jQuery._data( element[ 0 ], "events" ).remove.length, + origRemoveListenersCount, + "No extra listeners after removing all the extra tabs" ); +} ); + } ); diff --git a/tests/unit/tabs/events.js b/tests/unit/tabs/events.js index 757e2bada0f..70510d7d653 100644 --- a/tests/unit/tabs/events.js +++ b/tests/unit/tabs/events.js @@ -1,13 +1,15 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/tabs" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var state = testHelper.state; -QUnit.module( "tabs: events" ); +QUnit.module( "tabs: events", { afterEach: helper.moduleAfterEach } ); QUnit.test( "create", function( assert ) { assert.expect( 10 ); diff --git a/tests/unit/tabs/methods.js b/tests/unit/tabs/methods.js index 138f84fca61..e447d762325 100644 --- a/tests/unit/tabs/methods.js +++ b/tests/unit/tabs/methods.js @@ -1,14 +1,16 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/tabs" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var disabled = testHelper.disabled, state = testHelper.state; -QUnit.module( "tabs: methods" ); +QUnit.module( "tabs: methods", { afterEach: helper.moduleAfterEach } ); QUnit.test( "destroy", function( assert ) { assert.expect( 2 ); diff --git a/tests/unit/tabs/options.js b/tests/unit/tabs/options.js index 3735038434d..774a24d1774 100644 --- a/tests/unit/tabs/options.js +++ b/tests/unit/tabs/options.js @@ -1,15 +1,17 @@ define( [ "qunit", "jquery", + "lib/helper", "./helper", "ui/widgets/tabs" -], function( QUnit, $, testHelper ) { +], function( QUnit, $, helper, testHelper ) { +"use strict"; var disabled = testHelper.disabled, equalHeight = testHelper.equalHeight, state = testHelper.state; -QUnit.module( "tabs: options" ); +QUnit.module( "tabs: options", { afterEach: helper.moduleAfterEach } ); QUnit.test( "{ active: default }", function( assert ) { assert.expect( 6 ); diff --git a/tests/unit/tooltip/core.js b/tests/unit/tooltip/core.js index 2de37097af1..a3eedbd6af0 100644 --- a/tests/unit/tooltip/core.js +++ b/tests/unit/tooltip/core.js @@ -1,10 +1,14 @@ define( [ "qunit", "jquery", + "./helper", "ui/widgets/tooltip" -], function( QUnit, $ ) { +], function( QUnit, $, testHelper ) { +"use strict"; -QUnit.module( "tooltip: core" ); +var beforeAfterEach = testHelper.beforeAfterEach; + +QUnit.module( "tooltip: core", beforeAfterEach() ); QUnit.test( "markup structure", function( assert ) { assert.expect( 7 ); @@ -250,4 +254,74 @@ QUnit.test( "remove conflicting attributes from live region", function( assert ) .tooltip( "open" ); } ); +// gh-1990 +QUnit.test( "don't crash on empty tooltip content", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + + var anchor = $( "#tooltipped1" ), + input = anchor.next(), + actions = []; + + $( document ).tooltip( { + show: false, + hide: false, + content: function() { + var title = $( this ).attr( "title" ); + if ( title === "inputtitle" ) { + return ""; + } + return title; + }, + open: function( event, ui ) { + actions.push( "open:" + ui.tooltip.text() ); + }, + close: function( event, ui ) { + actions.push( "close:" + ui.tooltip.text() ); + } + } ); + + function step1() { + anchor.simulate( "mouseover" ); + setTimeout( step2 ); + } + + function step2() { + anchor.simulate( "mouseout" ); + setTimeout( step3 ); + } + + function step3() { + input.simulate( "focus" ); + setTimeout( step4 ); + } + + function step4() { + input.simulate( "blur" ); + setTimeout( step5 ); + } + + function step5() { + anchor.simulate( "mouseover" ); + setTimeout( step6 ); + } + + function step6() { + anchor.simulate( "mouseout" ); + setTimeout( step7 ); + } + + function step7() { + assert.deepEqual( actions, [ + "open:anchortitle", + "close:anchortitle", + "open:anchortitle", + "close:anchortitle" + ], "Tooltip opens and closes without crashing" ); + ready(); + } + + step1(); +} ); + } ); diff --git a/tests/unit/tooltip/deprecated.js b/tests/unit/tooltip/deprecated.js index bce1a6c6ab5..4d3975e84b1 100644 --- a/tests/unit/tooltip/deprecated.js +++ b/tests/unit/tooltip/deprecated.js @@ -1,10 +1,14 @@ define( [ "qunit", "jquery", + "./helper", "ui/widgets/tooltip" -], function( QUnit, $ ) { +], function( QUnit, $, testHelper ) { +"use strict"; -QUnit.module( "tooltip: (deprecated) options" ); +var beforeAfterEach = testHelper.beforeAfterEach; + +QUnit.module( "tooltip: (deprecated) options", beforeAfterEach() ); QUnit.test( "tooltipClass", function( assert ) { assert.expect( 1 ); diff --git a/tests/unit/tooltip/events.js b/tests/unit/tooltip/events.js index 3fbb683a588..16d1e08cb46 100644 --- a/tests/unit/tooltip/events.js +++ b/tests/unit/tooltip/events.js @@ -1,10 +1,14 @@ define( [ "qunit", "jquery", + "./helper", "ui/widgets/tooltip" -], function( QUnit, $ ) { +], function( QUnit, $, testHelper ) { +"use strict"; -QUnit.module( "tooltip: events" ); +var beforeAfterEach = testHelper.beforeAfterEach; + +QUnit.module( "tooltip: events", beforeAfterEach() ); QUnit.test( "programmatic triggers", function( assert ) { assert.expect( 4 ); diff --git a/tests/unit/tooltip/helper.js b/tests/unit/tooltip/helper.js new file mode 100644 index 00000000000..8bc999157e6 --- /dev/null +++ b/tests/unit/tooltip/helper.js @@ -0,0 +1,30 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/tooltip" +], function( QUnit, $, helper ) { + "use strict"; + + return $.extend( helper, { + beforeAfterEach: function() { + return { + afterEach: function() { + var index, timer, + timers = jQuery.timers; + + jQuery.fx.stop(); + + for ( index = timers.length; index--; ) { + timer = timers[ index ]; + timer.anim.stop(); + timers.splice( index, 1 ); + } + + return helper.moduleAfterEach.apply( this, arguments ); + } + }; + } + } ); + +} ); diff --git a/tests/unit/tooltip/methods.js b/tests/unit/tooltip/methods.js index 6e0af2eb4b8..b7a512ad1f9 100644 --- a/tests/unit/tooltip/methods.js +++ b/tests/unit/tooltip/methods.js @@ -1,10 +1,14 @@ define( [ "qunit", "jquery", + "./helper", "ui/widgets/tooltip" -], function( QUnit, $ ) { +], function( QUnit, $, testHelper ) { +"use strict"; -QUnit.module( "tooltip: methods" ); +var beforeAfterEach = testHelper.beforeAfterEach; + +QUnit.module( "tooltip: methods", beforeAfterEach() ); QUnit.test( "destroy", function( assert ) { assert.expect( 3 ); diff --git a/tests/unit/tooltip/options.js b/tests/unit/tooltip/options.js index 4354d89b3c9..72a3cf8897c 100644 --- a/tests/unit/tooltip/options.js +++ b/tests/unit/tooltip/options.js @@ -1,10 +1,14 @@ define( [ "qunit", "jquery", + "./helper", "ui/widgets/tooltip" -], function( QUnit, $ ) { +], function( QUnit, $, testHelper ) { +"use strict"; -QUnit.module( "tooltip: options" ); +var beforeAfterEach = testHelper.beforeAfterEach; + +QUnit.module( "tooltip: options", beforeAfterEach() ); QUnit.test( "disabled: true", function( assert ) { assert.expect( 1 ); @@ -100,7 +104,7 @@ QUnit.test( "content: async callback loses focus before load", function( assert } ); QUnit.test( "content: change while open", function( assert ) { - assert.expect( 2 ) ; + assert.expect( 2 ); var element = $( "#tooltipped1" ).tooltip( { content: function() { return "old"; diff --git a/tests/unit/widget/animation.js b/tests/unit/widget/animation.js index bbd3ca854a1..11d141369a2 100644 --- a/tests/unit/widget/animation.js +++ b/tests/unit/widget/animation.js @@ -1,8 +1,10 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widget" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; QUnit.module( "widget animation", ( function() { var show = $.fn.show, @@ -26,9 +28,10 @@ QUnit.module( "widget animation", ( function() { $.fn.show = show; $.fn.fadeIn = fadeIn; $.fn.slideDown = slideDown; + return helper.moduleAfterEach.apply( this, arguments ); } }; -}() ) ); +} )() ); QUnit.test( "show: null", function( assert ) { var ready = assert.async(); diff --git a/tests/unit/widget/classes.js b/tests/unit/widget/classes.js index 28f61f272e6..609f9903202 100644 --- a/tests/unit/widget/classes.js +++ b/tests/unit/widget/classes.js @@ -1,8 +1,10 @@ define( [ "qunit", "jquery", + "lib/helper", "ui/widget" -], function( QUnit, $ ) { +], function( QUnit, $, helper ) { +"use strict"; QUnit.module( "widget factory classes", { beforeEach: function() { @@ -50,6 +52,7 @@ QUnit.module( "widget factory classes", { _destroy: function() { this.span.remove(); this.element.unwrap(); + return helper.moduleAfterEach.apply( this, arguments ); } } ); }, diff --git a/tests/unit/widget/core.js b/tests/unit/widget/core.js index d6bb3efb813..1054bf09228 100644 --- a/tests/unit/widget/core.js +++ b/tests/unit/widget/core.js @@ -2,8 +2,10 @@ define( [ "qunit", "jquery", "lib/common", + "lib/helper", "ui/widget" -], function( QUnit, $, common ) { +], function( QUnit, $, common, helper ) { +"use strict"; QUnit.module( "widget factory", { afterEach: function() { @@ -11,11 +13,10 @@ QUnit.module( "widget factory", { delete $.ui.testWidget; delete $.fn.testWidget; } + return helper.moduleAfterEach.apply( this, arguments ); } } ); -common.testJshint( "widget" ); - QUnit.test( "widget creation", function( assert ) { assert.expect( 5 ); var method, @@ -29,7 +30,7 @@ QUnit.test( "widget creation", function( assert ) { }; $.widget( "ui.testWidget", myPrototype ); - assert.ok( $.isFunction( $.ui.testWidget ), "constructor was created" ); + assert.ok( typeof $.ui.testWidget === "function", "constructor was created" ); assert.equal( typeof $.ui.testWidget.prototype, "object", "prototype was created" ); method = "_create"; $.ui.testWidget.prototype._create(); @@ -91,6 +92,18 @@ QUnit.test( "element normalization", function( assert ) { $.ui.testWidget(); } ); +QUnit.test( "contextless construction", function( assert ) { + assert.expect( 1 ); + var testWidget, + elem = $( "
    " ); + + $.widget( "ui.testWidget", {} ); + testWidget = $.ui.testWidget; + + testWidget( {}, elem ); + assert.ok( true, "No crash" ); +} ); + QUnit.test( "custom selector expression", function( assert ) { assert.expect( 1 ); var elem = $( "
    " ).appendTo( "#qunit-fixture" ); @@ -947,7 +960,7 @@ QUnit.test( "_on() with delegate", function( assert ) { this.element = { on: function( event, handler ) { assert.equal( event, "click.testWidget" + uuid ); - assert.ok( $.isFunction( handler ) ); + assert.ok( typeof handler === "function" ); }, trigger: $.noop }; @@ -956,7 +969,7 @@ QUnit.test( "_on() with delegate", function( assert ) { on: function( event, selector, handler ) { assert.equal( selector, "a" ); assert.equal( event, "click.testWidget" + uuid ); - assert.ok( $.isFunction( handler ) ); + assert.ok( typeof handler === "function" ); } }; }; @@ -969,7 +982,7 @@ QUnit.test( "_on() with delegate", function( assert ) { on: function( event, selector, handler ) { assert.equal( selector, "form fieldset > input" ); assert.equal( event, "change.testWidget" + uuid ); - assert.ok( $.isFunction( handler ) ); + assert.ok( typeof handler === "function" ); } }; }; @@ -1441,7 +1454,7 @@ QUnit.test( "._trigger() - instance as element", function( assert ) { .trigger( "remove" ); } ); } ); -}() ); +} )(); QUnit.test( "redefine", function( assert ) { assert.expect( 4 ); @@ -1608,7 +1621,7 @@ QUnit.test( "$.widget.bridge()", function( assert ) { $.widget.bridge( "testWidget", TestWidget ); - assert.ok( $.isFunction( $.fn.testWidget ), "jQuery plugin was created" ); + assert.ok( typeof $.fn.testWidget === "function", "jQuery plugin was created" ); assert.strictEqual( elem.testWidget( { foo: "bar" } ), elem, "plugin returns original jQuery object" ); instance = elem.data( "testWidget" ); diff --git a/tests/unit/widget/extend.js b/tests/unit/widget/extend.js index 36575200b61..ea2707ef39d 100644 --- a/tests/unit/widget/extend.js +++ b/tests/unit/widget/extend.js @@ -3,9 +3,10 @@ define( [ "jquery", "ui/widget" ], function( QUnit, $ ) { +"use strict"; QUnit.test( "$.widget.extend()", function( assert ) { - assert.expect( 27 ); + assert.expect( 28 ); var ret, empty, optionsWithLength, optionsWithDate, myKlass, customObject, optionsWithCustomObject, nullUndef, target, recursive, obj, input, output, @@ -75,7 +76,7 @@ QUnit.test( "$.widget.extend()", function( assert ) { assert.strictEqual( nullUndef.xnumber0, null, "Check to make sure null values are inserted" ); target = {}; - recursive = { foo:target, bar:5 }; + recursive = { foo: target, bar: 5 }; $.widget.extend( target, recursive ); assert.deepEqual( target, { foo: {}, bar: 5 }, "Check to make sure a recursive obj doesn't go never-ending loop by not copying it over" ); @@ -92,7 +93,7 @@ QUnit.test( "$.widget.extend()", function( assert ) { assert.strictEqual( ret.foo, null, "Make sure a null value doesn't crash with deep extend, for #1908" ); obj = { foo: null }; - $.widget.extend( obj, { foo:"notnull" } ); + $.widget.extend( obj, { foo: "notnull" } ); assert.equal( obj.foo, "notnull", "Make sure a null value can be overwritten" ); settings = $.widget.extend( {}, defaults, options1, options2 ); @@ -108,6 +109,11 @@ QUnit.test( "$.widget.extend()", function( assert ) { assert.deepEqual( input, output, "don't clone arrays" ); input.key[ 0 ] = 10; assert.deepEqual( input, output, "don't clone arrays" ); + + input = Object.create( null ); + input.foo = "f"; + output = $.widget.extend( {}, input ); + assert.deepEqual( input, output, "Object with no prototype" ); } ); } ); diff --git a/tests/visual/checkboxradio/checkboxradio.html b/tests/visual/checkboxradio/checkboxradio.html index a472c9df2fd..8d26daeff17 100644 --- a/tests/visual/checkboxradio/checkboxradio.html +++ b/tests/visual/checkboxradio/checkboxradio.html @@ -24,7 +24,7 @@ checkboxes.checkboxradio( "option", option, value ); } }); - $( ".controls > button" ).click( function() { + $( ".controls > button" ).on( "click", function() { if ( this.id !== "create" ) { checkboxes.checkboxradio( this.id ); } else { diff --git a/tests/visual/compound/draggable_resizable.html b/tests/visual/compound/draggable_resizable.html index 539091b7f4a..e2822ca199b 100644 --- a/tests/visual/compound/draggable_resizable.html +++ b/tests/visual/compound/draggable_resizable.html @@ -27,7 +27,7 @@ minHeight: 13, handles: "s" }); - $( ".draggable:last" ).addClass( "absolute" ); + $( ".draggable" ).last().addClass( "absolute" ); diff --git a/tests/visual/dialog/performance.html b/tests/visual/dialog/performance.html index 45ef9094175..065eacbbef8 100644 --- a/tests/visual/dialog/performance.html +++ b/tests/visual/dialog/performance.html @@ -7,7 +7,7 @@