2 * mediaWiki JavaScript library test suite
4 * Available on Special:BlankPage?action=mwutiltest&debug=true
6 * @author Krinkle <krinklemail@gmail.com>
15 // contains either a header or a test
16 // test: [ code, result, contain ] see addTest
17 // header: [ 'HEADER', escapedtitle, id ] see addHead
25 * Adds a row to the test-table
27 * @param code String Code of the test to be executed
28 * @param result String Expected result in 'var (vartype)' form
29 * @param contain String Important part of the result,
30 * if result is different but does contain this it will not return ERROR but PARTIALLY
32 'addTest' : function( code
, result
, contain
) {
36 this.addedTests
.push( [code
, result
, contain
] );
37 this.$table
.append( '<tr class="mw-mwutiltest-test">'
38 + '<td>' + mw
.html
.escape( code
).replace( / /g
, ' ' )
39 + '</td><td>' + mw
.html
.escape( result
).replace( / /g
, ' ' )
40 + '</td><td></td><td>?</td></tr>' );
45 * Adds a heading to the test-table
47 * @param title String Title of the section
49 'addHead' : function( title
) {
53 var escapedtitle
= mw
.html
.escape( title
).replace( / /g
, ' ' );
54 this.addedTests
.push( [ 'HEADER', escapedtitle
, mw
.test
.numberOfHeader
++ ] );
56 '<tr class="mw-mwutiltest-head" id="mw-mwutiltest-head'
57 + mw
.test
.numberOfHeader
+ '"><th colspan="4">'
58 + escapedtitle
+ '</th></tr>'
64 'initialised' : false,
66 if ( this.initialised
=== false ) {
67 this.initialised
= true;
69 $(document
).ready( function() {
70 if ( mw
.config
.get( 'wgCanonicalSpecialPageName' ) == 'Blankpage'
71 && mw
.util
.getParamValue( 'action' ) === 'mwutiltest' ) {
74 document
.title
= 'mediaWiki JavaScript library test suite - ' + mw
.config
.get( 'wgSiteName' );
75 $( '#firstHeading' ).text( 'mediaWiki JavaScript library test suite' );
76 var skinLinksHtml
= 'Test in: ',
78 availableSkins
= mw
.config
.get( 'wgAvailableSkins' ),
80 for ( skincode
in availableSkins
) {
84 'href': mw
.util
.wikiGetlink( mw
.config
.get( 'wgPageName' ) )
85 + '?action=mwutiltest&debug=true&useskin=' + encodeURIComponent( skincode
)
87 availableSkins
[skincode
]
91 skinLinksHtml
+= skinLinks
.join( ' | ' ) + '.';
92 mw
.util
.$content
.html(
93 '<p>Below is a list of tests to confirm proper functionality of the mediaWiki JavaScript library</p>'
94 + '<p>' + skinLinksHtml
+ '</p>'
96 + '<table id="mw-mwutiltest-table" class="wikitable"'
97 + ' style="white-space:break; font-family:monospace,\'Courier New\'; width:100%;">'
98 + '<tr><th>Exec</th><th>Should return</th><th>Does return</th><th>Equal ?</th></tr>'
103 // Override wikitable padding for <td>
104 '#mw-mwutiltest-table tr td { padding:0 !important; }'
107 mw
.test
.$table
= $( 'table#mw-mwutiltest-table' );
110 // Try to roughly keep the order similar to the order in the files
111 // or alphabetical (depending on the context)
113 /** Main modules and their aliases **/
114 mw
.test
.addHead( 'Main modules and their aliases' );
116 mw
.test
.addTest( 'typeof mediaWiki',
119 mw
.test
.addTest( 'typeof mw',
122 mw
.test
.addTest( 'typeof jQuery',
123 'function (string)' );
125 mw
.test
.addTest( 'typeof $',
126 'function (string)' );
128 /** Prototype functions added by MediaWiki **/
129 mw
.test
.addHead( 'Prototype functions added by MediaWiki' );
131 mw
.test
.addTest( 'typeof $.trimLeft',
132 'function (string)' );
134 mw
.test
.addTest( '$.trimLeft( " foo bar " )',
135 'foo bar (string)' );
137 mw
.test
.addTest( 'typeof $.trimRight',
138 'function (string)' );
140 mw
.test
.addTest( '$.trimRight( " foo bar " )',
141 ' foo bar (string)' );
143 mw
.test
.addTest( 'typeof $.ucFirst',
144 'function (string)' );
146 mw
.test
.addTest( '$.ucFirst( "mediawiki" )',
147 'Mediawiki (string)' );
149 mw
.test
.addTest( 'typeof $.escapeRE',
150 'function (string)' );
152 mw
.test
.addTest( '$.escapeRE( "<!-- ([{+mW+}]) $^|?>" )',
153 '<!\\-\\- \\(\\[\\{\\+mW\\+\\}\\]\\) \\$\\^\\|\\?> (string)' ); // double escaped
155 mw
.test
.addTest( '$.escapeRE( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" )',
156 'ABCDEFGHIJKLMNOPQRSTUVWXYZ (string)' );
158 mw
.test
.addTest( '$.escapeRE( "abcdefghijklmnopqrstuvwxyz" )',
159 'abcdefghijklmnopqrstuvwxyz (string)' );
161 mw
.test
.addTest( '$.escapeRE( "0123456789" )',
162 '0123456789 (string)' );
164 mw
.test
.addTest( '$.isDomElement( document.getElementById("mw-mwutiltest-table") )',
167 mw
.test
.addTest( '$.isDomElement( document.getElementById("not-existant-id") )',
168 'false (boolean)' ); // returns null
170 mw
.test
.addTest( '$.isDomElement( document.getElementsByClassName("wikitable") )',
171 'false (boolean)' ); // returns an array
173 mw
.test
.addTest( '$.isDomElement( document.getElementsByClassName("wikitable")[0] )',
176 mw
.test
.addTest( '$.isDomElement( jQuery( "#mw-mwutiltest-table" ) )',
177 'false (boolean)' ); // returns jQuery object
179 mw
.test
.addTest( '$.isDomElement( jQuery( "#mw-mwutiltest-table" ).get(0) )',
182 mw
.test
.addTest( '$.isDomElement( document.createElement( "div" ) )',
185 mw
.test
.addTest( '$.isDomElement( {some: "thing" } )',
188 mw
.test
.addTest( 'typeof $.isEmpty',
189 'function (string)' );
191 mw
.test
.addTest( '$.isEmpty( "string" )',
194 mw
.test
.addTest( '$.isEmpty( "0" )',
197 mw
.test
.addTest( '$.isEmpty([])',
200 mw
.test
.addTest( 'typeof $.compareArray',
201 'function (string)' );
203 mw
.test
.addTest( '$.compareArray( [1, "a", [], [2, "b"] ], [1, "a", [], [2, "b"] ] )',
206 mw
.test
.addTest( '$.compareArray( [1], [2] )',
209 mw
.test
.addTest( 'typeof $.compareObject',
210 'function (string)' );
213 mw
.test
.addHead( 'mediawiki.js' );
215 mw
.test
.addTest( 'mw.config instanceof mw.Map',
218 mw
.test
.addTest( 'mw.config.exists()',
221 mw
.test
.addTest( 'mw.config.exists( "wgSomeName" )',
224 mw
.test
.addTest( 'mw.config.exists( ["wgCanonicalNamespace", "wgTitle"] )',
227 mw
.test
.addTest( 'mw.config.exists( ["wgSomeName", "wgTitle"] )',
230 mw
.test
.addTest( 'mw.config.get( "wgCanonicalNamespace" )',
231 'Special (string)' );
233 mw
.test
.addTest( 'var a = mw.config.get( ["wgCanonicalNamespace"] ); a.wgCanonicalNamespace',
234 'Special (string)' );
236 mw
.test
.addTest( 'typeof mw.html',
239 mw
.test
.addTest( 'mw.html.escape( \'<mw awesome="awesome">\' )',
240 '<mw awesome="awesome"> (string)' );
242 mw
.test
.addTest( 'mw.html.element( "hr" )',
245 mw
.test
.addTest( 'mw.html.element( "img", { "src": "http://mw.org/?title=Main page&action=edit" } )',
246 '<img src="http://mw.org/?title=Main page&action=edit"/> (string)' );
248 mw
.test
.addTest( 'typeof mw.loader',
251 mw
.test
.addTest( 'typeof mw.loader.using',
252 'function (string)' );
254 mw
.test
.addTest( 'typeof mw.Map',
255 'function (string)' );
257 mw
.test
.addTest( 'typeof mw.user',
260 mw
.test
.addTest( 'typeof mw.user.anonymous()',
261 'boolean (string)' );
263 /** mediawiki.util.js **/
264 mw
.test
.addHead( 'mediawiki.util.js' );
266 mw
.test
.addTest( 'typeof mw.util',
269 mw
.test
.addTest( 'typeof mw.util.rawurlencode',
270 'function (string)' );
272 mw
.test
.addTest( 'mw.util.rawurlencode( "Test:A & B/Here" )',
273 'Test%3AA%20%26%20B%2FHere (string)' );
275 mw
.test
.addTest( 'typeof mw.util.wikiUrlencode',
276 'function (string)' );
278 mw
.test
.addTest( 'mw.util.wikiUrlencode( "Test:A & B/Here" )',
279 'Test:A_%26_B/Here (string)' );
281 mw
.test
.addTest( 'typeof mw.util.addCSS',
282 'function (string)' );
284 mw
.test
.addTest( 'var a = mw.util.addCSS( "div#mw-js-message { background-color: rgb(170,255,170); }" ); a.disabled',
287 mw
.test
.addTest( 'typeof mw.util.toggleToc',
288 'function (string)' );
290 mw
.test
.addTest( 'typeof mw.util.wikiGetlink',
291 'function (string)' );
293 mw
.test
.addTest( 'typeof mw.util.getParamValue',
294 'function (string)' );
296 mw
.test
.addTest( 'mw.util.getParamValue( "action" )',
297 'mwutiltest (string)' );
299 mw
.test
.addTest( 'mw.util.getParamValue( "foo", "http://mw.org/?foo=wrong&foo=right#&foo=bad" )',
302 mw
.test
.addTest( 'typeof mw.util.tooltipAccessKeyPrefix',
305 mw
.test
.addTest( 'mw.util.tooltipAccessKeyRegexp.constructor.name',
308 mw
.test
.addTest( 'typeof mw.util.updateTooltipAccessKeys',
309 'function (string)' );
311 mw
.test
.addTest( 'mw.util.$content instanceof jQuery',
314 mw
.test
.addTest( 'mw.util.$content.size()',
317 mw
.test
.addTest( 'typeof mw.util.addPortletLink',
318 'function (string)' );
320 mw
.test
.addTest( 'typeof mw.util.addPortletLink( "p-tb", "http://mediawiki.org/wiki/ResourceLoader", "ResourceLoader", "t-rl", "More info about ResourceLoader on MediaWiki.org ", "l", "#t-specialpages" )',
323 mw
.test
.addTest( 'var a = mw.util.addPortletLink( "p-tb", "http://mediawiki.org/", "MediaWiki.org", "t-mworg", "Go to MediaWiki.org ", "m", "#t-rl" ); $(a).text();',
324 'MediaWiki.org (string)' );
326 mw
.test
.addTest( 'typeof mw.util.addPortletLink( "p-tb", "http://www.mediawiki.org/wiki/ResourceLoader/Default_modules", "Default modules", "t-rl", "All default modules present in MediaWiki" )',
329 mw
.test
.addTest( 'typeof mw.util.jsMessage',
330 'function (string)' );
332 mw
.test
.addTest( 'mw.util.jsMessage( mw.config.get( "wgSiteName" ) + " is <b>Awesome</b>." )',
335 mw
.test
.addTest( 'jQuery( "#mw-js-message" ).css( "background-color" )',
336 'rgb(170, 255, 170) (string)' );
338 // TODO: Import tests from PHPUnit test suite for user::isValidEmailAddr
339 mw
.test
.addTest( 'mw.util.validateEmail( "" )',
342 mw
.test
.addTest( 'mw.util.validateEmail( "user@localhost" )',
345 // testEmailWithCommasAreInvalids
346 mw
.test
.addTest( 'mw.util.validateEmail( "user,foo@example.org" )',
348 mw
.test
.addTest( 'mw.util.validateEmail( "userfoo@ex,ample.org" )',
350 // testEmailWithHyphens
351 mw
.test
.addTest( 'mw.util.validateEmail( "user-foo@example.org" )',
353 mw
.test
.addTest( 'mw.util.validateEmail( "userfoo@ex-ample.org" )',
356 // From IPTest.php IPv6
357 mw
.test
.addTest( 'mw.util.isIPv6Address( "" )',
359 mw
.test
.addTest( 'mw.util.isIPv6Address( ":fc:100::" )',
361 mw
.test
.addTest( 'mw.util.isIPv6Address( "fc:100::" )',
363 mw
.test
.addTest( 'mw.util.isIPv6Address( "fc:100:a:d:1:e:ac::" )',
365 mw
.test
.addTest( 'mw.util.isIPv6Address( ":::" )',
367 mw
.test
.addTest( 'mw.util.isIPv6Address( "::0:" )',
370 // From IPTest.php IPv4
371 mw
.test
.addTest( 'mw.util.isIPv4Address( "" )',
373 mw
.test
.addTest( 'mw.util.isIPv4Address( "...." )',
375 mw
.test
.addTest( 'mw.util.isIPv4Address( "abc" )',
377 mw
.test
.addTest( 'mw.util.isIPv4Address( "124.24.52" )',
379 mw
.test
.addTest( 'mw.util.isIPv4Address( ".24.52.13" )',
381 mw
.test
.addTest( 'mw.util.isIPv4Address( "124.24.52.13" )',
383 mw
.test
.addTest( 'mw.util.isIPv4Address( "1.24.52.13" )',
385 mw
.test
.addTest( 'mw.util.isIPv4Address( "74.24.52.13/20" )', // Range
387 // @FIXME: The regex that's been in MW JS has never supported ranges but it should
388 // The regex is expected to return false for that reason
391 mw
.test
.addHead( 'jQuery plugins' );
393 mw
.test
.addTest( 'typeof $.client',
396 mw
.test
.addTest( 'typeof $.client.profile',
397 'function (string)' );
399 mw
.test
.addTest( 'var a = $.client.profile(); typeof a.name',
402 mw
.test
.addTest( 'typeof $.fn.makeCollapsible',
403 'function (string)' );
407 mw
.test
.addHead( '*** End of tests ***' );
409 // Run tests and compare results
415 numberOfPartials
= 0,
417 headNumberOfTests
= 0,
418 headNumberOfPasseds
= 0,
419 headNumberOfPartials
= 0,
420 headNumberOfErrors
= 0,
422 previousHeadTitle
= '',
423 $testrows
= mw
.test
.$table
.find( 'tr:has(td)' );
425 $.each( mw
.test
.addedTests
, function( i
, item
) {
428 if( item
[0] == 'HEADER' ) {
430 // update current header with its tests results
431 mw
.test
.$table
.find( 'tr#mw-mwutiltest-head' + numberOfHeaders
+' > th' )
432 .html( previousHeadTitle
+ ' <span style="float:right">('
433 + 'Tests: ' + headNumberOfTests
434 + ' OK: ' + headNumberOfPasseds
435 + ' Partial: ' + headNumberOfPartials
436 + ' Error: ' + headNumberOfErrors
440 // Reset values for the new header;
441 headNumberOfTests
= 0;
442 headNumberOfPasseds
= 0;
443 headNumberOfPartials
= 0;
444 headNumberOfErrors
= 0;
446 previousHeadTitle
= item
[1];
452 var shouldreturn
= item
[1];
453 var shouldcontain
= item
[2];
458 var doesReturn
= eval( exec
);
460 mw
.log ('mw.util.test> ' + e
);
462 doesReturn
= doesReturn
+ ' (' + typeof doesReturn
+ ')';
463 var $thisrow
= $testrows
.eq( i
- numberOfHeaders
); // since headers are rows as well
464 $thisrow
.find( '> td' )
466 .html( mw
.html
.escape( doesReturn
).replace(/ /g
, ' ' ) );
468 if ( doesReturn
.indexOf( shouldcontain
) !== -1 ) {
469 if ( doesReturn
== shouldreturn
) {
470 $thisrow
.find( '>td' ).eq(3).css( 'background', '#AFA' ).text( 'OK' );
472 headNumberOfPasseds
++;
474 $thisrow
.find( '>td' ).eq(3).css( 'background', '#FFA' ).html( '<small>PARTIALLY</small>' );
476 headNumberOfPartials
++;
479 $thisrow
.css( 'background', '#FAA' ).find( '>td' ).eq(3).text( 'ERROR' );
481 headNumberOfErrors
++;
485 mw
.test
.$table
.before( '<p><strong>Ran ' + numberOfTests
+ ' tests. ' +
486 numberOfPasseds
+ ' passed test(s). ' + numberOfErrors
+ ' error(s). ' +
487 numberOfPartials
+ ' partially passed test(s). </p>' );
497 } )(jQuery
, mediaWiki
);