Skip to content
Permalink
Browse files

Tests: Ensure no timers are running at the end of each test (#1920)

This helps fix issues that make tooltip tests sometimes fail when run against
jQuery 3.2 or newer due to timing differences.

Details:
* Add the `moduleAfterEach` function ensuring no timers are running.
* Attach this function via `common.testWidget`.
* Attach this function to most test suites.
* Add a tooltip test helper cleaning up leftover timers.
* Rename legacy `setup`/`teardown` hooks to `beforeEach`/`afterEach`.

Closes gh-1920
  • Loading branch information
mgol committed May 16, 2020
1 parent f4ef03e commit e7a10c70ae75c741992afdda60a433be205fd85e
Showing with 352 additions and 175 deletions.
  1. +4 −3 tests/lib/common.js
  2. +24 −1 tests/lib/helper.js
  3. +2 −2 tests/unit/accordion/core.js
  4. +2 −2 tests/unit/accordion/events.js
  5. +4 −3 tests/unit/accordion/helper.js
  6. +2 −2 tests/unit/accordion/methods.js
  7. +2 −2 tests/unit/accordion/options.js
  8. +3 −2 tests/unit/autocomplete/core.js
  9. +3 −2 tests/unit/autocomplete/events.js
  10. +3 −2 tests/unit/autocomplete/methods.js
  11. +3 −2 tests/unit/autocomplete/options.js
  12. +3 −2 tests/unit/button/core.js
  13. +5 −4 tests/unit/button/deprecated.js
  14. +3 −2 tests/unit/button/events.js
  15. +3 −2 tests/unit/button/methods.js
  16. +3 −2 tests/unit/button/options.js
  17. +3 −2 tests/unit/checkboxradio/core.js
  18. +3 −2 tests/unit/checkboxradio/events.js
  19. +3 −2 tests/unit/checkboxradio/methods.js
  20. +3 −2 tests/unit/checkboxradio/options.js
  21. +5 −4 tests/unit/controlgroup/core.js
  22. +3 −2 tests/unit/controlgroup/methods.js
  23. +3 −2 tests/unit/controlgroup/options.js
  24. +3 −2 tests/unit/core/core.js
  25. +3 −2 tests/unit/core/selector.js
  26. +4 −2 tests/unit/datepicker/core.js
  27. +3 −1 tests/unit/datepicker/events.js
  28. +6 −0 tests/unit/datepicker/helper.js
  29. +3 −1 tests/unit/datepicker/methods.js
  30. +3 −1 tests/unit/datepicker/options.js
  31. +4 −3 tests/unit/dialog/core.js
  32. +3 −2 tests/unit/dialog/deprecated.js
  33. +1 −1 tests/unit/dialog/events.js
  34. +3 −1 tests/unit/dialog/methods.js
  35. +3 −2 tests/unit/dialog/options.js
  36. +3 −2 tests/unit/draggable/core.js
  37. +3 −1 tests/unit/draggable/events.js
  38. +3 −1 tests/unit/draggable/methods.js
  39. +6 −2 tests/unit/draggable/options.js
  40. +3 −2 tests/unit/droppable/core.js
  41. +3 −2 tests/unit/droppable/events.js
  42. +3 −2 tests/unit/droppable/methods.js
  43. +3 −2 tests/unit/droppable/options.js
  44. +5 −4 tests/unit/effects/core.js
  45. +3 −2 tests/unit/effects/scale.js
  46. +3 −1 tests/unit/form-reset-mixin/core.js
  47. +3 −2 tests/unit/menu/core.js
  48. +4 −2 tests/unit/menu/events.js
  49. +4 −2 tests/unit/menu/methods.js
  50. +4 −2 tests/unit/menu/options.js
  51. +4 −2 tests/unit/position/core.js
  52. +3 −2 tests/unit/progressbar/core.js
  53. +3 −2 tests/unit/progressbar/events.js
  54. +3 −2 tests/unit/progressbar/methods.js
  55. +3 −2 tests/unit/progressbar/options.js
  56. +3 −2 tests/unit/resizable/core.js
  57. +3 −2 tests/unit/resizable/events.js
  58. +3 −2 tests/unit/resizable/methods.js
  59. +3 −2 tests/unit/resizable/options.js
  60. +1 −1 tests/unit/selectable/events.js
  61. +3 −2 tests/unit/selectable/methods.js
  62. +3 −2 tests/unit/selectable/options.js
  63. +3 −2 tests/unit/selectmenu/core.js
  64. +4 −2 tests/unit/selectmenu/events.js
  65. +3 −2 tests/unit/selectmenu/methods.js
  66. +3 −2 tests/unit/selectmenu/options.js
  67. +3 −2 tests/unit/slider/core.js
  68. +3 −2 tests/unit/slider/events.js
  69. +3 −2 tests/unit/slider/methods.js
  70. +3 −2 tests/unit/slider/options.js
  71. +3 −2 tests/unit/sortable/core.js
  72. +3 −2 tests/unit/sortable/events.js
  73. +3 −2 tests/unit/sortable/methods.js
  74. +7 −2 tests/unit/sortable/options.js
  75. +3 −2 tests/unit/spinner/core.js
  76. +3 −1 tests/unit/spinner/deprecated.js
  77. +3 −2 tests/unit/spinner/events.js
  78. +3 −2 tests/unit/spinner/methods.js
  79. +3 −2 tests/unit/spinner/options.js
  80. +3 −2 tests/unit/tabs/core.js
  81. +3 −2 tests/unit/tabs/events.js
  82. +3 −2 tests/unit/tabs/methods.js
  83. +3 −2 tests/unit/tabs/options.js
  84. +5 −2 tests/unit/tooltip/core.js
  85. +5 −2 tests/unit/tooltip/deprecated.js
  86. +5 −2 tests/unit/tooltip/events.js
  87. +31 −0 tests/unit/tooltip/helper.js
  88. +5 −2 tests/unit/tooltip/methods.js
  89. +5 −2 tests/unit/tooltip/options.js
  90. +3 −1 tests/unit/widget/animation.js
  91. +3 −1 tests/unit/widget/classes.js
  92. +3 −1 tests/unit/widget/core.js
@@ -1,7 +1,8 @@
define( [
"qunit",
"jquery" ],
function( QUnit, $ ) {
"jquery",
"lib/helper"
], function( QUnit, $, helper ) {

var exports = {};

@@ -66,7 +67,7 @@ function testBasicUsage( widget ) {
}

exports.testWidget = function( widget, settings ) {
QUnit.module( widget + ": common widget" );
QUnit.module( widget + ": common widget", { afterEach: helper.moduleAfterEach } );

exports.testJshint( "/widgets/" + widget );
testWidgetDefaults( widget, settings.defaults );
@@ -2,7 +2,12 @@ define( [
"jquery"
], function( $ ) {

var exports = {};
var exports = {},

// Store the old count so that we only assert on tests that have actually leaked,
// instead of asserting every time a test has leaked sometime in the past
oldActive = 0,
splice = [].splice;

exports.forceScrollableWindow = function( appendTo ) {

@@ -28,6 +33,24 @@ exports.onFocus = function( element, onFocus ) {
element.on( "focus", fn )[ 0 ].focus();
};

/**
* Ensures that tests have cleaned up properly after themselves. Should be passed as the
* afterEach function on all modules' lifecycle object.
*/
exports.moduleAfterEach = function( assert ) {

// Check for (and clean up, if possible) incomplete animations/requests/etc.
if ( jQuery.timers && jQuery.timers.length !== 0 ) {
assert.equal( jQuery.timers.length, 0, "No timers are still running" );
splice.call( jQuery.timers, 0, jQuery.timers.length );
jQuery.fx.stop();
}
if ( jQuery.active !== undefined && jQuery.active !== oldActive ) {
assert.equal( jQuery.active, oldActive, "No AJAX requests are still active" );
oldActive = jQuery.active;
}
};

return exports;

} );
@@ -5,10 +5,10 @@ define( [
"ui/widgets/accordion"
], function( QUnit, $, testHelper ) {

var setupTeardown = testHelper.setupTeardown,
var beforeAfterEach = testHelper.beforeAfterEach,
state = testHelper.state;

QUnit.module( "accordion: core", setupTeardown() );
QUnit.module( "accordion: core", beforeAfterEach() );

$.each( { div: "#list1", ul: "#navigation", dl: "#accordion-dl" }, function( type, selector ) {
QUnit.test( "markup structure: " + type, function( assert ) {
@@ -5,10 +5,10 @@ define( [
"ui/widgets/accordion"
], function( QUnit, $, testHelper ) {

var setupTeardown = testHelper.setupTeardown,
var beforeAfterEach = testHelper.beforeAfterEach,
state = testHelper.state;

QUnit.module( "accordion: events", setupTeardown() );
QUnit.module( "accordion: events", beforeAfterEach() );

QUnit.test( "create", function( assert ) {
assert.expect( 10 );
@@ -12,14 +12,15 @@ return $.extend( helper, {
} );
},

setupTeardown: function() {
beforeAfterEach: function() {
var animate = $.ui.accordion.prototype.options.animate;
return {
setup: function() {
beforeEach: function() {
$.ui.accordion.prototype.options.animate = false;
},
teardown: function() {
afterEach: function() {
$.ui.accordion.prototype.options.animate = animate;
return helper.moduleAfterEach.apply( this, arguments );
}
};
},
@@ -6,10 +6,10 @@ define( [
], function( QUnit, $, testHelper ) {

var equalHeight = testHelper.equalHeight,
setupTeardown = testHelper.setupTeardown,
beforeAfterEach = testHelper.beforeAfterEach,
state = testHelper.state;

QUnit.module( "accordion: methods", setupTeardown() );
QUnit.module( "accordion: methods", beforeAfterEach() );

QUnit.test( "destroy", function( assert ) {
assert.expect( 1 );
@@ -6,10 +6,10 @@ define( [
], function( QUnit, $, testHelper ) {

var equalHeight = testHelper.equalHeight,
setupTeardown = testHelper.setupTeardown,
beforeAfterEach = testHelper.beforeAfterEach,
state = testHelper.state;

QUnit.module( "accordion: options", setupTeardown() );
QUnit.module( "accordion: options", beforeAfterEach() );

QUnit.test( "{ active: default }", function( assert ) {
assert.expect( 2 );
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/autocomplete"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "autocomplete: core" );
QUnit.module( "autocomplete: core", { afterEach: helper.moduleAfterEach } );

QUnit.test( "markup structure", function( assert ) {
assert.expect( 2 );
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/autocomplete"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "autocomplete: events" );
QUnit.module( "autocomplete: events", { afterEach: helper.moduleAfterEach } );

var data = [ "Clojure", "COBOL", "ColdFusion", "Java", "JavaScript", "Scala", "Scheme" ];

@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/autocomplete"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "autocomplete: methods" );
QUnit.module( "autocomplete: methods", { afterEach: helper.moduleAfterEach } );

QUnit.test( "destroy", function( assert ) {
assert.expect( 1 );
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/autocomplete"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "autocomplete: options" );
QUnit.module( "autocomplete: options", { afterEach: helper.moduleAfterEach } );

var data = [ "c++", "java", "php", "coldfusion", "javascript", "asp", "ruby",
"python", "c", "scala", "groovy", "haskell", "perl" ];
@@ -1,11 +1,12 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/safe-active-element",
"ui/widgets/button"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Button: core" );
QUnit.module( "Button: core", { afterEach: helper.moduleAfterEach } );

QUnit.test( "Disabled button loses focus", function( assert ) {
var ready = assert.async();
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/button"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Button (deprecated): core" );
QUnit.module( "Button (deprecated): core", { afterEach: helper.moduleAfterEach } );

QUnit.test( "Calling button on a checkbox input calls checkboxradio widget", function( assert ) {
var checkbox = $( "#checkbox01" );
@@ -27,7 +28,7 @@ QUnit.test( "Calling buttonset calls controlgroup", function( assert ) {
assert.ok( controlgroup.is( ":ui-controlgroup" ), "Calling buttonset creates controlgroup instance" );
} );

QUnit.module( "Button (deprecated): methods" );
QUnit.module( "Button (deprecated): methods", { afterEach: helper.moduleAfterEach } );

QUnit.test( "destroy", function( assert ) {
assert.expect( 1 );
@@ -59,7 +60,7 @@ QUnit.test( "refresh: Ensure disabled state is preserved correctly.", function(

} );

QUnit.module( "button (deprecated): options" );
QUnit.module( "button (deprecated): options", { afterEach: helper.moduleAfterEach } );

QUnit.test( "Setting items option on buttonset sets the button properties on the items option", function( assert ) {
assert.expect( 2 );
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/button"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Button: events" );
QUnit.module( "Button: events", { afterEach: helper.moduleAfterEach } );

QUnit.test( "Anchor recieves click event when spacebar is pressed", function( assert ) {
var ready = assert.async();
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/button"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Button: methods" );
QUnit.module( "Button: methods", { afterEach: helper.moduleAfterEach } );

QUnit.test( "destroy", function( assert ) {
assert.expect( 1 );
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/button"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "button: options" );
QUnit.module( "button: options", { afterEach: helper.moduleAfterEach } );

QUnit.test( "disabled, explicit value", function( assert ) {
assert.expect( 8 );
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/checkboxradio"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Checkboxradio: core" );
QUnit.module( "Checkboxradio: core", { afterEach: helper.moduleAfterEach } );

QUnit.test( "Checkbox - Initial class structure", function( assert ) {
assert.expect( 2 );
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/checkboxradio"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Checkboxradio: events" );
QUnit.module( "Checkboxradio: events", { afterEach: helper.moduleAfterEach } );

QUnit.test(
"Resetting a checkbox's form should refresh the visual state of the checkbox",
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/checkboxradio"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Checkboxradio: methods" );
QUnit.module( "Checkboxradio: methods", { afterEach: helper.moduleAfterEach } );

$.each( [ "checkbox", "radio" ], function( index, value ) {
QUnit.test( value + ": refresh", function( assert ) {
@@ -1,10 +1,11 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/checkboxradio"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Checkboxradio: options" );
QUnit.module( "Checkboxradio: options", { afterEach: helper.moduleAfterEach } );

function assertDisabled( checkbox, assert ) {
assert.hasClasses( checkbox.checkboxradio( "widget" ), "ui-state-disabled",
@@ -1,14 +1,15 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/controlgroup",
"ui/widgets/checkboxradio",
"ui/widgets/selectmenu",
"ui/widgets/button",
"ui/widgets/spinner"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Controlgroup: Core" );
QUnit.module( "Controlgroup: Core", { afterEach: helper.moduleAfterEach } );

QUnit.test( "selectmenu: open/close corners", function( assert ) {
assert.expect( 12 );
@@ -161,12 +162,12 @@ QUnit.test( "Single controlgroup button - vertical", function( assert ) {
} );

QUnit.module( "Controlgroup: Non-empty class key", {
setup: function() {
beforeEach: function() {
this.classKey = $.ui.selectmenu.prototype.options.classes[ "ui-selectmenu-button-closed" ];
$.ui.selectmenu.prototype.options.classes[ "ui-selectmenu-button-closed" ] =
"something-custom";
},
teardown: function() {
afterEach: function() {
$.ui.selectmenu.prototype.options.classes[ "ui-selectmenu-button-closed" ] = this.classKey;
}
} );
@@ -1,14 +1,15 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/controlgroup",
"ui/widgets/checkboxradio",
"ui/widgets/selectmenu",
"ui/widgets/button",
"ui/widgets/spinner"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Controlgroup: methods" );
QUnit.module( "Controlgroup: methods", { afterEach: helper.moduleAfterEach } );

QUnit.test( "destroy", function( assert ) {
assert.expect( 1 );
@@ -1,14 +1,15 @@
define( [
"qunit",
"jquery",
"lib/helper",
"ui/widgets/controlgroup",
"ui/widgets/checkboxradio",
"ui/widgets/selectmenu",
"ui/widgets/button",
"ui/widgets/spinner"
], function( QUnit, $ ) {
], function( QUnit, $, helper ) {

QUnit.module( "Controlgroup: options" );
QUnit.module( "Controlgroup: options", { afterEach: helper.moduleAfterEach } );

QUnit.test( "disabled", function( assert ) {
assert.expect( 4 );

0 comments on commit e7a10c7

Please sign in to comment.
You can’t perform that action at this time.