Continue implementation QUnit/TestSwarm integration (bug 28915)
authorKrinkle <krinkle@users.mediawiki.org>
Thu, 12 May 2011 01:34:07 +0000 (01:34 +0000)
committerKrinkle <krinkle@users.mediawiki.org>
Thu, 12 May 2011 01:34:07 +0000 (01:34 +0000)
--
For now static html files. I have considered using load.php calls, and tried an in-wiki SpecialPage. However in order for versioned testing to work in TestSwarm it must be possible to do a checkout of a revision, alias or put it in a web-acccesible directory (eg. domain/tmp-svn/r1234/resources/test) and it must work right away (without needing database or LocalConfig or permission rules to avoid the wiki being modified).

For that reason I chose for a static html page for now.

Right now it loads mediawiki.js and mediawiki.util.js modules and I created complete tests for these modules.

resources/test/index.html [new file with mode: 0644]
resources/test/unit/main.css [new file with mode: 0644]
resources/test/unit/mediawiki.util/mediawiki.util.js [new file with mode: 0644]
resources/test/unit/mediawiki/mediawiki.js [new file with mode: 0644]

diff --git a/resources/test/index.html b/resources/test/index.html
new file mode 100644 (file)
index 0000000..7255234
--- /dev/null
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<head>
+       <title>MediaWiki JavaScript Test Suite</title>
+
+       <!-- MediaWiki Includes -->
+       <meta name="ResourceLoaderDynamicStyles" content="" /> 
+
+       <script src="../jquery/jquery.js"></script>
+
+       <script> function startUp(){} </script>
+       <script src="../mediawiki/mediawiki.js"></script>
+       <script> mw.config = new mw.Map( false ); </script>
+
+       <script src="../jquery/jquery.checkboxShiftClick.js"></script>
+       <script src="../jquery/jquery.client.js"></script>
+       <script src="../jquery/jquery.cookie.js"></script>
+       <script src="../jquery/jquery.messageBox.js"></script>
+       <script src="../jquery/jquery.makeCollapsible.js"></script>
+       <script src="../jquery/jquery.placeholder.js"></script>
+       <script src="../jquery/jquery.tablesorter.js"></script>
+       <script src="../mediawiki.util/mediawiki.util.js"></script>
+
+       <!-- QUnit dependancies and scripts -->
+       <link rel="stylesheet" href="../jquery/jquery.qunit.css" />
+       <script src="../jquery/jquery.qunit.js"></script>
+
+       <!-- Your tests styles go here -->
+       <link rel="stylesheet" href="unit/main.css" />
+
+       <!-- Your test suites go here -->
+       <script src="unit/mediawiki/mediawiki.js"></script>
+       <script src="unit/mediawiki.util/mediawiki.util.js"></script>
+
+       <!-- TestSwarm -->
+       <!-- <script src="http://testswarm.wikimedia.org/js/inject.js"></script> -->
+</head>
+<body>
+       <h1 id="qunit-header">MediaWiki JavaScript Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+
+<div id="mw-content">
+       <div id="bodyContent"></div>
+       <div id="mw-panel">
+               <div id="p-tb" class="portal">
+                       <ul class="body">
+                               <li id="t-specialpages"><a href="#">Special pages</a></li>
+                       </ul>
+               </div>
+       </div>
+</div>
+</body>
+</html>
diff --git a/resources/test/unit/main.css b/resources/test/unit/main.css
new file mode 100644 (file)
index 0000000..b4b24e1
--- /dev/null
@@ -0,0 +1,5 @@
+/* Hide mediawiki elements */
+div#mw-js-message,
+#mw-content {
+       display: none !important;
+}
\ No newline at end of file
diff --git a/resources/test/unit/mediawiki.util/mediawiki.util.js b/resources/test/unit/mediawiki.util/mediawiki.util.js
new file mode 100644 (file)
index 0000000..b5be0b3
--- /dev/null
@@ -0,0 +1,109 @@
+module( 'mediawiki.util.js' );
+
+test( '-- Initial check', function(){
+
+       ok( mw.util, 'mw.util defined' );
+
+});
+
+test( 'rawurlencode', function(){
+
+       equals( mw.util.rawurlencode( 'Test:A & B/Here' ), 'Test%3AA%20%26%20B%2FHere' );
+
+});
+
+test( 'wikiUrlencode', function(){
+
+       equals( mw.util.wikiUrlencode( 'Test:A & B/Here' ), 'Test:A_%26_B/Here' );
+
+});
+
+test( 'addCSS', function(){
+
+       var a = mw.util.addCSS( '#bodyContent { background-color: rgb(170, 255, 170); }' );
+       ok(  a, 'function works' );
+       same( a.disabled, false, 'property "disabled" is available and set to false' );
+       
+       var $b = $('#bodyContent');
+       equals( $b.css('background-color'), 'rgb(170, 255, 170)', 'Style color matches.' );
+
+});
+
+test( 'toggleToc', function(){
+
+       ok( mw.util.toggleToc );
+
+});
+
+test( 'wikiGetlink', function(){
+
+       // Not part of startUp module
+       mw.config.set( 'wgArticlePath', '/wiki/$1' );
+
+       var hrefA = mw.util.wikiGetlink( 'Sandbox' );
+       
+       equals( hrefA, '/wiki/Sandbox', 'Simple title; Get link for "Sandbox"' );
+
+       var hrefB = mw.util.wikiGetlink( 'Foo:Sandbox ? 5+5=10 ! (test)/subpage' );
+       
+       equals( hrefB, '/wiki/Foo:Sandbox_%3F_5%2B5%3D10_%21_%28test%29/subpage', 'Advanced title; Get link for "Foo:Sandbox ? 5+5=10 ! (test)/subpage"' );
+
+});
+
+test( 'getParamValue', function(){
+
+       equals( mw.util.getParamValue( 'foo', 'http://mediawiki.org/?foo=wrong&foo=right#&foo=bad' ), 'right', 'Use latest one, ignore hash' );
+       same( mw.util.getParamValue( 'bar', 'http://mediawiki.org/?foo=right' ), null, 'Return null when not found' );
+
+});
+
+test( 'tooltipAccessKey', function(){
+
+       equals( typeof mw.util.tooltipAccessKeyPrefix, 'string', 'mw.util.tooltipAccessKeyPrefix must be a string' );
+       ok( mw.util.tooltipAccessKeyRegexp instanceof RegExp, 'mw.util.tooltipAccessKeyRegexp instance of RegExp' );
+       ok( mw.util.updateTooltipAccessKeys, 'mw.util.updateTooltipAccessKeys' );
+
+});
+
+test( '$content', function(){
+
+       ok( mw.util.$content instanceof jQuery, 'mw.util.$content instance of jQuery' );
+       same( mw.util.$content.length, 1, 'mw.util.$content must have length of 1' );
+
+});
+
+test( 'addPortletLink', function(){
+
+       var a = mw.util.addPortletLink( 'p-tb', 'http://mediawiki.org/wiki/ResourceLoader', 'ResourceLoader', 't-rl', 'More info about ResourceLoader on MediaWiki.org ', 'l', '#t-specialpages' );
+       
+       ok( $.isDomElement(a), 'addPortletLink returns a DomElement' );
+       
+       var b = mw.util.addPortletLink( "p-tb", "http://mediawiki.org/", "MediaWiki.org", "t-mworg", "Go to MediaWiki.org ", "m", "#t-rl" );
+       
+       equals( $(a).text(), 'ResourceLoader', 'Link contains correct text' );
+       equals( $(b).next().text(), 'ResourceLoader', 'Link was inserted in correct nextnode position' );
+
+});
+
+test( 'jsMessage', function(){
+
+       var a = mw.util.jsMessage( "MediaWiki is <b>Awesome</b>." );
+
+       ok( a, 'Basic return value checking' );
+
+});
+
+test( 'validateEmail', function(){
+
+       same( mw.util.validateEmail( "" ), null, 'Empty string should return null' );
+       same( mw.util.validateEmail( "user@localhost" ), true );
+
+       // testEmailWithCommasAreInvalids
+       same( mw.util.validateEmail( "user,foo@example.org" ), false, 'Comma' );
+       same( mw.util.validateEmail( "userfoo@ex,ample.org" ), false, 'Comma' );
+
+       // testEmailWithHyphens
+       same( mw.util.validateEmail( "user-foo@example.org" ), true, 'Hyphen' );
+       same( mw.util.validateEmail( "userfoo@ex-ample.org" ), true, 'Hyphen' );
+
+});
diff --git a/resources/test/unit/mediawiki/mediawiki.js b/resources/test/unit/mediawiki/mediawiki.js
new file mode 100644 (file)
index 0000000..2e75b72
--- /dev/null
@@ -0,0 +1,169 @@
+module( 'mediawiki.js' );
+
+test( '-- Initial check', function(){
+
+       ok( window.jQuery, 'jQuery defined' );
+       ok( window.$j, '$j defined' );
+       equals( window.$j, window.jQuery, '$j alias to jQuery' );
+
+       ok( window.mediaWiki, 'mediaWiki defined' );
+       ok( window.mw, 'mw defined' );
+       equals( window.mw, window.mediaWiki, 'mw alias to mediaWiki' );
+
+});
+
+test( 'jQuery.extend', function(){
+
+       equals( $j.trimLeft( '  foo bar  ' ), 'foo bar  ', 'trimLeft' );
+       equals( $j.trimRight( '  foo bar  ' ), '  foo bar', 'trimRight' );
+       equals( $j.ucFirst( 'foo'), 'Foo', 'ucFirst' );
+
+       equals( $j.escapeRE( '<!-- ([{+mW+}]) $^|?>' ),
+        '<!\\-\\- \\(\\[\\{\\+mW\\+\\}\\]\\) \\$\\^\\|\\?>', 'escapeRE - Escape specials' );
+       equals( $j.escapeRE( 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ),
+        'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'escapeRE - Leave uppercase alone' );
+       equals( $j.escapeRE( 'abcdefghijklmnopqrstuvwxyz' ),
+        'abcdefghijklmnopqrstuvwxyz', 'escapeRE - Leave lowercase alone' );
+       equals( $j.escapeRE( '0123456789' ), '0123456789', 'escapeRE - Leave numbers alone' );
+
+       same( $j.isDomElement( document.getElementById( 'qunit-header' ) ), true,
+        'isDomElement: #qunit-header Node' );
+       same( $j.isDomElement( document.getElementById( 'random-name' ) ), false,
+        'isDomElement: #random-name (null)' );
+       same( $j.isDomElement( document.getElementsByTagName( 'div' ) ), false,
+        'isDomElement: getElementsByTagName Array' );
+       same( $j.isDomElement( document.getElementsByTagName( 'div' )[0] ), true,
+        'isDomElement: getElementsByTagName(..)[0] Node' );
+       same( $j.isDomElement( $j( 'div' ) ), false,
+        'isDomElement: jQuery object' );
+       same( $j.isDomElement( $j( 'div' ).get(0) ), true,
+        'isDomElement: jQuery object > Get node' );
+       same( $j.isDomElement( document.createElement( 'div' ) ), true,
+        'isDomElement: createElement' );
+       same( $j.isDomElement( { foo: 1 } ), false,
+        'isDomElement: Object' );
+
+       equals( $j.isEmpty( 'string' ), false, 'isEmptry: "string"' );
+       equals( $j.isEmpty( '0' ), true, 'isEmptry: "0"' );
+       equals( $j.isEmpty( [] ), true, 'isEmptry: []' );
+       equals( $j.isEmpty( {} ), true, 'isEmptry: {}' );
+       // Documented behaviour
+       equals( $j.isEmpty( { length: 0 } ), true, 'isEmptry: { length: 0 }' );
+
+       ok( $j.compareArray( [0, 'a', [], [2, 'b'] ], [0, "a", [], [2, "b"] ] ),
+        'compareArray: Two the same deep arrays' );
+       ok( !$j.compareArray( [1], [2] ), 'compareArray: Two different arrays' );
+
+       ok( $j.compareObject( {}, {} ), 'compareObject: Two empty objects' );
+       ok( $j.compareObject( { foo: 1 }, { foo: 1 } ), 'compareObject: Two the same objects' );
+       ok( !$j.compareObject( { bar: true }, { baz: false } ),
+        'compareObject: Two different objects' );
+       
+});
+
+test( 'mw.Map / mw.config', function(){
+
+       ok( mw.config instanceof mw.Map, 'mw.config instance of mw.Map' );
+       ok( mw.config.get, 'get' );
+       ok( mw.config.set, 'set' );
+       ok( mw.config.exists, 'exists' );
+
+       ok( !mw.config.exists( 'lipsum' ), 'exists: lipsum (inexistant)' );
+       ok( mw.config.set( 'lipsum', 'Lorem ipsum' ), 'set: lipsum' );
+       ok( mw.config.exists( 'lipsum' ), 'exists: lipsum (existant)' );
+
+       equals( mw.config.get( 'lipsum' ), 'Lorem ipsum', 'get: lipsum' );
+       equals( mw.config.get( ['lipsum'] ).lipsum, 'Lorem ipsum', 'get: lipsum (multiple)' );
+
+});
+
+test( 'mw.message / mw.msg / mw.messages', function(){
+       ok( mw.message, 'mw.message defined' );
+       ok( mw.msg, 'mw.msg defined' );
+       ok( mw.messages, 'messages defined' );
+       ok( mw.messages instanceof mw.Map, 'mw.messages instance of mw.Map' );
+       ok( mw.messages.set( 'hello', 'Hello <b>awesome</b> world' ), 'mw.messages.set: Register' );
+
+       var hello = mw.message( 'hello' );
+       ok( hello, 'hello: Instance of Message' );
+
+       equals( hello.format, 'parse', 'Message property "format" (default value)' );
+       equals( hello.key, 'hello', 'Message property "key" (currect key)' );
+       same( hello.parameters, [], 'Message property "parameters" (default value)' );
+
+
+       ok( hello.params, 'Message prototype "params"');
+       ok( hello.toString, 'Message prototype "toString"');
+       ok( hello.parse, 'Message prototype "parse"');
+       ok( hello.plain, 'Message prototype "plain"');
+       ok( hello.escaped, 'Message prototype "escaped"');
+       ok( hello.exists, 'Message prototype "exists"');
+
+       equals( hello.toString(), 'Hello <b>awesome</b> world', 'Message.toString() test');
+       equals( hello.escaped(), 'Hello &lt;b&gt;awesome&lt;/b&gt; world', 'Message.escaped() test');
+       same( hello.exists(), true, 'Message.exists() test');
+
+       equals( mw.msg( 'random' ), '<random>', 'square brackets around inexistant messages' );
+       equals( mw.msg( 'hello' ), 'Hello <b>awesome</b> world', 'get message with default options' );
+       
+// params, toString, parse, plain, escaped, exists
+});
+
+test( 'mw.user', function(){
+
+       ok( mw.user, 'user defined' );
+       ok( mw.user.options instanceof mw.Map, 'user.options instance of mw.Map' );
+
+       same( mw.user.name(), null, 'user.name() Anonymous' );
+       ok( mw.user.anonymous(), 'user.anonymous() Anonymous' );
+
+       // Not part of startUp module
+       mw.config.set( 'wgUserName', 'John' );
+
+       equals( mw.user.name(), 'John', 'user.name() Logged-in' );
+       ok( !mw.user.anonymous(), 'user.anonymous() Logged-in' );
+
+       equals( mw.user.id(), 'John', 'user.id() Logged-in' );
+
+});
+
+test( 'mw.loader', function(){
+
+       // @TODO: More elaborate testing ?
+       // Difficult due to modules already being loaded
+       // through it at this point
+       ok( mw.loader, 'loader defined' );
+       ok( mw.loader.work, 'loader.work defined' );
+       ok( mw.loader.register, 'loader.register defined' );
+       ok( mw.loader.implement, 'loader.implement defined' );
+       ok( mw.loader.using, 'loader.using defined' );
+       ok( mw.loader.load, 'loader.load defined' );
+       ok( mw.loader.go, 'loader.go defined' );
+       ok( mw.loader.state, 'loader.state defined' );
+       ok( mw.loader.version, 'loader.version defined' );
+
+});
+
+test( 'mw.html', function(){
+
+       equals( mw.html.escape( '<mw awesome="awesome" value=\'test\' />' ),
+        '&lt;mw awesome=&quot;awesome&quot; value=&#039;test&#039; /&gt;', 'html.escape()' );
+
+       equals( mw.html.element( 'div' ), '<div/>', 'mw.html.element() DIV (simple)' );
+
+       equals( mw.html.element( 'div',
+        { id: 'foobar' } ),
+        '<div id="foobar"/>',
+        'mw.html.element() DIV (attribs)' );
+
+       equals( mw.html.element( 'div',
+        null, 'a' ),
+        '<div>a</div>',
+        'mw.html.element() DIV (content)' );
+
+       equals( mw.html.element( 'a',
+         { href: 'http://mediawiki.org/w/index.php?title=RL&action=history' }, 'a' ),
+         '<a href="http://mediawiki.org/w/index.php?title=RL&amp;action=history">a</a>',
+         'mw.html.element() DIV (attribs + content)' );
+
+});