1 |
(function( $ ) { |
2 |
|
3 |
var reset, jshintLoaded; |
4 |
|
5 |
window.TestHelpers = {}; |
6 |
|
7 |
function includeStyle( url ) { |
8 |
document.write( "<link rel='stylesheet' href='../../../" + url + "'>" ); |
9 |
} |
10 |
|
11 |
function includeScript( url ) { |
12 |
document.write( "<script src='../../../" + url + "'></script>" ); |
13 |
} |
14 |
|
15 |
function url( value ) { |
16 |
return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random() * 100000, 10); |
17 |
} |
18 |
|
19 |
reset = QUnit.reset; |
20 |
QUnit.reset = function() { |
21 |
// Ensure jQuery events and data on the fixture are properly removed |
22 |
jQuery("#qunit-fixture").empty(); |
23 |
// Let QUnit reset the fixture |
24 |
reset.apply( this, arguments ); |
25 |
}; |
26 |
|
27 |
|
28 |
QUnit.config.requireExpects = true; |
29 |
|
30 |
QUnit.config.urlConfig.push({ |
31 |
id: "min", |
32 |
label: "Minified source", |
33 |
tooltip: "Load minified source files instead of the regular unminified ones." |
34 |
}); |
35 |
|
36 |
TestHelpers.loadResources = QUnit.urlParams.min ? |
37 |
function() { |
38 |
includeStyle( "dist/jquery-ui.min.css" ); |
39 |
includeScript( "dist/jquery-ui.min.js" ); |
40 |
} : |
41 |
function( resources ) { |
42 |
$.each( resources.css || [], function( i, resource ) { |
43 |
includeStyle( "themes/base/jquery." + resource + ".css" ); |
44 |
}); |
45 |
$.each( resources.js || [], function( i, resource ) { |
46 |
includeScript( resource ); |
47 |
}); |
48 |
}; |
49 |
|
50 |
QUnit.config.urlConfig.push({ |
51 |
id: "nojshint", |
52 |
label: "Skip JSHint", |
53 |
tooltip: "Skip running JSHint, e.g. within TestSwarm, where Jenkins runs it already" |
54 |
}); |
55 |
|
56 |
jshintLoaded = false; |
57 |
TestHelpers.testJshint = function( module ) { |
58 |
if ( QUnit.urlParams.nojshint ) { |
59 |
return; |
60 |
} |
61 |
|
62 |
if ( !jshintLoaded ) { |
63 |
includeScript( "external/jshint.js" ); |
64 |
jshintLoaded = true; |
65 |
} |
66 |
|
67 |
asyncTest( "JSHint", function() { |
68 |
expect( 1 ); |
69 |
|
70 |
$.when( |
71 |
$.ajax({ |
72 |
url: url("../../../ui/.jshintrc"), |
73 |
dataType: "json" |
74 |
}), |
75 |
$.ajax({ |
76 |
url: url("../../../ui/jquery.ui." + module + ".js"), |
77 |
dataType: "text" |
78 |
}) |
79 |
).done(function( hintArgs, srcArgs ) { |
80 |
var globals, passed, errors, |
81 |
jshintrc = hintArgs[ 0 ], |
82 |
source = srcArgs[ 0 ]; |
83 |
|
84 |
globals = jshintrc.globals || {}; |
85 |
delete jshintrc.globals; |
86 |
passed = JSHINT( source, jshintrc, globals ), |
87 |
errors = $.map( JSHINT.errors, function( error ) { |
88 |
// JSHINT may report null if there are too many errors |
89 |
if ( !error ) { |
90 |
return; |
91 |
} |
92 |
|
93 |
return "[L" + error.line + ":C" + error.character + "] " + |
94 |
error.reason + "\n" + error.evidence + "\n"; |
95 |
}).join( "\n" ); |
96 |
ok( passed, errors ); |
97 |
start(); |
98 |
}) |
99 |
.fail(function() { |
100 |
ok( false, "error loading source" ); |
101 |
start(); |
102 |
}); |
103 |
}); |
104 |
}; |
105 |
|
106 |
function testWidgetDefaults( widget, defaults ) { |
107 |
var pluginDefaults = $.ui[ widget ].prototype.options; |
108 |
|
109 |
// ensure that all defaults have the correct value |
110 |
test( "defined defaults", function() { |
111 |
var count = 0; |
112 |
$.each( defaults, function( key, val ) { |
113 |
expect( ++count ); |
114 |
if ( $.isFunction( val ) ) { |
115 |
ok( $.isFunction( pluginDefaults[ key ] ), key ); |
116 |
return; |
117 |
} |
118 |
deepEqual( pluginDefaults[ key ], val, key ); |
119 |
}); |
120 |
}); |
121 |
|
122 |
// ensure that all defaults were tested |
123 |
test( "tested defaults", function() { |
124 |
var count = 0; |
125 |
$.each( pluginDefaults, function( key ) { |
126 |
expect( ++count ); |
127 |
ok( key in defaults, key ); |
128 |
}); |
129 |
}); |
130 |
} |
131 |
|
132 |
function testWidgetOverrides( widget ) { |
133 |
if ( $.uiBackCompat === false ) { |
134 |
test( "$.widget overrides", function() { |
135 |
expect( 4 ); |
136 |
$.each([ |
137 |
"_createWidget", |
138 |
"destroy", |
139 |
"option", |
140 |
"_trigger" |
141 |
], function( i, method ) { |
142 |
strictEqual( $.ui[ widget ].prototype[ method ], |
143 |
$.Widget.prototype[ method ], "should not override " + method ); |
144 |
}); |
145 |
}); |
146 |
} |
147 |
} |
148 |
|
149 |
function testBasicUsage( widget ) { |
150 |
test( "basic usage", function() { |
151 |
expect( 3 ); |
152 |
|
153 |
var defaultElement = $.ui[ widget ].prototype.defaultElement; |
154 |
$( defaultElement ).appendTo( "body" )[ widget ]().remove(); |
155 |
ok( true, "initialized on element" ); |
156 |
|
157 |
$( defaultElement )[ widget ]().remove(); |
158 |
ok( true, "initialized on disconnected DOMElement - never connected" ); |
159 |
|
160 |
$( defaultElement ).appendTo( "body" ).remove()[ widget ]().remove(); |
161 |
ok( true, "initialized on disconnected DOMElement - removed" ); |
162 |
}); |
163 |
} |
164 |
|
165 |
TestHelpers.commonWidgetTests = function( widget, settings ) { |
166 |
module( widget + ": common widget" ); |
167 |
|
168 |
TestHelpers.testJshint( widget ); |
169 |
testWidgetDefaults( widget, settings.defaults ); |
170 |
testWidgetOverrides( widget ); |
171 |
testBasicUsage( widget ); |
172 |
test( "version", function() { |
173 |
expect( 1 ); |
174 |
ok( "version" in $.ui[ widget ].prototype, "version property exists" ); |
175 |
}); |
176 |
}; |
177 |
|
178 |
/* |
179 |
* Taken from https://github.com/jquery/qunit/tree/master/addons/close-enough |
180 |
*/ |
181 |
window.closeEnough = function( actual, expected, maxDifference, message ) { |
182 |
var passes = (actual === expected) || Math.abs(actual - expected) <= maxDifference; |
183 |
QUnit.push(passes, actual, expected, message); |
184 |
}; |
185 |
|
186 |
/* |
187 |
* Experimental assertion for comparing DOM objects. |
188 |
* |
189 |
* Serializes an element and some properties and attributes and it's children if any, otherwise the text. |
190 |
* Then compares the result using deepEqual. |
191 |
*/ |
192 |
window.domEqual = function( selector, modifier, message ) { |
193 |
var expected, actual, |
194 |
properties = [ |
195 |
"disabled", |
196 |
"readOnly" |
197 |
], |
198 |
attributes = [ |
199 |
"autocomplete", |
200 |
"aria-activedescendant", |
201 |
"aria-controls", |
202 |
"aria-describedby", |
203 |
"aria-disabled", |
204 |
"aria-expanded", |
205 |
"aria-haspopup", |
206 |
"aria-hidden", |
207 |
"aria-labelledby", |
208 |
"aria-pressed", |
209 |
"aria-selected", |
210 |
"aria-valuemax", |
211 |
"aria-valuemin", |
212 |
"aria-valuenow", |
213 |
"class", |
214 |
"href", |
215 |
"id", |
216 |
"nodeName", |
217 |
"role", |
218 |
"tabIndex", |
219 |
"title" |
220 |
]; |
221 |
|
222 |
function getElementStyles( elem ) { |
223 |
var key, len, |
224 |
style = elem.ownerDocument.defaultView ? |
225 |
elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : |
226 |
elem.currentStyle, |
227 |
styles = {}; |
228 |
|
229 |
if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { |
230 |
len = style.length; |
231 |
while ( len-- ) { |
232 |
key = style[ len ]; |
233 |
if ( typeof style[ key ] === "string" ) { |
234 |
styles[ $.camelCase( key ) ] = style[ key ]; |
235 |
} |
236 |
} |
237 |
// support: Opera, IE <9 |
238 |
} else { |
239 |
for ( key in style ) { |
240 |
if ( typeof style[ key ] === "string" ) { |
241 |
styles[ key ] = style[ key ]; |
242 |
} |
243 |
} |
244 |
} |
245 |
|
246 |
return styles; |
247 |
} |
248 |
|
249 |
function extract( elem ) { |
250 |
if ( !elem || !elem.length ) { |
251 |
QUnit.push( false, actual, expected, |
252 |
"domEqual failed, can't extract " + selector + ", message was: " + message ); |
253 |
return; |
254 |
} |
255 |
|
256 |
var children, |
257 |
result = {}; |
258 |
$.each( properties, function( index, attr ) { |
259 |
var value = elem.prop( attr ); |
260 |
result[ attrĀ ] = value !== undefined ? value : ""; |
261 |
}); |
262 |
$.each( attributes, function( index, attr ) { |
263 |
var value = elem.attr( attr ); |
264 |
result[ attrĀ ] = value !== undefined ? value : ""; |
265 |
}); |
266 |
result.style = getElementStyles( elem[ 0 ] ); |
267 |
result.events = $._data( elem[ 0 ], "events" ); |
268 |
result.data = $.extend( {}, elem.data() ); |
269 |
delete result.data[ $.expando ]; |
270 |
children = elem.children(); |
271 |
if ( children.length ) { |
272 |
result.children = elem.children().map(function() { |
273 |
return extract( $( this ) ); |
274 |
}).get(); |
275 |
} else { |
276 |
result.text = elem.text(); |
277 |
} |
278 |
return result; |
279 |
} |
280 |
|
281 |
function done() { |
282 |
actual = extract( $( selector ) ); |
283 |
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); |
284 |
} |
285 |
|
286 |
// Get current state prior to modifier |
287 |
expected = extract( $( selector ) ); |
288 |
|
289 |
// Run modifier (async or sync), then compare state via done() |
290 |
if ( modifier.length ) { |
291 |
modifier( done ); |
292 |
} else { |
293 |
modifier(); |
294 |
done(); |
295 |
} |
296 |
}; |
297 |
|
298 |
}( jQuery )); |