summaryrefslogtreecommitdiff
path: root/tests/qunit/suites
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2012-05-03 13:01:35 +0200
committerPierre Schmitz <pierre@archlinux.de>2012-05-03 13:01:35 +0200
commitd9022f63880ce039446fba8364f68e656b7bf4cb (patch)
tree16b40fbf17bf7c9ee6f4ead25b16dd192378050a /tests/qunit/suites
parent27cf83d177256813e2e802241085fce5dd0f3fb9 (diff)
Update to MediaWiki 1.19.0
Diffstat (limited to 'tests/qunit/suites')
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js (renamed from tests/qunit/suites/resources/jquery/jquery.autoEllipsis.js)13
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.byteLength.test.js (renamed from tests/qunit/suites/resources/jquery/jquery.byteLength.js)4
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js (renamed from tests/qunit/suites/resources/jquery/jquery.byteLimit.js)136
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.client.test.js (renamed from tests/qunit/suites/resources/jquery/jquery.client.js)164
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js (renamed from tests/qunit/suites/resources/jquery/jquery.colorUtil.js)2
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.delayedBind.test.js4
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js (renamed from tests/qunit/suites/resources/jquery/jquery.getAttrs.js)2
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.highlightText.test.js239
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.localize.test.js (renamed from tests/qunit/suites/resources/jquery/jquery.localize.js)2
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js (renamed from tests/qunit/suites/resources/jquery/jquery.mwPrototypes.js)6
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js (renamed from tests/qunit/suites/resources/jquery/jquery.tabIndex.js)12
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js227
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.textSelection.test.js279
-rw-r--r--tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js (renamed from tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.js)36
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js201
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js43
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js29
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.test.js (renamed from tests/qunit/suites/resources/mediawiki/mediawiki.js)130
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js (renamed from tests/qunit/suites/resources/mediawiki/mediawiki.user.js)12
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js (renamed from tests/qunit/suites/resources/mediawiki/mediawiki.util.js)56
20 files changed, 1317 insertions, 280 deletions
diff --git a/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.js b/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js
index caf5a6f1..6e371384 100644
--- a/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.js
+++ b/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js
@@ -1,4 +1,4 @@
-module( 'jquery.autoEllipsis.js' );
+module( 'jquery.autoEllipsis', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(1);
@@ -6,8 +6,8 @@ test( '-- Initial check', function() {
});
function createWrappedDiv( text, width ) {
- var $wrapper = $( '<div />' ).css( 'width', width );
- var $div = $( '<div />' ).text( text );
+ var $wrapper = $( '<div>' ).css( 'width', width );
+ var $div = $( '<div>' ).text( text );
$wrapper.append( $div );
return $wrapper;
}
@@ -26,7 +26,7 @@ test( 'Position right', function() {
// We need this thing to be visible, so append it to the DOM
var origText = 'This is a really long random string and there is no way it fits in 100 pixels.';
var $wrapper = createWrappedDiv( origText, '100px' );
- $( 'body' ).append( $wrapper );
+ $( '#qunit-fixture' ).append( $wrapper );
$wrapper.autoEllipsis( { position: 'right' } );
// Verify that, and only one, span element was created
@@ -47,12 +47,9 @@ test( 'Position right', function() {
// Put this text in the span and verify it doesn't fit
$span.text( spanTextNew );
// In IE6 width works like min-width, allow IE6's width to be "equal to"
- if ( $.browser.msie && Number( $.browser.version ) == 6 ) {
+ if ( $.browser.msie && Number( $.browser.version ) === 6 ) {
gtOrEq( $span.width(), $span.parent().width(), 'Fit is maximal (adding two characters makes it not fit any more) - IE6: Maybe equal to as well due to width behaving like min-width in IE6' );
} else {
gt( $span.width(), $span.parent().width(), 'Fit is maximal (adding two characters makes it not fit any more)' );
}
-
- // Clean up
- $wrapper.remove();
});
diff --git a/tests/qunit/suites/resources/jquery/jquery.byteLength.js b/tests/qunit/suites/resources/jquery/jquery.byteLength.test.js
index f82fda27..15fac691 100644
--- a/tests/qunit/suites/resources/jquery/jquery.byteLength.js
+++ b/tests/qunit/suites/resources/jquery/jquery.byteLength.test.js
@@ -1,4 +1,4 @@
-module( 'jquery.byteLength.js' );
+module( 'jquery.byteLength', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(1);
@@ -25,7 +25,7 @@ test( 'Simple text', function() {
test( 'Special text', window.foo = function() {
expect(5);
- // http://en.wikipedia.org/wiki/UTF-8
+ // http://en.wikipedia.org/wiki/UTF-8
var U_0024 = '\u0024',
U_00A2 = '\u00A2',
U_20AC = '\u20AC',
diff --git a/tests/qunit/suites/resources/jquery/jquery.byteLimit.js b/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js
index 461ea49b..3346c2d5 100644
--- a/tests/qunit/suites/resources/jquery/jquery.byteLimit.js
+++ b/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js
@@ -1,4 +1,6 @@
-module( 'jquery.byteLimit.js' );
+( function () {
+
+module( 'jquery.byteLimit', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(1);
@@ -23,46 +25,47 @@ $.addChars = function( $input, charstr ) {
}
}
};
-var blti = 0;
+
/**
* Test factory for $.fn.byteLimit
*
* @param $input {jQuery} jQuery object in an input element
- * @param useLimit {Boolean} Wether a limit should apply at all
+ * @param hasLimit {Boolean} Wether a limit should apply at all
* @param limit {Number} Limit (if used) otherwise undefined
- * The limit should be less than 20 (the sample data's length)
+ * The limit should be less than 20 (the sample data's length)
*/
var byteLimitTest = function( options ) {
var opt = $.extend({
description: '',
$input: null,
sample: '',
- useLimit: false,
- expected: 0,
+ hasLimit: false,
+ expected: '',
limit: null
}, options);
- var i = blti++;
test( opt.description, function() {
- opt.$input.appendTo( 'body' );
-
+ opt.$input.appendTo( '#qunit-fixture' );
+
// Simulate pressing keys for each of the sample characters
$.addChars( opt.$input, opt.sample );
- var newVal = opt.$input.val();
-
- if ( opt.useLimit ) {
- expect(2);
-
+ var rawVal = opt.$input.val(),
+ fn = opt.$input.data( 'byteLimit-callback' ),
+ newVal = $.isFunction( fn ) ? fn( rawVal ) : rawVal;
+
+ if ( opt.hasLimit ) {
+ expect(3);
+
ltOrEq( $.byteLength( newVal ), opt.limit, 'Prevent keypresses after byteLimit was reached, length never exceeded the limit' );
- equal( $.byteLength( newVal ), opt.expected, 'Not preventing keypresses too early, length has reached the expected length' );
-
+ equal( $.byteLength( rawVal ), $.byteLength( opt.expected ), 'Not preventing keypresses too early, length has reached the expected length' );
+ equal( rawVal, opt.expected, 'New value matches the expected string' );
+
} else {
- expect(1);
- equal( $.byteLength( newVal ), opt.expected, 'Unlimited scenarios are not affected, expected length reached' );
+ expect(2);
+ equal( newVal, opt.expected, 'New value matches the expected string' );
+ equal( $.byteLength( newVal ), $.byteLength( opt.expected ), 'Unlimited scenarios are not affected, expected length reached' );
}
-
- opt.$input.remove();
} );
};
@@ -79,77 +82,106 @@ var
byteLimitTest({
description: 'Plain text input',
$input: $( '<input>' )
- .attr( {
- 'type': 'text'
- }),
+ .attr( 'type', 'text' ),
sample: simpleSample,
- useLimit: false,
- expected: $.byteLength( simpleSample )
+ hasLimit: false,
+ expected: simpleSample
});
byteLimitTest({
description: 'Limit using the maxlength attribute',
$input: $( '<input>' )
- .attr( {
- 'type': 'text',
- 'maxlength': '10'
- })
+ .attr( 'type', 'text' )
+ .prop( 'maxLength', '10' )
.byteLimit(),
sample: simpleSample,
- useLimit: true,
+ hasLimit: true,
limit: 10,
- expected: 10
+ expected: '1234567890'
});
byteLimitTest({
description: 'Limit using a custom value',
$input: $( '<input>' )
- .attr( {
- 'type': 'text'
- })
+ .attr( 'type', 'text' )
.byteLimit( 10 ),
sample: simpleSample,
- useLimit: true,
+ hasLimit: true,
limit: 10,
- expected: 10
+ expected: '1234567890'
});
byteLimitTest({
description: 'Limit using a custom value, overriding maxlength attribute',
$input: $( '<input>' )
- .attr( {
- 'type': 'text',
- 'maxLength': '10'
- })
+ .attr( 'type', 'text' )
+ .prop( 'maxLength', '10' )
.byteLimit( 15 ),
sample: simpleSample,
- useLimit: true,
+ hasLimit: true,
limit: 15,
- expected: 15
+ expected: '123456789012345'
});
byteLimitTest({
description: 'Limit using a custom value (multibyte)',
$input: $( '<input>' )
- .attr( {
- 'type': 'text'
- })
+ .attr( 'type', 'text' )
.byteLimit( 14 ),
sample: mbSample,
- useLimit: true,
+ hasLimit: true,
limit: 14,
- expected: 14 // (10 x 1-byte char) + (1 x 3-byte char) + (1 x 1-byte char)
+ expected: '1234567890' + U_20AC + '1'
});
byteLimitTest({
description: 'Limit using a custom value (multibyte) overlapping a byte',
$input: $( '<input>' )
- .attr( {
- 'type': 'text'
- })
+ .attr( 'type', 'text' )
.byteLimit( 12 ),
sample: mbSample,
- useLimit: true,
+ hasLimit: true,
limit: 12,
- expected: 12 // 10 x 1-byte char. The next 3-byte char exceeds limit of 12, but 2 more 1-byte chars come in after.
+ expected: '1234567890' + '12'
});
+
+byteLimitTest({
+ description: 'Pass the limit and a callback as input filter',
+ $input: $( '<input>' )
+ .attr( 'type', 'text' )
+ .byteLimit( 6, function( val ) {
+ // Invalid title
+ if ( val == '' ) {
+ return '';
+ }
+
+ // Return without namespace prefix
+ return new mw.Title( '' + val ).getMain();
+ } ),
+ sample: 'User:Sample',
+ hasLimit: true,
+ limit: 6, // 'Sample' length
+ expected: 'User:Sample'
+});
+
+byteLimitTest({
+ description: 'Limit using the maxlength attribute and pass a callback as input filter',
+ $input: $( '<input>' )
+ .attr( 'type', 'text' )
+ .prop( 'maxLength', '6' )
+ .byteLimit( function( val ) {
+ // Invalid title
+ if ( val === '' ) {
+ return '';
+ }
+
+ // Return without namespace prefix
+ return new mw.Title( '' + val ).getMain();
+ } ),
+ sample: 'User:Sample',
+ hasLimit: true,
+ limit: 6, // 'Sample' length
+ expected: 'User:Sample'
+});
+
+}() ); \ No newline at end of file
diff --git a/tests/qunit/suites/resources/jquery/jquery.client.js b/tests/qunit/suites/resources/jquery/jquery.client.test.js
index 50df2928..7be41971 100644
--- a/tests/qunit/suites/resources/jquery/jquery.client.js
+++ b/tests/qunit/suites/resources/jquery/jquery.client.test.js
@@ -1,12 +1,14 @@
-module( 'jquery.client.js' );
+module( 'jquery.client', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(1);
ok( jQuery.client, 'jQuery.client defined' );
});
-test( 'profile userAgent support', function() {
- expect(8);
+/** Number of user-agent defined */
+var uacount = 0;
+
+var uas = (function() {
// Object keyed by userAgent. Value is an array (human-readable name, client-profile object, navigator.platform value)
// Info based on results from http://toolserver.org/~krinkle/testswarm/job/174/
@@ -24,11 +26,32 @@ test( 'profile userAgent support', function() {
"version": "7.0",
"versionBase": "7",
"versionNumber": 7
+ },
+ wikiEditor: {
+ ltr: true,
+ rtl: false
}
},
// Internet Explorer 8
// Internet Explorer 9
// Internet Explorer 10
+ 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)': {
+ title: 'Internet Explorer 10',
+ platform: 'Win32',
+ profile: {
+ "name": "msie",
+ "layout": "trident",
+ "layoutVersion": "unknown", // should be able to report 6?
+ "platform": "win",
+ "version": "10.0",
+ "versionBase": "10",
+ "versionNumber": 10
+ },
+ wikiEditor: {
+ ltr: true,
+ rtl: true
+ }
+ },
// Firefox 2
// Firefox 3.5
'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.19) Gecko/20110420 Firefox/3.5.19': {
@@ -42,6 +65,10 @@ test( 'profile userAgent support', function() {
"version": "3.5.19",
"versionBase": "3",
"versionNumber": 3.5
+ },
+ wikiEditor: {
+ ltr: true,
+ rtl: true
}
},
// Firefox 3.6
@@ -56,6 +83,10 @@ test( 'profile userAgent support', function() {
"version": "3.6.17",
"versionBase": "3",
"versionNumber": 3.6
+ },
+ wikiEditor: {
+ ltr: true,
+ rtl: true
}
},
// Firefox 4
@@ -70,7 +101,29 @@ test( 'profile userAgent support', function() {
"version": "4.0.1",
"versionBase": "4",
"versionNumber": 4
- }
+ },
+ wikiEditor: {
+ ltr: true,
+ rtl: true
+ }
+ },
+ // Firefox 10 nightly build
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0a1) Gecko/20111103 Firefox/10.0a1': {
+ title: 'Firefox 10 nightly',
+ platform: 'Linux',
+ profile: {
+ "name": "firefox",
+ "layout": "gecko",
+ "layoutVersion": 20111103,
+ "platform": "linux",
+ "version": "10.0a1",
+ "versionBase": "10",
+ "versionNumber": 10
+ },
+ wikiEditor: {
+ ltr: true,
+ rtl: true
+ }
},
// Firefox 5
// Safari 3
@@ -86,7 +139,11 @@ test( 'profile userAgent support', function() {
"version": "4.0.5",
"versionBase": "4",
"versionNumber": 4
- }
+ },
+ wikiEditor: {
+ ltr: true,
+ rtl: true
+ }
},
'Mozilla/5.0 (Windows; U; Windows NT 6.0; cs-CZ) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7': {
title: 'Safari 4',
@@ -99,6 +156,10 @@ test( 'profile userAgent support', function() {
"version": "4.0.5",
"versionBase": "4",
"versionNumber": 4
+ },
+ wikiEditor: {
+ ltr: true,
+ rtl: true
}
},
// Safari 5
@@ -122,6 +183,10 @@ test( 'profile userAgent support', function() {
"version": "12.0.742.112",
"versionBase": "12",
"versionNumber": 12
+ },
+ wikiEditor: {
+ ltr: true,
+ rtl: true
}
},
'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.68 Safari/534.30': {
@@ -135,9 +200,19 @@ test( 'profile userAgent support', function() {
"version": "12.0.742.68",
"versionBase": "12",
"versionNumber": 12
+ },
+ wikiEditor: {
+ ltr: true,
+ rtl: true
}
}
};
+ $.each( uas, function() { uacount++ });
+ return uas;
+})();
+
+test( 'profile userAgent support', function() {
+ expect(uacount);
// Generate a client profile object and compare recursively
var uaTest = function( rawUserAgent, data ) {
@@ -168,34 +243,37 @@ test( 'profile return validation for current user agent', function() {
equal( typeof p.versionNumber, 'number', 'p.versionNumber is a number' );
});
+// Example from WikiEditor
+// Make sure to use raw numbers, a string like "7.0" would fail on a
+// version 10 browser since in string comparaison "10" is before "7.0" :)
+var testMap = {
+ 'ltr': {
+ 'msie': [['>=', 7.0]],
+ 'firefox': [['>=', 2]],
+ 'opera': [['>=', 9.6]],
+ 'safari': [['>=', 3]],
+ 'chrome': [['>=', 3]],
+ 'netscape': [['>=', 9]],
+ 'blackberry': false,
+ 'ipod': false,
+ 'iphone': false
+ },
+ 'rtl': {
+ 'msie': [['>=', 8]],
+ 'firefox': [['>=', 2]],
+ 'opera': [['>=', 9.6]],
+ 'safari': [['>=', 3]],
+ 'chrome': [['>=', 3]],
+ 'netscape': [['>=', 9]],
+ 'blackberry': false,
+ 'ipod': false,
+ 'iphone': false
+ }
+};
+
test( 'test', function() {
expect(1);
- // Example from WikiEditor
- var testMap = {
- 'ltr': {
- 'msie': [['>=', 7]],
- 'firefox': [['>=', 2]],
- 'opera': [['>=', 9.6]],
- 'safari': [['>=', 3]],
- 'chrome': [['>=', 3]],
- 'netscape': [['>=', 9]],
- 'blackberry': false,
- 'ipod': false,
- 'iphone': false
- },
- 'rtl': {
- 'msie': [['>=', 8]],
- 'firefox': [['>=', 2]],
- 'opera': [['>=', 9.6]],
- 'safari': [['>=', 3]],
- 'chrome': [['>=', 3]],
- 'netscape': [['>=', 9]],
- 'blackberry': false,
- 'ipod': false,
- 'iphone': false
- }
- };
// .test() uses eval, make sure no exceptions are thrown
// then do a basic return value type check
var testMatch = $.client.test( testMap );
@@ -203,3 +281,29 @@ test( 'test', function() {
equal( typeof testMatch, 'boolean', 'test returns a boolean value' );
});
+
+test( 'User-agent matches against WikiEditor\'s compatibility map', function() {
+ expect( uacount * 2 ); // double since we test both LTR and RTL
+
+ var $body = $( 'body' ),
+ bodyClasses = $body.attr( 'class' );
+
+ // Loop through and run tests
+ $.each( uas, function ( agent, data ) {
+ $.each( ['ltr', 'rtl'], function ( i, dir ) {
+ $body.removeClass( 'ltr rtl' ).addClass( dir );
+ var profile = $.client.profile( {
+ userAgent: agent,
+ platform: data.platform
+ } );
+ var testMatch = $.client.test( testMap, profile );
+ $body.removeClass( dir );
+
+ equal( testMatch, data.wikiEditor[dir], 'testing comparison based on ' + dir + ', ' + agent );
+ });
+ });
+
+ // Restore body classes
+ $body.attr( 'class', bodyClasses );
+});
+
diff --git a/tests/qunit/suites/resources/jquery/jquery.colorUtil.js b/tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js
index 93f12b82..655ee564 100644
--- a/tests/qunit/suites/resources/jquery/jquery.colorUtil.js
+++ b/tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js
@@ -1,4 +1,4 @@
-module( 'jquery.colorUtil.js' );
+module( 'jquery.colorUtil', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(1);
diff --git a/tests/qunit/suites/resources/jquery/jquery.delayedBind.test.js b/tests/qunit/suites/resources/jquery/jquery.delayedBind.test.js
index 8688f12e..6489a1f1 100644
--- a/tests/qunit/suites/resources/jquery/jquery.delayedBind.test.js
+++ b/tests/qunit/suites/resources/jquery/jquery.delayedBind.test.js
@@ -1,5 +1,5 @@
test('jquery.delayedBind with data option', function() {
- var $fixture = $('<div>').appendTo('body'),
+ var $fixture = $('<div>').appendTo('#qunit-fixture'),
data = { magic: "beeswax" },
delay = 50;
@@ -20,7 +20,7 @@ test('jquery.delayedBind with data option', function() {
});
test('jquery.delayedBind without data option', function() {
- var $fixture = $('<div>').appendTo('body'),
+ var $fixture = $('<div>').appendTo('#qunit-fixture'),
data = { magic: "beeswax" },
delay = 50;
diff --git a/tests/qunit/suites/resources/jquery/jquery.getAttrs.js b/tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js
index 3d3d01e1..9377a2f6 100644
--- a/tests/qunit/suites/resources/jquery/jquery.getAttrs.js
+++ b/tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js
@@ -1,4 +1,4 @@
-module( 'jquery.getAttrs.js' );
+module( 'jquery.getAttrs', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(1);
diff --git a/tests/qunit/suites/resources/jquery/jquery.highlightText.test.js b/tests/qunit/suites/resources/jquery/jquery.highlightText.test.js
new file mode 100644
index 00000000..4750d2b8
--- /dev/null
+++ b/tests/qunit/suites/resources/jquery/jquery.highlightText.test.js
@@ -0,0 +1,239 @@
+module( 'jquery.highlightText', QUnit.newMwEnvironment() );
+
+test( '-- Initial check', function() {
+ expect(1);
+ ok( $.fn.highlightText, 'jQuery.fn.highlightText defined' );
+} );
+
+test( 'Check', function() {
+ var cases = [
+ {
+ desc: 'Test 001',
+ text: 'Blue Öyster Cult',
+ highlight: 'Blue',
+ expected: '<span class="highlight">Blue</span> Öyster Cult'
+ },
+ {
+ desc: 'Test 002',
+ text: 'Blue Öyster Cult',
+ highlight: 'Blue ',
+ expected: '<span class="highlight">Blue</span> Öyster Cult'
+ },
+ {
+ desc: 'Test 003',
+ text: 'Blue Öyster Cult',
+ highlight: 'Blue Ö',
+ expected: '<span class="highlight">Blue</span> <span class="highlight">Ö</span>yster Cult'
+ },
+ {
+ desc: 'Test 004',
+ text: 'Blue Öyster Cult',
+ highlight: 'Blue Öy',
+ expected: '<span class="highlight">Blue</span> <span class="highlight">Öy</span>ster Cult'
+ },
+ {
+ desc: 'Test 005',
+ text: 'Blue Öyster Cult',
+ highlight: ' Blue',
+ expected: '<span class="highlight">Blue</span> Öyster Cult'
+ },
+ {
+ desc: 'Test 006',
+ text: 'Blue Öyster Cult',
+ highlight: ' Blue ',
+ expected: '<span class="highlight">Blue</span> Öyster Cult'
+ },
+ {
+ desc: 'Test 007',
+ text: 'Blue Öyster Cult',
+ highlight: ' Blue Ö',
+ expected: '<span class="highlight">Blue</span> <span class="highlight">Ö</span>yster Cult'
+ },
+ {
+ desc: 'Test 008',
+ text: 'Blue Öyster Cult',
+ highlight: ' Blue Öy',
+ expected: '<span class="highlight">Blue</span> <span class="highlight">Öy</span>ster Cult'
+ },
+ {
+ desc: 'Test 009: Highlighter broken on starting Umlaut?',
+ text: 'Österreich',
+ highlight: 'Österreich',
+ expected: '<span class="highlight">Österreich</span>'
+ },
+ {
+ desc: 'Test 010: Highlighter broken on starting Umlaut?',
+ text: 'Österreich',
+ highlight: 'Ö',
+ expected: '<span class="highlight">Ö</span>sterreich'
+ },
+ {
+ desc: 'Test 011: Highlighter broken on starting Umlaut?',
+ text: 'Österreich',
+ highlight: 'Öst',
+ expected: '<span class="highlight">Öst</span>erreich'
+ },
+ {
+ desc: 'Test 012: Highlighter broken on starting Umlaut?',
+ text: 'Österreich',
+ highlight: 'Oe',
+ expected: 'Österreich'
+ },
+ {
+ desc: 'Test 013: Highlighter broken on punctuation mark?',
+ text: 'So good. To be there',
+ highlight: 'good',
+ expected: 'So <span class="highlight">good</span>. To be there'
+ },
+ {
+ desc: 'Test 014: Highlighter broken on space?',
+ text: 'So good. To be there',
+ highlight: 'be',
+ expected: 'So good. To <span class="highlight">be</span> there'
+ },
+ {
+ desc: 'Test 015: Highlighter broken on space?',
+ text: 'So good. To be there',
+ highlight: ' be',
+ expected: 'So good. To <span class="highlight">be</span> there'
+ },
+ {
+ desc: 'Test 016: Highlighter broken on space?',
+ text: 'So good. To be there',
+ highlight: 'be ',
+ expected: 'So good. To <span class="highlight">be</span> there'
+ },
+ {
+ desc: 'Test 017: Highlighter broken on space?',
+ text: 'So good. To be there',
+ highlight: ' be ',
+ expected: 'So good. To <span class="highlight">be</span> there'
+ },
+ {
+ desc: 'Test 018: en de Highlighter broken on special character at the end?',
+ text: 'So good. xbß',
+ highlight: 'xbß',
+ expected: 'So good. <span class="highlight">xbß</span>'
+ },
+ {
+ desc: 'Test 019: en de Highlighter broken on special character at the end?',
+ text: 'So good. xbß.',
+ highlight: 'xbß.',
+ expected: 'So good. <span class="highlight">xbß.</span>'
+ },
+ {
+ desc: 'Test 020: RTL he Hebrew',
+ text: 'חסיד אומות העולם',
+ highlight: 'חסיד אומות העולם',
+ expected: '<span class="highlight">חסיד</span> <span class="highlight">אומות</span> <span class="highlight">העולם</span>'
+ },
+ {
+ desc: 'Test 021: RTL he Hebrew',
+ text: 'חסיד אומות העולם',
+ highlight: 'חסי',
+ expected: '<span class="highlight">חסי</span>ד אומות העולם'
+ },
+ {
+ desc: 'Test 022: ja Japanese',
+ text: '諸国民の中の正義の人',
+ highlight: '諸国民の中の正義の人',
+ expected: '<span class="highlight">諸国民の中の正義の人</span>'
+ },
+ {
+ desc: 'Test 023: ja Japanese',
+ text: '諸国民の中の正義の人',
+ highlight: '諸国',
+ expected: '<span class="highlight">諸国</span>民の中の正義の人'
+ },
+ {
+ desc: 'Test 024: fr French text and « french quotes » (guillemets)',
+ text: "« L'oiseau est sur l’île »",
+ highlight: "« L'oiseau est sur l’île »",
+ expected: '<span class="highlight">«</span> <span class="highlight">L\'oiseau</span> <span class="highlight">est</span> <span class="highlight">sur</span> <span class="highlight">l’île</span> <span class="highlight">»</span>'
+ },
+ {
+ desc: 'Test 025: fr French text and « french quotes » (guillemets)',
+ text: "« L'oiseau est sur l’île »",
+ highlight: "« L'oise",
+ expected: '<span class="highlight">«</span> <span class="highlight">L\'oise</span>au est sur l’île »'
+ },
+ {
+ desc: 'Test 025a: fr French text and « french quotes » (guillemets) - does it match the single strings "«" and "L" separately?',
+ text: "« L'oiseau est sur l’île »",
+ highlight: "« L",
+ expected: '<span class="highlight">«</span> <span class="highlight">L</span>\'oiseau est sur <span class="highlight">l</span>’île »'
+ },
+ {
+ desc: 'Test 026: ru Russian',
+ text: 'Праведники мира',
+ highlight: 'Праведники мира',
+ expected: '<span class="highlight">Праведники</span> <span class="highlight">мира</span>'
+ },
+ {
+ desc: 'Test 027: ru Russian',
+ text: 'Праведники мира',
+ highlight: 'Праве',
+ expected: '<span class="highlight">Праве</span>дники мира'
+ },
+ {
+ desc: 'Test 028 ka Georgian',
+ text: 'მთავარი გვერდი',
+ highlight: 'მთავარი გვერდი',
+ expected: '<span class="highlight">მთავარი</span> <span class="highlight">გვერდი</span>'
+ },
+ {
+ desc: 'Test 029 ka Georgian',
+ text: 'მთავარი გვერდი',
+ highlight: 'მთა',
+ expected: '<span class="highlight">მთა</span>ვარი გვერდი'
+ },
+ {
+ desc: 'Test 030 hy Armenian',
+ text: 'Նոնա Գափրինդաշվիլի',
+ highlight: 'Նոնա Գափրինդաշվիլի',
+ expected: '<span class="highlight">Նոնա</span> <span class="highlight">Գափրինդաշվիլի</span>'
+ },
+ {
+ desc: 'Test 031 hy Armenian',
+ text: 'Նոնա Գափրինդաշվիլի',
+ highlight: 'Նոն',
+ expected: '<span class="highlight">Նոն</span>ա Գափրինդաշվիլի'
+ },
+ {
+ desc: 'Test 032: th Thai',
+ text: 'พอล แอร์ดิช',
+ highlight: 'พอล แอร์ดิช',
+ expected: '<span class="highlight">พอล</span> <span class="highlight">แอร์ดิช</span>'
+ },
+ {
+ desc: 'Test 033: th Thai',
+ text: 'พอล แอร์ดิช',
+ highlight: 'พอ',
+ expected: '<span class="highlight">พอ</span>ล แอร์ดิช'
+ },
+ {
+ desc: 'Test 034: RTL ar Arabic',
+ text: 'بول إيردوس',
+ highlight: 'بول إيردوس',
+ expected: '<span class="highlight">بول</span> <span class="highlight">إيردوس</span>'
+ },
+ {
+ desc: 'Test 035: RTL ar Arabic',
+ text: 'بول إيردوس',
+ highlight: 'بو',
+ expected: '<span class="highlight">بو</span>ل إيردوس'
+ }
+ ];
+ expect(cases.length);
+ var $fixture;
+
+ $.each(cases, function( i, item ) {
+ $fixture = $( '<p></p>' ).text( item.text );
+ $fixture.highlightText( item.highlight );
+ equals(
+ $fixture.html(),
+ $('<p>' + item.expected + '</p>').html(), // re-parse to normalize!
+ item.desc || undefined
+ );
+ } );
+} );
diff --git a/tests/qunit/suites/resources/jquery/jquery.localize.js b/tests/qunit/suites/resources/jquery/jquery.localize.test.js
index 40b58687..cd828634 100644
--- a/tests/qunit/suites/resources/jquery/jquery.localize.js
+++ b/tests/qunit/suites/resources/jquery/jquery.localize.test.js
@@ -1,4 +1,4 @@
-module( 'jquery.localize.js' );
+module( 'jquery.localize', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(1);
diff --git a/tests/qunit/suites/resources/jquery/jquery.mwPrototypes.js b/tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js
index bb6d2a1b..3a2d0d83 100644
--- a/tests/qunit/suites/resources/jquery/jquery.mwPrototypes.js
+++ b/tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js
@@ -1,10 +1,10 @@
-module( 'jquery.mwPrototypes.js' );
+module( 'jquery.mwExtension', QUnit.newMwEnvironment() );
test( 'String functions', function() {
equal( $.trimLeft( ' foo bar ' ), 'foo bar ', 'trimLeft' );
equal( $.trimRight( ' foo bar ' ), ' foo bar', 'trimRight' );
- equal( $.ucFirst( 'foo'), 'Foo', 'ucFirst' );
+ equal( $.ucFirst( 'foo' ), 'Foo', 'ucFirst' );
equal( $.escapeRE( '<!-- ([{+mW+}]) $^|?>' ),
'<!\\-\\- \\(\\[\\{\\+mW\\+\\}\\]\\) \\$\\^\\|\\?>', 'escapeRE - Escape specials' );
@@ -36,6 +36,8 @@ test( 'Is functions', function() {
strictEqual( $.isEmpty( 'string' ), false, 'isEmptry: "string"' );
strictEqual( $.isEmpty( '0' ), true, 'isEmptry: "0"' );
+ strictEqual( $.isEmpty( '' ), true, 'isEmptry: ""' );
+ strictEqual( $.isEmpty( 1 ), false, 'isEmptry: 1' );
strictEqual( $.isEmpty( [] ), true, 'isEmptry: []' );
strictEqual( $.isEmpty( {} ), true, 'isEmptry: {}' );
diff --git a/tests/qunit/suites/resources/jquery/jquery.tabIndex.js b/tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js
index 1ff81e58..98ff5508 100644
--- a/tests/qunit/suites/resources/jquery/jquery.tabIndex.js
+++ b/tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js
@@ -1,4 +1,4 @@
-module( 'jquery.tabIndex.js' );
+module( 'jquery.tabIndex', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(2);
@@ -18,14 +18,11 @@ test( 'firstTabIndex', function() {
'<textarea tabindex="5">Foobar</textarea>' +
'</form>';
- var $testA = $( '<div>' ).html( testEnvironment ).appendTo( 'body' );
+ var $testA = $( '<div>' ).html( testEnvironment ).appendTo( '#qunit-fixture' );
strictEqual( $testA.firstTabIndex(), 2, 'First tabindex should be 2 within this context.' );
var $testB = $( '<div>' );
strictEqual( $testB.firstTabIndex(), null, 'Return null if none available.' );
-
- // Clean up
- $testA.add( $testB ).remove();
});
test( 'lastTabIndex', function() {
@@ -39,12 +36,9 @@ test( 'lastTabIndex', function() {
'<textarea tabindex="5">Foobar</textarea>' +
'</form>';
- var $testA = $( '<div>' ).html( testEnvironment ).appendTo( 'body' );
+ var $testA = $( '<div>' ).html( testEnvironment ).appendTo( '#qunit-fixture' );
strictEqual( $testA.lastTabIndex(), 9, 'Last tabindex should be 9 within this context.' );
var $testB = $( '<div>' );
strictEqual( $testB.lastTabIndex(), null, 'Return null if none available.' );
-
- // Clean up
- $testA.add( $testB ).remove();
});
diff --git a/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js b/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js
index f47b7f40..7ecdc4b1 100644
--- a/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js
+++ b/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js
@@ -1,11 +1,13 @@
-(function() {
+( function () {
-module( 'jquery.tablesorter.test.js' );
+var config = {
+ wgMonthNames: ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
+ wgMonthNamesShort: ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
+ wgDefaultDateFormat: 'dmy',
+ wgContentLanguage: 'en'
+};
-// setup hack
-mw.config.set('wgMonthNames', window.wgMonthNames = ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']);
-mw.config.set('wgMonthNamesShort', window.wgMonthNamesShort = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']);
-mw.config.set('wgDefaultDateFormat', window.wgDefaultDateFormat = 'dmy');
+module( 'jquery.tablesorter', QUnit.newMwEnvironment( config ) );
test( '-- Initial check', function() {
expect(1);
@@ -21,23 +23,24 @@ test( '-- Initial check', function() {
* @return jQuery
*/
var tableCreate = function( header, data ) {
- var $table = $('<table class="sortable"><thead></thead><tbody></tbody></table>'),
- $thead = $table.find('thead'),
- $tbody = $table.find('tbody');
- var $tr = $('<tr>');
- $.each(header, function(i, str) {
- var $th = $('<th>');
- $th.text(str).appendTo($tr);
+ var $table = $( '<table class="sortable"><thead></thead><tbody></tbody></table>' ),
+ $thead = $table.find( 'thead' ),
+ $tbody = $table.find( 'tbody' ),
+ $tr = $( '<tr>' );
+
+ $.each( header, function( i, str ) {
+ var $th = $( '<th>' );
+ $th.text( str ).appendTo( $tr );
});
- $tr.appendTo($thead);
+ $tr.appendTo( $thead );
for (var i = 0; i < data.length; i++) {
- $tr = $('<tr>');
- $.each(data[i], function(j, str) {
- var $td = $('<td>');
- $td.text(str).appendTo($tr);
+ $tr = $( '<tr>' );
+ $.each( data[i], function( j, str ) {
+ var $td = $( '<td>' );
+ $td.text( str ).appendTo( $tr );
});
- $tr.appendTo($tbody);
+ $tr.appendTo( $tbody );
}
return $table;
};
@@ -50,12 +53,13 @@ var tableCreate = function( header, data ) {
*/
var tableExtract = function( $table ) {
var data = [];
- $table.find('tbody').find('tr').each(function(i, tr) {
+
+ $table.find( 'tbody' ).find( 'tr' ).each( function( i, tr ) {
var row = [];
- $(tr).find('td,th').each(function(i, td) {
- row.push($(td).text());
+ $( tr ).find( 'td,th' ).each( function( i, td ) {
+ row.push( $( td ).text() );
});
- data.push(row);
+ data.push( row );
});
return data;
};
@@ -75,7 +79,6 @@ var tableTest = function( msg, header, data, expected, callback ) {
expect(1);
var $table = tableCreate( header, data );
- //$('body').append($table);
// Give caller a chance to set up sorting and manipulate the table.
callback( $table );
@@ -93,18 +96,18 @@ var reversed = function(arr) {
return arr2;
};
-// Sample data set: some planets!
-var header = ['Planet', 'Radius (km)'],
- mercury = ['Mercury', '2439.7'],
- venus = ['Venus', '6051.8'],
- earth = ['Earth', '6371.0'],
- mars = ['Mars', '3390.0'],
- jupiter = ['Jupiter', '69911'],
- saturn = ['Saturn', '58232'];
+// Sample data set using planets named and their radius
+var header = [ 'Planet' , 'Radius (km)'],
+ mercury = [ 'Mercury', '2439.7' ],
+ venus = [ 'Venus' , '6051.8' ],
+ earth = [ 'Earth' , '6371.0' ],
+ mars = [ 'Mars' , '3390.0' ],
+ jupiter = [ 'Jupiter', '69911' ],
+ saturn = [ 'Saturn' , '58232' ];
// Initial data set
-var planets = [mercury, venus, earth, mars, jupiter, saturn];
-var ascendingName = [earth, jupiter, mars, mercury, saturn, venus];
+var planets = [mercury, venus, earth, mars, jupiter, saturn];
+var ascendingName = [earth, jupiter, mars, mercury, saturn, venus];
var ascendingRadius = [mercury, mars, venus, earth, saturn, jupiter];
tableTest(
@@ -114,7 +117,7 @@ tableTest(
ascendingName,
function( $table ) {
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click();
+ $table.find( '.headerSort:eq(0)' ).click();
}
);
tableTest(
@@ -124,7 +127,7 @@ tableTest(
ascendingName,
function( $table ) {
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click();
+ $table.find( '.headerSort:eq(0)' ).click();
}
);
tableTest(
@@ -134,7 +137,7 @@ tableTest(
reversed(ascendingName),
function( $table ) {
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click().click();
+ $table.find( '.headerSort:eq(0)' ).click().click();
}
);
tableTest(
@@ -144,7 +147,7 @@ tableTest(
ascendingRadius,
function( $table ) {
$table.tablesorter();
- $table.find('.headerSort:eq(1)').click();
+ $table.find( '.headerSort:eq(1)' ).click();
}
);
tableTest(
@@ -154,25 +157,23 @@ tableTest(
reversed(ascendingRadius),
function( $table ) {
$table.tablesorter();
- $table.find('.headerSort:eq(1)').click().click();
+ $table.find( '.headerSort:eq(1)' ).click().click();
}
);
// Regression tests!
tableTest(
- 'Bug 28775: German-style short numeric dates',
+ 'Bug 28775: German-style (dmy) short numeric dates',
['Date'],
- [
- // German-style dates are day-month-year
+ [ // German-style dates are day-month-year
['11.11.2011'],
['01.11.2011'],
['02.10.2011'],
['03.08.2011'],
['09.11.2011']
],
- [
- // Sorted by ascending date
+ [ // Sorted by ascending date
['03.08.2011'],
['02.10.2011'],
['01.11.2011'],
@@ -180,25 +181,25 @@ tableTest(
['11.11.2011']
],
function( $table ) {
- // @fixme reset it at end or change module to allow us to override it
- mw.config.set('wgDefaultDateFormat', window.wgDefaultDateFormat = 'dmy');
+ mw.config.set( 'wgDefaultDateFormat', 'dmy' );
+ mw.config.set( 'wgContentLanguage', 'de' );
+
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click();
+ $table.find( '.headerSort:eq(0)' ).click();
}
);
+
tableTest(
- 'Bug 28775: American-style short numeric dates',
+ 'Bug 28775: American-style (mdy) short numeric dates',
['Date'],
- [
- // American-style dates are month-day-year
+ [ // American-style dates are month-day-year
['11.11.2011'],
['01.11.2011'],
['02.10.2011'],
['03.08.2011'],
['09.11.2011']
],
- [
- // Sorted by ascending date
+ [ // Sorted by ascending date
['01.11.2011'],
['02.10.2011'],
['03.08.2011'],
@@ -206,10 +207,10 @@ tableTest(
['11.11.2011']
],
function( $table ) {
- // @fixme reset it at end or change module to allow us to override it
- mw.config.set('wgDefaultDateFormat', window.wgDefaultDateFormat = 'mdy');
+ mw.config.set( 'wgDefaultDateFormat', 'mdy' );
+
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click();
+ $table.find( '.headerSort:eq(0)' ).click();
}
);
@@ -235,6 +236,7 @@ var ipv4Sorted = [
['204.204.132.158'],
['247.240.82.209']
];
+
tableTest(
'Bug 17141: IPv4 address sorting',
['IP'],
@@ -242,7 +244,7 @@ tableTest(
ipv4Sorted,
function( $table ) {
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click();
+ $table.find( '.headerSort:eq(0)' ).click();
}
);
tableTest(
@@ -252,7 +254,7 @@ tableTest(
reversed(ipv4Sorted),
function( $table ) {
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click().click();
+ $table.find( '.headerSort:eq(0)' ).click().click();
}
);
@@ -286,27 +288,36 @@ tableTest(
umlautWords,
umlautWordsSorted,
function( $table ) {
- mw.config.set('tableSorterCollation', {'ä':'ae', 'ö' : 'oe', 'ß': 'ss', 'ü':'ue'});
+ mw.config.set( 'tableSorterCollation', {
+ 'ä': 'ae',
+ 'ö': 'oe',
+ 'ß': 'ss',
+ 'ü':'ue'
+ } );
+
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click();
- mw.config.set('tableSorterCollation', {});
+ $table.find( '.headerSort:eq(0)' ).click();
}
);
-var planetsRowspan =[["Earth","6051.8"], jupiter, ["Mars","6051.8"], mercury, saturn, venus];
-var planetsRowspanII =[jupiter, mercury, saturn, ['Venus', '6371.0'], venus, ['Venus', '3390.0']];
+var planetsRowspan = [["Earth","6051.8"], jupiter, ["Mars","6051.8"], mercury, saturn, venus];
+var planetsRowspanII = [jupiter, mercury, saturn, ['Venus', '6371.0'], venus, ['Venus', '3390.0']];
tableTest(
- 'Basic planet table: Same value for multiple rows via rowspan',
+ 'Basic planet table: same value for multiple rows via rowspan',
header,
planets,
planetsRowspan,
function( $table ) {
- //Quick&Dirty mod
- $table.find('tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)').remove();
- $table.find('tr:eq(2) td:eq(1)').attr('rowspan', '3');
+ // Modify the table to have a multiuple-row-spanning cell:
+ // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
+ $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
+ // - Set rowspan for 2nd cell of 3rd row to 3.
+ // This covers the removed cell in the 4th and 5th row.
+ $table.find( 'tr:eq(2) td:eq(1)' ).prop( 'rowspan', '3' );
+
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click();
+ $table.find( '.headerSort:eq(0)' ).click();
}
);
tableTest(
@@ -315,11 +326,15 @@ tableTest(
planets,
planetsRowspanII,
function( $table ) {
- //Quick&Dirty mod
- $table.find('tr:eq(3) td:eq(0), tr:eq(4) td:eq(0)').remove();
- $table.find('tr:eq(2) td:eq(0)').attr('rowspan', '3');
+ // Modify the table to have a multiuple-row-spanning cell:
+ // - Remove 1st cell of 4th row, and, 1st cell or 5th row.
+ $table.find( 'tr:eq(3) td:eq(0), tr:eq(4) td:eq(0)' ).remove();
+ // - Set rowspan for 1st cell of 3rd row to 3.
+ // This covers the removed cell in the 4th and 5th row.
+ $table.find( 'tr:eq(2) td:eq(0)' ).prop( 'rowspan', '3' );
+
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click();
+ $table.find( '.headerSort:eq(0)' ).click();
}
);
@@ -346,9 +361,10 @@ tableTest(
complexMDYDates,
complexMDYSorted,
function( $table ) {
- mw.config.set('wgDefaultDateFormat', window.wgDefaultDateFormat = 'mdy');
+ mw.config.set( 'wgDefaultDateFormat', 'mdy' );
+
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click();
+ $table.find( '.headerSort:eq(0)' ).click();
}
);
@@ -362,9 +378,9 @@ tableTest(
planets,
ascendingNameLegacy,
function( $table ) {
- $table.find('tr:last').addClass('sortbottom');
+ $table.find( 'tr:last' ).addClass( 'sortbottom' );
$table.tablesorter();
- $table.find('.headerSort:eq(0)').click();
+ $table.find( '.headerSort:eq(0)' ).click();
}
);
@@ -472,4 +488,65 @@ test( 'data-sort-value attribute, when available, should override sorting positi
});
+var numbers = [
+ [ '12' ],
+ [ '7' ],
+ [ '13,000'],
+ [ '9' ],
+ [ '14' ],
+ [ '8.0' ]
+];
+var numbersAsc = [
+ [ '7' ],
+ [ '8.0' ],
+ [ '9' ],
+ [ '12' ],
+ [ '14' ],
+ [ '13,000']
+];
+
+tableTest( 'bug 8115: sort numbers with commas (ascending)',
+ ['Numbers'], numbers, numbersAsc,
+ function( $table ) {
+ $table.tablesorter();
+ $table.find( '.headerSort:eq(0)' ).click();
+ }
+);
+
+tableTest( 'bug 8115: sort numbers with commas (descending)',
+ ['Numbers'], numbers, reversed(numbersAsc),
+ function( $table ) {
+ $table.tablesorter();
+ $table.find( '.headerSort:eq(0)' ).click().click();
+ }
+);
+// TODO add numbers sorting tests for bug 8115 with a different language
+
+test( 'bug 32888 - Tables inside a tableheader cell', function() {
+ expect(2);
+
+ var $table;
+ $table = $(
+ '<table class="sortable" id="32888">' +
+ '<tr><th>header<table id="32888-2">'+
+ '<tr><th>1</th><th>2</th></tr>' +
+ '</table></th></tr>' +
+ '<tr><td>A</td></tr>' +
+ '<tr><td>B</td></tr>' +
+ '</table>'
+ );
+ $table.tablesorter();
+
+ equals(
+ $table.find('> thead:eq(0) > tr > th.headerSort').length,
+ 1,
+ 'Child tables inside a headercell should not interfere with sortable headers (bug 32888)'
+ );
+ equals(
+ $('#32888-2').find('th.headerSort').length,
+ 0,
+ 'The headers of child tables inside a headercell should not be sortable themselves (bug 32888)'
+ );
+});
+
})();
diff --git a/tests/qunit/suites/resources/jquery/jquery.textSelection.test.js b/tests/qunit/suites/resources/jquery/jquery.textSelection.test.js
new file mode 100644
index 00000000..1b2f3024
--- /dev/null
+++ b/tests/qunit/suites/resources/jquery/jquery.textSelection.test.js
@@ -0,0 +1,279 @@
+module( 'jquery.textSelection', QUnit.newMwEnvironment() );
+
+test( '-- Initial check', function() {
+ expect(1);
+ ok( $.fn.textSelection, 'jQuery.fn.textSelection defined' );
+} );
+
+/**
+ * Test factory for $.fn.textSelection( 'encapsulateText' )
+ *
+ * @param options {object} associative array containing:
+ * description {string}
+ * input {string}
+ * output {string}
+ * start {int} starting char for selection
+ * end {int} ending char for selection
+ * params {object} add'l parameters for $().textSelection( 'encapsulateText' )
+ */
+var encapsulateTest = function( options ) {
+ var opt = $.extend({
+ description: '',
+ before: {},
+ after: {},
+ replace: {}
+ }, options);
+
+ opt.before = $.extend({
+ text: '',
+ start: 0,
+ end: 0
+ }, opt.before);
+ opt.after = $.extend({
+ text: '',
+ selected: null
+ }, opt.after);
+
+ test( opt.description, function() {
+ var tests = 1;
+ if ( opt.after.selected !== null ) {
+ tests++;
+ }
+ expect( tests );
+
+ var $textarea = $( '<textarea>' );
+
+ $( '#qunit-fixture' ).append( $textarea );
+
+ //$textarea.textSelection( 'setContents', opt.before.text); // this method is actually missing atm...
+ $textarea.val( opt.before.text ); // won't work with the WikiEditor iframe?
+
+ var start = opt.before.start,
+ end = opt.before.end;
+ if ( window.opera ) {
+ // Compensate for Opera's craziness converting "\n" to "\r\n" and counting that as two chars
+ var newLinesBefore = opt.before.text.substring( 0, start ).split( "\n" ).length - 1,
+ newLinesInside = opt.before.text.substring( start, end ).split( "\n" ).length - 1;
+ start += newLinesBefore;
+ end += newLinesBefore + newLinesInside;
+ }
+
+ var options = $.extend( {}, opt.replace ); // Clone opt.replace
+ options.selectionStart = start;
+ options.selectionEnd = end;
+ $textarea.textSelection( 'encapsulateSelection', options );
+
+ var text = $textarea.textSelection( 'getContents' ).replace( /\r\n/g, "\n" );
+
+ equal( text, opt.after.text, 'Checking full text after encapsulation' );
+
+ if (opt.after.selected !== null) {
+ var selected = $textarea.textSelection( 'getSelection' );
+ equal( selected, opt.after.selected, 'Checking selected text after encapsulation.' );
+ }
+
+ } );
+};
+
+var sig = {
+ 'pre': "--~~~~"
+}, bold = {
+ pre: "'''",
+ peri: 'Bold text',
+ post: "'''"
+}, h2 = {
+ 'pre': '== ',
+ 'peri': 'Heading 2',
+ 'post': ' ==',
+ 'regex': /^(\s*)(={1,6})(.*?)\2(\s*)$/,
+ 'regexReplace': "\$1==\$3==\$4",
+ 'ownline': true
+}, ulist = {
+ 'pre': "* ",
+ 'peri': 'Bulleted list item',
+ 'post': "",
+ 'ownline': true,
+ 'splitlines': true
+};
+
+encapsulateTest({
+ description: "Adding sig to end of text",
+ before: {
+ text: "Wikilove dude! ",
+ start: 15,
+ end: 15
+ },
+ after: {
+ text: "Wikilove dude! --~~~~",
+ selected: ""
+ },
+ replace: sig
+});
+
+encapsulateTest({
+ description: "Adding bold to empty",
+ before: {
+ text: "",
+ start: 0,
+ end: 0
+ },
+ after: {
+ text: "'''Bold text'''",
+ selected: "Bold text" // selected because it's the default
+ },
+ replace: bold
+});
+
+encapsulateTest({
+ description: "Adding bold to existing text",
+ before: {
+ text: "Now is the time for all good men to come to the aid of their country",
+ start: 20,
+ end: 32
+ },
+ after: {
+ text: "Now is the time for '''all good men''' to come to the aid of their country",
+ selected: "" // empty because it's not the default'
+ },
+ replace: bold
+});
+
+encapsulateTest({
+ description: "ownline option: adding new h2",
+ before: {
+ text:"Before\nAfter",
+ start: 7,
+ end: 7
+ },
+ after: {
+ text: "Before\n== Heading 2 ==\nAfter",
+ selected: "Heading 2"
+ },
+ replace: h2
+});
+
+encapsulateTest({
+ description: "ownline option: turn a whole line into new h2",
+ before: {
+ text:"Before\nMy heading\nAfter",
+ start: 7,
+ end: 17
+ },
+ after: {
+ text: "Before\n== My heading ==\nAfter",
+ selected: ""
+ },
+ replace: h2
+});
+
+
+encapsulateTest({
+ description: "ownline option: turn a partial line into new h2",
+ before: {
+ text:"BeforeMy headingAfter",
+ start: 6,
+ end: 16
+ },
+ after: {
+ text: "Before\n== My heading ==\nAfter",
+ selected: ""
+ },
+ replace: h2
+});
+
+
+encapsulateTest({
+ description: "splitlines option: no selection, insert new list item",
+ before: {
+ text: "Before\nAfter",
+ start: 7,
+ end: 7
+ },
+ after: {
+ text: "Before\n* Bulleted list item\nAfter"
+ },
+ replace: ulist
+});
+
+encapsulateTest({
+ description: "splitlines option: single partial line selection, insert new list item",
+ before: {
+ text: "BeforeMy List ItemAfter",
+ start: 6,
+ end: 18
+ },
+ after: {
+ text: "Before\n* My List Item\nAfter"
+ },
+ replace: ulist
+});
+
+encapsulateTest({
+ description: "splitlines option: multiple lines",
+ before: {
+ text: "Before\nFirst\nSecond\nThird\nAfter",
+ start: 7,
+ end: 25
+ },
+ after: {
+ text: "Before\n* First\n* Second\n* Third\nAfter"
+ },
+ replace: ulist
+});
+
+
+var caretTest = function(options) {
+ test(options.description, function() {
+ expect(2);
+
+ var $textarea = $( '<textarea>' ).text(options.text);
+
+ $( '#qunit-fixture' ).append( $textarea );
+
+ if (options.mode == 'set') {
+ $textarea.textSelection('setSelection', {
+ start: options.start,
+ end: options.end
+ });
+ }
+
+ var among = function(actual, expected, message) {
+ if ($.isArray(expected)) {
+ ok($.inArray(actual, expected) !== -1 , message + ' (got ' + actual + '; expected one of ' + expected.join(', ') + ')');
+ } else {
+ equal(actual, expected, message);
+ }
+ };
+
+ var pos = $textarea.textSelection('getCaretPosition', {startAndEnd: true});
+ among(pos[0], options.start, 'Caret start should be where we set it.');
+ among(pos[1], options.end, 'Caret end should be where we set it.');
+ });
+}
+
+var caretSample = "Some big text that we like to work with. Nothing fancy... you know what I mean?";
+
+caretTest({
+ description: 'getCaretPosition with original/empty selection - bug 31847 with IE 6/7/8',
+ text: caretSample,
+ start: [0, caretSample.length], // Opera and Firefox (prior to FF 6.0) default caret to the end of the box (caretSample.length)
+ end: [0, caretSample.length], // Other browsers default it to the beginning (0), so check both.
+ mode: 'get'
+});
+
+caretTest({
+ description: 'set/getCaretPosition with forced empty selection',
+ text: caretSample,
+ start: 7,
+ end: 7,
+ mode: 'set'
+});
+
+caretTest({
+ description: 'set/getCaretPosition with small selection',
+ text: caretSample,
+ start: 6,
+ end: 11,
+ mode: 'set'
+});
+
diff --git a/tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.js b/tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js
index bcc9b96b..d73fe5a6 100644
--- a/tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.js
+++ b/tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js
@@ -1,13 +1,9 @@
-module( 'mediawiki.special.recentchanges.js' );
+module( 'mediawiki.special.recentchanges', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect( 2 );
- ok( mw.special.recentchanges.init,
- 'mw.special.recentchanges.init defined'
- );
- ok( mw.special.recentchanges.updateCheckboxes,
- 'mw.special.recentchanges.updateCheckboxes defined'
- );
+ ok( mw.special.recentchanges.init, 'mw.special.recentchanges.init defined' );
+ ok( mw.special.recentchanges.updateCheckboxes, 'mw.special.recentchanges.updateCheckboxes defined' );
// TODO: verify checkboxes == [ 'nsassociated', 'nsinvert' ]
});
@@ -37,34 +33,34 @@ test( '"all" namespace disable checkboxes', function() {
// TODO abstract the double strictEquals
// At first checkboxes are enabled
- strictEqual( $( '#nsinvert' ).attr( 'disabled' ), undefined );
- strictEqual( $( '#nsassociated' ).attr( 'disabled' ), undefined );
+ strictEqual( $( '#nsinvert' ).prop( 'disabled' ), false );
+ strictEqual( $( '#nsassociated' ).prop( 'disabled' ), false );
// Initiate the recentchanges module
mw.special.recentchanges.init();
// By default
- strictEqual( $( '#nsinvert' ).attr( 'disabled' ), 'disabled' );
- strictEqual( $( '#nsassociated' ).attr( 'disabled' ), 'disabled' );
+ strictEqual( $( '#nsinvert' ).prop( 'disabled' ), true );
+ strictEqual( $( '#nsassociated' ).prop( 'disabled' ), true );
// select second option...
var $options = $( '#namespace' ).find( 'option' );
- $options.eq(0).removeAttr( 'selected' );
- $options.eq(1).attr( 'selected', 'selected' );
+ $options.eq(0).removeProp( 'selected' );
+ $options.eq(1).prop( 'selected', true );
$( '#namespace' ).change();
// ... and checkboxes should be enabled again
- strictEqual( $( '#nsinvert' ).attr( 'disabled' ), undefined );
- strictEqual( $( '#nsassociated' ).attr( 'disabled' ), undefined );
+ strictEqual( $( '#nsinvert' ).prop( 'disabled' ), false );
+ strictEqual( $( '#nsassociated' ).prop( 'disabled' ), false );
// select first option ( 'all' namespace)...
- $options.eq(1).removeAttr( 'selected' );
- $options.eq(0).attr( 'selected', 'selected' );;
+ $options.eq(1).removeProp( 'selected' );
+ $options.eq(0).prop( 'selected', true );
$( '#namespace' ).change();
-
+
// ... and checkboxes should now be disabled
- strictEqual( $( '#nsinvert' ).attr( 'disabled' ), 'disabled' );
- strictEqual( $( '#nsassociated' ).attr( 'disabled' ), 'disabled' );
+ strictEqual( $( '#nsinvert' ).prop( 'disabled' ), true );
+ strictEqual( $( '#nsassociated' ).prop( 'disabled' ), true );
// DOM cleanup
$env.remove();
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js
new file mode 100644
index 00000000..e04111f1
--- /dev/null
+++ b/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js
@@ -0,0 +1,201 @@
+( function () {
+
+// mw.Title relies on these three config vars
+// Restore them after each test run
+var config = {
+ "wgFormattedNamespaces": {
+ "-2": "Media",
+ "-1": "Special",
+ "0": "",
+ "1": "Talk",
+ "2": "User",
+ "3": "User talk",
+ "4": "Wikipedia",
+ "5": "Wikipedia talk",
+ "6": "File",
+ "7": "File talk",
+ "8": "MediaWiki",
+ "9": "MediaWiki talk",
+ "10": "Template",
+ "11": "Template talk",
+ "12": "Help",
+ "13": "Help talk",
+ "14": "Category",
+ "15": "Category talk",
+ // testing custom / localized namespace
+ "100": "Penguins"
+ },
+ "wgNamespaceIds": {
+ "media": -2,
+ "special": -1,
+ "": 0,
+ "talk": 1,
+ "user": 2,
+ "user_talk": 3,
+ "wikipedia": 4,
+ "wikipedia_talk": 5,
+ "file": 6,
+ "file_talk": 7,
+ "mediawiki": 8,
+ "mediawiki_talk": 9,
+ "template": 10,
+ "template_talk": 11,
+ "help": 12,
+ "help_talk": 13,
+ "category": 14,
+ "category_talk": 15,
+ "image": 6,
+ "image_talk": 7,
+ "project": 4,
+ "project_talk": 5,
+ /* testing custom / alias */
+ "penguins": 100,
+ "antarctic_waterfowl": 100
+ },
+ "wgCaseSensitiveNamespaces": []
+};
+
+module( 'mediawiki.Title', QUnit.newMwEnvironment( config ) );
+
+test( '-- Initial check', function () {
+ expect(1);
+ ok( mw.Title, 'mw.Title defined' );
+});
+
+test( 'Transformation', function () {
+ expect(8);
+
+ var title;
+
+ title = new mw.Title( 'File:quux pif.jpg' );
+ equal( title.getName(), 'Quux_pif' );
+
+ title = new mw.Title( 'File:Glarg_foo_glang.jpg' );
+ equal( title.getNameText(), 'Glarg foo glang' );
+
+ title = new mw.Title( 'User:ABC.DEF' );
+ equal( title.toText(), 'User:ABC.DEF' );
+ equal( title.getNamespaceId(), 2 );
+ equal( title.getNamespacePrefix(), 'User:' );
+
+ title = new mw.Title( 'uSEr:hAshAr' );
+ equal( title.toText(), 'User:HAshAr' );
+ equal( title.getNamespaceId(), 2 );
+
+ title = new mw.Title( ' MediaWiki: Foo bar .js ' );
+ // Don't ask why, it's the way the backend works. One space is kept of each set
+ equal( title.getName(), 'Foo_bar_.js', "Merge multiple spaces to a single space." );
+});
+
+test( 'Main text for filename', function () {
+ expect(8);
+
+ var title = new mw.Title( 'File:foo_bar.JPG' );
+
+ equal( title.getNamespaceId(), 6 );
+ equal( title.getNamespacePrefix(), 'File:' );
+ equal( title.getName(), 'Foo_bar' );
+ equal( title.getNameText(), 'Foo bar' );
+ equal( title.getMain(), 'Foo_bar.JPG' );
+ equal( title.getMainText(), 'Foo bar.JPG' );
+ equal( title.getExtension(), 'JPG' );
+ equal( title.getDotExtension(), '.JPG' );
+});
+
+test( 'Namespace detection and conversion', function () {
+ expect(6);
+
+ var title;
+
+ title = new mw.Title( 'something.PDF', 6 );
+ equal( title.toString(), 'File:Something.PDF' );
+
+ title = new mw.Title( 'NeilK', 3 );
+ equal( title.toString(), 'User_talk:NeilK' );
+ equal( title.toText(), 'User talk:NeilK' );
+
+ title = new mw.Title( 'Frobisher', 100 );
+ equal( title.toString(), 'Penguins:Frobisher' );
+
+ title = new mw.Title( 'antarctic_waterfowl:flightless_yet_cute.jpg' );
+ equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
+
+ title = new mw.Title( 'Penguins:flightless_yet_cute.jpg' );
+ equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
+});
+
+test( 'Throw error on invalid title', function () {
+ expect(1);
+
+ raises(function () {
+ var title = new mw.Title( '' );
+ }, 'Throw error on empty string' );
+});
+
+test( 'Case-sensivity', function () {
+ expect(3);
+
+ var title;
+
+ // Default config
+ mw.config.set( 'wgCaseSensitiveNamespaces', [] );
+
+ title = new mw.Title( 'article' );
+ equal( title.toString(), 'Article', 'Default config: No sensitive namespaces by default. First-letter becomes uppercase' );
+
+ // $wgCapitalLinks = false;
+ mw.config.set( 'wgCaseSensitiveNamespaces', [0, -2, 1, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15] );
+
+ title = new mw.Title( 'article' );
+ equal( title.toString(), 'article', '$wgCapitalLinks=false: Article namespace is sensitive, first-letter case stays lowercase' );
+
+ title = new mw.Title( 'john', 2 );
+ equal( title.toString(), 'User:John', '$wgCapitalLinks=false: User namespace is insensitive, first-letter becomes uppercase' );
+});
+
+test( 'toString / toText', function () {
+ expect(2);
+
+ var title = new mw.Title( 'Some random page' );
+
+ equal( title.toString(), title.getPrefixedDb() );
+ equal( title.toText(), title.getPrefixedText() );
+});
+
+test( 'Exists', function () {
+ expect(3);
+
+ var title;
+
+ // Empty registry, checks default to null
+
+ title = new mw.Title( 'Some random page', 4 );
+ strictEqual( title.exists(), null, 'Return null with empty existance registry' );
+
+ // Basic registry, checks default to boolean
+ mw.Title.exist.set( ['Does_exist', 'User_talk:NeilK', 'Wikipedia:Sandbox_rules'], true );
+ mw.Title.exist.set( ['Does_not_exist', 'User:John', 'Foobar'], false );
+
+ title = new mw.Title( 'Project:Sandbox rules' );
+ assertTrue( title.exists(), 'Return true for page titles marked as existing' );
+ title = new mw.Title( 'Foobar' );
+ assertFalse( title.exists(), 'Return false for page titles marked as nonexistent' );
+
+});
+
+test( 'Url', function () {
+ expect(2);
+
+ var title;
+
+ // Config
+ mw.config.set( 'wgArticlePath', '/wiki/$1' );
+
+ title = new mw.Title( 'Foobar' );
+ equal( title.getUrl(), '/wiki/Foobar', 'Basic functionally, toString passing to wikiGetlink' );
+
+ title = new mw.Title( 'John Doe', 3 );
+ equal( title.getUrl(), '/wiki/User_talk:John_Doe', 'Escaping in title and namespace for urls' );
+});
+
+}() ); \ No newline at end of file
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
new file mode 100644
index 00000000..265ec2ae
--- /dev/null
+++ b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
@@ -0,0 +1,43 @@
+module( 'mediawiki.jqueryMsg' );
+
+test( '-- Initial check', function() {
+ expect( 1 );
+ ok( mw.jqueryMsg, 'mw.jqueryMsg defined' );
+} );
+
+test( 'mw.jqueryMsg Plural', function() {
+ expect( 5 );
+ var parser = mw.jqueryMsg.getMessageFunction();
+ ok( parser, 'Parser Function initialized' );
+ ok( mw.messages.set( 'plural-msg', 'Found $1 {{PLURAL:$1|item|items}}' ), 'mw.messages.set: Register' );
+ equal( parser( 'plural-msg', 0 ) , 'Found 0 items', 'Plural test for english with zero as count' );
+ equal( parser( 'plural-msg', 1 ) , 'Found 1 item', 'Singular test for english' );
+ equal( parser( 'plural-msg', 2 ) , 'Found 2 items', 'Plural test for english' );
+} );
+
+
+test( 'mw.jqueryMsg Gender', function() {
+ expect( 16 );
+ //TODO: These tests should be for mw.msg once mw.msg integrated with mw.jqueryMsg
+ var user = mw.user;
+ user.options.set( 'gender', 'male' );
+ var parser = mw.jqueryMsg.getMessageFunction();
+ ok( parser, 'Parser Function initialized' );
+ //TODO: English may not be the best language for these tests. Use a language like Arabic or Russian
+ ok( mw.messages.set( 'gender-msg', '$1 reverted {{GENDER:$2|his|her|their}} last edit' ), 'mw.messages.set: Register' );
+ equal( parser( 'gender-msg', 'Bob', 'male' ) , 'Bob reverted his last edit', 'Gender masculine' );
+ equal( parser( 'gender-msg', 'Bob', user ) , 'Bob reverted his last edit', 'Gender masculine' );
+ user.options.set( 'gender', 'unknown' );
+ equal( parser( 'gender-msg', 'They', user ) , 'They reverted their last edit', 'Gender neutral or unknown' );
+ equal( parser( 'gender-msg', 'Alice', 'female' ) , 'Alice reverted her last edit', 'Gender feminine' );
+ equal( parser( 'gender-msg', 'User' ) , 'User reverted their last edit', 'Gender neutral' );
+ equal( parser( 'gender-msg', 'User', 'unknown' ) , 'User reverted their last edit', 'Gender neutral' );
+ ok( mw.messages.set( 'gender-msg-one-form', '{{GENDER:$1|User}} reverted last $2 {{PLURAL:$2|edit|edits}}' ), 'mw.messages.set: Register' );
+ equal( parser( 'gender-msg-one-form', 'male', 10 ) , 'User reverted last 10 edits', 'Gender neutral and plural form' );
+ equal( parser( 'gender-msg-one-form', 'female', 1 ) , 'User reverted last 1 edit', 'Gender neutral and singular form' );
+ ok( mw.messages.set( 'gender-msg-lowercase', '{{gender:$1|he|she}} is awesome' ), 'mw.messages.set: Register' );
+ equal( parser( 'gender-msg-lowercase', 'male' ) , 'he is awesome', 'Gender masculine' );
+ equal( parser( 'gender-msg-lowercase', 'female' ) , 'she is awesome', 'Gender feminine' );
+ ok( mw.messages.set( 'gender-msg-wrong', '{{gender}} is awesome' ), 'mw.messages.set: Register' );
+ equal( parser( 'gender-msg-wrong', 'female' ) , ' is awesome', 'Wrong syntax used, but ignore the {{gender}}' );
+} );
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js
index 52cd32c8..24005b64 100644
--- a/tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js
+++ b/tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js
@@ -1,6 +1,6 @@
/* Some misc JavaScript compatibility tests, just to make sure the environments we run in are consistent */
-module( 'mediawiki.jscompat' );
+module( 'mediawiki.jscompat', QUnit.newMwEnvironment() );
test( 'Variable with Unicode letter in name', function() {
expect(3);
@@ -33,3 +33,30 @@ test( 'Keyword workaround: "if" as member variable name using Unicode escapes',
deepEqual( foo.\u0069\u0066, orig, 'foo.\\u0069\\u0066' );
});
*/
+
+test( 'Stripping of single initial newline from textarea\'s literal contents (bug 12130)', function() {
+ var maxn = 4;
+ expect(maxn * 2);
+
+ var repeat = function(str, n) {
+ if (n <= 0) {
+ return '';
+ } else {
+ var out = Array(n);
+ for (var i = 0; i < n; i++) {
+ out[i] = str;
+ }
+ return out.join('');
+ }
+ };
+
+ for (var n = 0; n < maxn; n++) {
+ var expected = repeat('\n', n) + 'some text';
+
+ var $textarea = $('<textarea>\n' + expected + '</textarea>');
+ equal($textarea.val(), expected, 'Expecting ' + n + ' newlines (HTML contained ' + (n + 1) + ')');
+
+ var $textarea2 = $('<textarea>').val(expected);
+ equal($textarea2.val(), expected, 'Expecting ' + n + ' newlines (from DOM set with ' + n + ')');
+ }
+});
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.js b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js
index 4beed881..e6934eda 100644
--- a/tests/qunit/suites/resources/mediawiki/mediawiki.js
+++ b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js
@@ -1,4 +1,4 @@
-module( 'mediawiki.js' );
+module( 'mediawiki', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(8);
@@ -80,7 +80,7 @@ test( 'mw.config', function() {
});
test( 'mw.message & mw.messages', function() {
- expect(17);
+ expect(20);
ok( mw.messages, 'messages defined' );
ok( mw.messages instanceof mw.Map, 'mw.messages instance of mw.Map' );
@@ -88,7 +88,7 @@ test( 'mw.message & mw.messages', function() {
var hello = mw.message( 'hello' );
- equal( hello.format, 'parse', 'Message property "format" defaults to "parse"' );
+ equal( hello.format, 'plain', 'Message property "format" defaults to "plain"' );
strictEqual( hello.map, mw.messages, 'Message property "map" defaults to the global instance in mw.messages' );
equal( hello.key, 'hello', 'Message property "key" (currect key)' );
deepEqual( hello.parameters, [], 'Message property "parameters" defaults to an empty array' );
@@ -111,59 +111,45 @@ test( 'mw.message & mw.messages', function() {
strictEqual( hello.exists(), true, 'Message.exists returns true for existing messages' );
var goodbye = mw.message( 'goodbye' );
- strictEqual( goodbye.exists(), false, 'Message.exists returns false for inexisting messages' );
+ strictEqual( goodbye.exists(), false, 'Message.exists returns false for nonexistent messages' );
equal( goodbye.plain(), '<goodbye>', 'Message.toString returns plain <key> if format is "plain" and key does not exist' );
// bug 30684
equal( goodbye.escaped(), '&lt;goodbye&gt;', 'Message.toString returns properly escaped &lt;key&gt; if format is "escaped" and key does not exist' );
+
+ ok( mw.messages.set( 'pluraltestmsg', 'There {{PLURAL:$1|is|are}} $1 {{PLURAL:$1|result|results}}' ), 'mw.messages.set: Register' );
+ var pluralMessage = mw.message( 'pluraltestmsg' , 6 );
+ equal( pluralMessage.plain(), 'There are 6 results', 'plural get resolved when format is plain' );
+ equal( pluralMessage.parse(), 'There are 6 results', 'plural get resolved when format is parse' );
+
});
test( 'mw.msg', function() {
- expect(3);
+ expect(11);
ok( mw.messages.set( 'hello', 'Hello <b>awesome</b> world' ), 'mw.messages.set: Register' );
-
equal( mw.msg( 'hello' ), 'Hello <b>awesome</b> world', 'Gets message with default options (existing message)' );
- equal( mw.msg( 'goodbye' ), '<goodbye>', 'Gets message with default options (inexisting message)' );
-});
+ equal( mw.msg( 'goodbye' ), '<goodbye>', 'Gets message with default options (nonexistent message)' );
-test( 'mw.loader', function() {
- expect(5);
+ ok( mw.messages.set( 'plural-item' , 'Found $1 {{PLURAL:$1|item|items}}' ) );
+ equal( mw.msg( 'plural-item', 5 ), 'Found 5 items', 'Apply plural for count 5' );
+ equal( mw.msg( 'plural-item', 0 ), 'Found 0 items', 'Apply plural for count 0' );
+ equal( mw.msg( 'plural-item', 1 ), 'Found 1 item', 'Apply plural for count 1' );
- // Regular expression to extract the path for the QUnit tests
- // Takes into account that tests could be run from a file:// URL
- // by excluding the 'index.html' part from the URL
- var rePath = /(?:[^#\?](?!index.html))*\/?/;
+ ok( mw.messages.set('gender-plural-msg' , '{{GENDER:$1|he|she|they}} {{PLURAL:$2|is|are}} awesome' ) );
+ equal( mw.msg( 'gender-plural-msg', 'male', 1 ), 'he is awesome', 'Gender test for male, plural count 1' );
+ equal( mw.msg( 'gender-plural-msg', 'female', '1' ), 'she is awesome', 'Gender test for female, plural count 1' );
+ equal( mw.msg( 'gender-plural-msg', 'unknown', 10 ), 'they are awesome', 'Gender test for neutral, plural count 10' );
- // Four assertions to test the above regular expression:
- equal(
- rePath.exec( 'http://path/to/tests/?foobar' )[0],
- "http://path/to/tests/",
- "Extracting path from http URL with query"
- );
- equal(
- rePath.exec( 'http://path/to/tests/#frag' )[0],
- "http://path/to/tests/",
- "Extracting path from http URL with fragment"
- );
- equal(
- rePath.exec( 'file://path/to/tests/index.html?foobar' )[0],
- "file://path/to/tests/",
- "Extracting path from local URL (file://) with query"
- );
- equal(
- rePath.exec( 'file://path/to/tests/index.html#frag' )[0],
- "file://path/to/tests/",
- "Extracting path from local URL (file://) with fragment"
- );
+});
- // Asynchronous ahead
- stop(5000);
+test( 'mw.loader', function() {
+ expect(1);
- // Extract path
- var tests_path = rePath.exec( location.href );
+ // Asynchronous ahead
+ stop();
- mw.loader.implement( 'is.awesome', [QUnit.fixurl( tests_path + 'data/defineTestCallback.js')], {}, {} );
+ mw.loader.implement( 'is.awesome', [QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/defineTestCallback.js' )], {}, {} );
mw.loader.using( 'is.awesome', function() {
@@ -185,9 +171,9 @@ test( 'mw.loader.bug29107' , function() {
// Message doesn't exist already
ok( !mw.messages.exists( 'bug29107' ) );
- // Async! Include a timeout, as failure in this test leads to neither the
- // success nor failure callbacks getting called.
- stop(5000);
+ // Async! Failure in this test may lead to neither the success nor error callbacks getting called.
+ // Due to QUnit's timeout feauture we won't hang here forever if this happends.
+ stop();
mw.loader.implement( 'bug29107.messages-only', [], {}, {'bug29107': 'loaded'} );
mw.loader.using( 'bug29107.messages-only', function() {
@@ -199,8 +185,31 @@ test( 'mw.loader.bug29107' , function() {
});
});
+test( 'mw.loader.bug30825', function() {
+ // This bug was actually already fixed in 1.18 and later when discovered in 1.17.
+ // Test is for regressions!
+
+ expect(2);
+
+ // Forge an URL to the test callback script
+ var target = QUnit.fixurl(
+ mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/qunitOkCall.js'
+ );
+
+ // Confirm that mw.loader.load() works with protocol-relative URLs
+ target = target.replace( /https?:/, '' );
+
+ equal( target.substr( 0, 2 ), '//',
+ 'URL must be relative to test relative URLs!'
+ );
+
+ // Async!
+ stop();
+ mw.loader.load( target );
+});
+
test( 'mw.html', function() {
- expect(7);
+ expect(11);
raises( function(){
mw.html.escape();
@@ -214,11 +223,40 @@ test( 'mw.html', function() {
equal( mw.html.element( 'div' ), '<div/>', 'html.element DIV (simple)' );
- equal( mw.html.element( 'div',
- { id: 'foobar' } ),
+ equal(
+ mw.html.element(
+ 'div', {
+ id: 'foobar'
+ }
+ ),
'<div id="foobar"/>',
'html.element DIV (attribs)' );
+ equal( mw.html.element( 'p', null, 12 ), '<p>12</p>', 'Numbers are valid content and should be casted to a string' );
+
+ equal( mw.html.element( 'p', { title: 12 }, '' ), '<p title="12"></p>', 'Numbers are valid attribute values' );
+
+ equal(
+ mw.html.element(
+ 'option', {
+ selected: true
+ }, 'Foo'
+ ),
+ '<option selected="selected">Foo</option>',
+ 'Attributes may have boolean values. True copies the attribute name to the value.'
+ );
+
+ equal(
+ mw.html.element(
+ 'option', {
+ value: 'foo',
+ selected: false
+ }, 'Foo'
+ ),
+ '<option value="foo">Foo</option>',
+ 'Attributes may have boolean values. False keeps the attribute from output.'
+ );
+
equal( mw.html.element( 'div',
null, 'a' ),
'<div>a</div>',
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.user.js b/tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js
index d5c6baad..15265db5 100644
--- a/tests/qunit/suites/resources/mediawiki/mediawiki.user.js
+++ b/tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js
@@ -1,4 +1,4 @@
-module( 'mediawiki.user.js' );
+module( 'mediawiki.user', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(1);
@@ -16,6 +16,16 @@ test( 'options', function() {
test( 'User login status', function() {
expect(5);
+ /**
+ * Tests can be run under three different conditions:
+ * 1) From tests/qunit/index.html, user will be anonymous.
+ * 2) Logged in on [[Special:JavaScriptTest/qunit]]
+ * 3) Anonymously at the same special page.
+ */
+
+ // Forge an anonymous user:
+ mw.config.set( 'wgUserName', null);
+
strictEqual( mw.user.name(), null, 'user.name should return null when anonymous' );
ok( mw.user.anonymous(), 'user.anonymous should reutrn true when anonymous' );
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.util.js b/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js
index 9c05d9b2..ea28935e 100644
--- a/tests/qunit/suites/resources/mediawiki/mediawiki.util.js
+++ b/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js
@@ -1,4 +1,4 @@
-module( 'mediawiki.util.js' );
+module( 'mediawiki.util', QUnit.newMwEnvironment() );
test( '-- Initial check', function() {
expect(1);
@@ -47,13 +47,12 @@ test( 'wikiScript', function() {
equal( mw.util.wikiScript(), mw.config.get( 'wgScript' ), 'Defaults to index.php and is equal to wgScript' );
equal( mw.util.wikiScript( 'api' ), '/w/api.php', 'API path' );
-
});
test( 'addCSS', function() {
expect(3);
- var $testEl = $( '<div>' ).attr( 'id', 'mw-addcsstest' ).appendTo( 'body' );
+ var $testEl = $( '<div>' ).attr( 'id', 'mw-addcsstest' ).appendTo( '#qunit-fixture' );
var style = mw.util.addCSS( '#mw-addcsstest { visibility: hidden; }' );
equal( typeof style, 'object', 'addCSS returned an object' );
@@ -62,9 +61,7 @@ test( 'addCSS', function() {
equal( $testEl.css( 'visibility' ), 'hidden', 'Added style properties are in effect' );
// Clean up
- $( style.ownerNode )
- .add( $testEl )
- .remove();
+ $( style.ownerNode ).remove();
});
test( 'toggleToc', function() {
@@ -80,7 +77,7 @@ test( 'toggleToc', function() {
'</div>' +
'<ul><li></li></ul>' +
'</td></tr></table>',
- $toc = $(tocHtml).appendTo( 'body' ),
+ $toc = $(tocHtml).appendTo( '#qunit-fixture' ),
$toggleLink = $( '#togglelink' );
strictEqual( $toggleLink.length, 1, 'Toggle link is appended to the page.' );
@@ -91,9 +88,6 @@ test( 'toggleToc', function() {
var actionC = function() {
start();
-
- // Clean up
- $toc.remove();
};
var actionB = function() {
start(); stop();
@@ -109,18 +103,18 @@ test( 'toggleToc', function() {
test( 'getParamValue', function() {
expect(5);
- var url1 = 'http://mediawiki.org/?foo=wrong&foo=right#&foo=bad';
+ var url1 = 'http://example.org/?foo=wrong&foo=right#&foo=bad';
equal( mw.util.getParamValue( 'foo', url1 ), 'right', 'Use latest one, ignore hash' );
strictEqual( mw.util.getParamValue( 'bar', url1 ), null, 'Return null when not found' );
- var url2 = 'http://mediawiki.org/#&foo=bad';
+ var url2 = 'http://example.org/#&foo=bad';
strictEqual( mw.util.getParamValue( 'foo', url2 ), null, 'Ignore hash if param is not in querystring but in hash (bug 27427)' );
- var url3 = 'example.com?' + $.param({ 'TEST': 'a b+c' });
+ var url3 = 'example.org?' + $.param({ 'TEST': 'a b+c' });
strictEqual( mw.util.getParamValue( 'TEST', url3 ), 'a b+c', 'Bug 30441: getParamValue must understand "+" encoding of space' );
- var url4 = 'example.com?' + $.param({ 'TEST': 'a b+c d' }); // check for sloppy code from r95332 :)
+ var url4 = 'example.org?' + $.param({ 'TEST': 'a b+c d' }); // check for sloppy code from r95332 :)
strictEqual( mw.util.getParamValue( 'TEST', url4 ), 'a b+c d', 'Bug 30441: getParamValue must understand "+" encoding of space (multiple spaces)' );
});
@@ -139,51 +133,55 @@ test( '$content', function() {
strictEqual( mw.util.$content.length, 1, 'mw.util.$content must have length of 1' );
});
+
+/**
+ * Portlet names are prefixed with 'p-test' to avoid conflict with core
+ * when running the test suite under a wiki page.
+ * Previously, test elements where invisible to the selector since only
+ * one element can have a given id.
+ */
test( 'addPortletLink', function() {
expect(7);
var mwPanel = '<div id="mw-panel" class="noprint">\
<h5>Toolbox</h5>\
- <div class="portlet" id="p-tb">\
+ <div class="portlet" id="p-test-tb">\
<ul class="body"></ul>\
</div>\
</div>',
- vectorTabs = '<div id="p-views" class="vectorTabs">\
+ vectorTabs = '<div id="p-test-views" class="vectorTabs">\
<h5>Views</h5>\
<ul></ul>\
</div>',
- $mwPanel = $(mwPanel).appendTo( 'body' ),
- $vectorTabs = $(vectorTabs).appendTo( 'body' );
+ $mwPanel = $(mwPanel).appendTo( '#qunit-fixture' ),
+ $vectorTabs = $(vectorTabs).appendTo( '#qunit-fixture' );
- var tbRL = mw.util.addPortletLink( 'p-tb', 'http://mediawiki.org/wiki/ResourceLoader',
+ var tbRL = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/wiki/ResourceLoader',
'ResourceLoader', 't-rl', 'More info about ResourceLoader on MediaWiki.org ', 'l' );
ok( $.isDomElement( tbRL ), 'addPortletLink returns a valid DOM Element according to $.isDomElement' );
- var tbMW = mw.util.addPortletLink( 'p-tb', 'http://mediawiki.org/',
+ var tbMW = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/',
'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org ', 'm', tbRL ),
$tbMW = $( tbMW );
-
+
equal( $tbMW.attr( 'id' ), 't-mworg', 'Link has correct ID set' );
- equal( $tbMW.closest( '.portlet' ).attr( 'id' ), 'p-tb', 'Link was inserted within correct portlet' );
+ equal( $tbMW.closest( '.portlet' ).attr( 'id' ), 'p-test-tb', 'Link was inserted within correct portlet' );
equal( $tbMW.next().attr( 'id' ), 't-rl', 'Link is in the correct position (by passing nextnode)' );
- var tbRLDM = mw.util.addPortletLink( 'p-tb', 'http://mediawiki.org/wiki/RL/DM',
+ var tbRLDM = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/wiki/RL/DM',
'Default modules', 't-rldm', 'List of all default modules ', 'd', '#t-rl' );
equal( $( tbRLDM ).next().attr( 'id' ), 't-rl', 'Link is in the correct position (by passing CSS selector)' );
- var caFoo = mw.util.addPortletLink( 'p-views', '#', 'Foo' );
+ var caFoo = mw.util.addPortletLink( 'p-test-views', '#', 'Foo' );
strictEqual( $tbMW.find( 'span').length, 0, 'No <span> element should be added for porlets without vectorTabs class.' );
strictEqual( $( caFoo ).find( 'span').length, 1, 'A <span> element should be added for porlets with vectorTabs class.' );
-
+
// Clean up
- $( [tbRL, tbMW, tbRLDM, caFoo] )
- .add( $mwPanel )
- .add( $vectorTabs )
- .remove();
+ $( [tbRL, tbMW, tbRLDM, caFoo] ).remove();
});
test( 'jsMessage', function() {