diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2011-12-03 13:29:22 +0100 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2011-12-03 13:29:22 +0100 |
commit | ca32f08966f1b51fcb19460f0996bb0c4048e6fe (patch) | |
tree | ec04cc15b867bc21eedca904cea9af0254531a11 /tests/qunit/suites/resources/jquery | |
parent | a22fbfc60f36f5f7ee10d5ae6fe347340c2ee67c (diff) |
Update to MediaWiki 1.18.0
* also update ArchLinux skin to chagnes in MonoBook
* Use only css to hide our menu bar when printing
Diffstat (limited to 'tests/qunit/suites/resources/jquery')
10 files changed, 1248 insertions, 0 deletions
diff --git a/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.js b/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.js new file mode 100644 index 00000000..caf5a6f1 --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.js @@ -0,0 +1,58 @@ +module( 'jquery.autoEllipsis.js' ); + +test( '-- Initial check', function() { + expect(1); + ok( $.fn.autoEllipsis, 'jQuery.fn.autoEllipsis defined' ); +}); + +function createWrappedDiv( text, width ) { + var $wrapper = $( '<div />' ).css( 'width', width ); + var $div = $( '<div />' ).text( text ); + $wrapper.append( $div ); + return $wrapper; +} + +function findDivergenceIndex( a, b ) { + var i = 0; + while ( i < a.length && i < b.length && a[i] == b[i] ) { + i++; + } + return i; +} + +test( 'Position right', function() { + expect(4); + + // 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 ); + $wrapper.autoEllipsis( { position: 'right' } ); + + // Verify that, and only one, span element was created + var $span = $wrapper.find( '> span' ); + strictEqual( $span.length, 1, 'autoEllipsis wrapped the contents in a span element' ); + + // Check that the text fits by turning on word wrapping + $span.css( 'whiteSpace', 'nowrap' ); + ltOrEq( $span.width(), $span.parent().width(), "Text fits (making the span 'white-space:nowrap' does not make it wider than its parent)" ); + + // Add two characters using scary black magic + var spanText = $span.text(); + var d = findDivergenceIndex( origText, spanText ); + var spanTextNew = spanText.substr( 0, d ) + origText[d] + origText[d] + '...'; + + gt( spanTextNew.length, spanText.length, 'Verify that the new span-length is indeed greater' ); + + // 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 ) { + 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.js new file mode 100644 index 00000000..f82fda27 --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.byteLength.js @@ -0,0 +1,42 @@ +module( 'jquery.byteLength.js' ); + +test( '-- Initial check', function() { + expect(1); + ok( $.byteLength, 'jQuery.byteLength defined' ); +} ); + +test( 'Simple text', function() { + expect(5); + + var azLc = 'abcdefghijklmnopqrstuvwxyz', + azUc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + num = '0123456789', + x = '*', + space = ' '; + + equal( $.byteLength( azLc ), 26, 'Lowercase a-z' ); + equal( $.byteLength( azUc ), 26, 'Uppercase A-Z' ); + equal( $.byteLength( num ), 10, 'Numbers 0-9' ); + equal( $.byteLength( x ), 1, 'An asterisk' ); + equal( $.byteLength( space ), 3, '3 spaces' ); + +} ); + +test( 'Special text', window.foo = function() { + expect(5); + + // http://en.wikipedia.org/wiki/UTF-8 + var U_0024 = '\u0024', + U_00A2 = '\u00A2', + U_20AC = '\u20AC', + U_024B62 = '\u024B62', + // The normal one doesn't display properly, try the below which is the same + // according to http://www.fileformat.info/info/unicode/char/24B62/index.htm + U_024B62_alt = '\uD852\uDF62'; + + strictEqual( $.byteLength( U_0024 ), 1, 'U+0024: 1 byte. \u0024 (dollar sign)' ); + strictEqual( $.byteLength( U_00A2 ), 2, 'U+00A2: 2 bytes. \u00A2 (cent sign)' ); + strictEqual( $.byteLength( U_20AC ), 3, 'U+20AC: 3 bytes. \u20AC (euro sign)' ); + strictEqual( $.byteLength( U_024B62 ), 4, 'U+024B62: 4 bytes. \uD852\uDF62 (a Han character)' ); + strictEqual( $.byteLength( U_024B62_alt ), 4, 'U+024B62: 4 bytes. \uD852\uDF62 (a Han character) - alternative method' ); +} ); diff --git a/tests/qunit/suites/resources/jquery/jquery.byteLimit.js b/tests/qunit/suites/resources/jquery/jquery.byteLimit.js new file mode 100644 index 00000000..461ea49b --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.byteLimit.js @@ -0,0 +1,155 @@ +module( 'jquery.byteLimit.js' ); + +test( '-- Initial check', function() { + expect(1); + ok( $.fn.byteLimit, 'jQuery.fn.byteLimit defined' ); +} ); + +// Basic sendkey-implementation +$.addChars = function( $input, charstr ) { + var len = charstr.length; + for ( var i = 0; i < len; i++ ) { + // Keep track of the previous value + var prevVal = $input.val(); + + // Get the key code + var code = charstr.charCodeAt(i); + + // Trigger event and undo if prevented + var event = new jQuery.Event( 'keypress', { keyCode: code, which: code, charCode: code } ); + $input.trigger( event ); + if ( !event.isDefaultPrevented() ) { + $input.val( prevVal + charstr.charAt(i) ); + } + } +}; +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 limit {Number} Limit (if used) otherwise undefined + * 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, + limit: null + }, options); + var i = blti++; + + test( opt.description, function() { + + opt.$input.appendTo( 'body' ); + + // Simulate pressing keys for each of the sample characters + $.addChars( opt.$input, opt.sample ); + var newVal = opt.$input.val(); + + if ( opt.useLimit ) { + expect(2); + + 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' ); + + } else { + expect(1); + equal( $.byteLength( newVal ), opt.expected, 'Unlimited scenarios are not affected, expected length reached' ); + } + + opt.$input.remove(); + } ); +}; + +var + // Simple sample (20 chars, 20 bytes) + simpleSample = '12345678901234567890', + + // 3 bytes (euro-symbol) + U_20AC = '\u20AC', + + // Multi-byte sample (22 chars, 26 bytes) + mbSample = '1234567890' + U_20AC + '1234567890' + U_20AC; + +byteLimitTest({ + description: 'Plain text input', + $input: $( '<input>' ) + .attr( { + 'type': 'text' + }), + sample: simpleSample, + useLimit: false, + expected: $.byteLength( simpleSample ) +}); + +byteLimitTest({ + description: 'Limit using the maxlength attribute', + $input: $( '<input>' ) + .attr( { + 'type': 'text', + 'maxlength': '10' + }) + .byteLimit(), + sample: simpleSample, + useLimit: true, + limit: 10, + expected: 10 +}); + +byteLimitTest({ + description: 'Limit using a custom value', + $input: $( '<input>' ) + .attr( { + 'type': 'text' + }) + .byteLimit( 10 ), + sample: simpleSample, + useLimit: true, + limit: 10, + expected: 10 +}); + +byteLimitTest({ + description: 'Limit using a custom value, overriding maxlength attribute', + $input: $( '<input>' ) + .attr( { + 'type': 'text', + 'maxLength': '10' + }) + .byteLimit( 15 ), + sample: simpleSample, + useLimit: true, + limit: 15, + expected: 15 +}); + +byteLimitTest({ + description: 'Limit using a custom value (multibyte)', + $input: $( '<input>' ) + .attr( { + 'type': 'text' + }) + .byteLimit( 14 ), + sample: mbSample, + useLimit: true, + limit: 14, + expected: 14 // (10 x 1-byte char) + (1 x 3-byte char) + (1 x 1-byte char) +}); + +byteLimitTest({ + description: 'Limit using a custom value (multibyte) overlapping a byte', + $input: $( '<input>' ) + .attr( { + 'type': 'text' + }) + .byteLimit( 12 ), + sample: mbSample, + useLimit: 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. +}); diff --git a/tests/qunit/suites/resources/jquery/jquery.client.js b/tests/qunit/suites/resources/jquery/jquery.client.js new file mode 100644 index 00000000..50df2928 --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.client.js @@ -0,0 +1,205 @@ +module( 'jquery.client.js' ); + +test( '-- Initial check', function() { + expect(1); + ok( jQuery.client, 'jQuery.client defined' ); +}); + +test( 'profile userAgent support', function() { + expect(8); + + // 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/ + var uas = { + // Internet Explorer 6 + // Internet Explorer 7 + 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)': { + title: 'Internet Explorer 7', + platform: 'Win32', + profile: { + "name": "msie", + "layout": "trident", + "layoutVersion": "unknown", + "platform": "win", + "version": "7.0", + "versionBase": "7", + "versionNumber": 7 + } + }, + // Internet Explorer 8 + // Internet Explorer 9 + // Internet Explorer 10 + // 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': { + title: 'Firefox 3.5', + platform: 'MacIntel', + profile: { + "name": "firefox", + "layout": "gecko", + "layoutVersion": 20110420, + "platform": "mac", + "version": "3.5.19", + "versionBase": "3", + "versionNumber": 3.5 + } + }, + // Firefox 3.6 + 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110422 Ubuntu/10.10 (maverick) Firefox/3.6.17': { + title: 'Firefox 3.6', + platform: 'Linux i686', + profile: { + "name": "firefox", + "layout": "gecko", + "layoutVersion": 20110422, + "platform": "linux", + "version": "3.6.17", + "versionBase": "3", + "versionNumber": 3.6 + } + }, + // Firefox 4 + 'Mozilla/5.0 (Windows NT 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1': { + title: 'Firefox 4', + platform: 'Win32', + profile: { + "name": "firefox", + "layout": "gecko", + "layoutVersion": 20100101, + "platform": "win", + "version": "4.0.1", + "versionBase": "4", + "versionNumber": 4 + } + }, + // Firefox 5 + // Safari 3 + // Safari 4 + 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; nl-nl) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7': { + title: 'Safari 4', + platform: 'MacIntel', + profile: { + "name": "safari", + "layout": "webkit", + "layoutVersion": 531, + "platform": "mac", + "version": "4.0.5", + "versionBase": "4", + "versionNumber": 4 + } + }, + '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', + platform: 'Win32', + profile: { + "name": "safari", + "layout": "webkit", + "layoutVersion": 533, + "platform": "win", + "version": "4.0.5", + "versionBase": "4", + "versionNumber": 4 + } + }, + // Safari 5 + // Opera 10 + // Chrome 5 + // Chrome 6 + // Chrome 7 + // Chrome 8 + // Chrome 9 + // Chrome 10 + // Chrome 11 + // Chrome 12 + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30': { + title: 'Chrome 12', + platform: 'MacIntel', + profile: { + "name": "chrome", + "layout": "webkit", + "layoutVersion": 534, + "platform": "mac", + "version": "12.0.742.112", + "versionBase": "12", + "versionNumber": 12 + } + }, + 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.68 Safari/534.30': { + title: 'Chrome 12', + platform: 'Linux i686', + profile: { + "name": "chrome", + "layout": "webkit", + "layoutVersion": 534, + "platform": "linux", + "version": "12.0.742.68", + "versionBase": "12", + "versionNumber": 12 + } + } + }; + + // Generate a client profile object and compare recursively + var uaTest = function( rawUserAgent, data ) { + var ret = $.client.profile( { + userAgent: rawUserAgent, + platform: data.platform + } ); + deepEqual( ret, data.profile, 'Client profile support check for ' + data.title + ' (' + data.platform + '): ' + rawUserAgent ); + }; + + // Loop through and run tests + $.each( uas, uaTest ); +} ); + +test( 'profile return validation for current user agent', function() { + expect(7); + var p = $.client.profile(); + var unknownOrType = function( val, type, summary ) { + return ok( typeof val === type || val === 'unknown', summary ); + }; + + equal( typeof p, 'object', 'profile returns an object' ); + unknownOrType( p.layout, 'string', 'p.layout is a string (or "unknown")' ); + unknownOrType( p.layoutVersion, 'number', 'p.layoutVersion is a number (or "unknown")' ); + unknownOrType( p.platform, 'string', 'p.platform is a string (or "unknown")' ); + unknownOrType( p.version, 'string', 'p.version is a string (or "unknown")' ); + unknownOrType( p.versionBase, 'string', 'p.versionBase is a string (or "unknown")' ); + equal( typeof p.versionNumber, 'number', 'p.versionNumber is a number' ); +}); + +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 ); + + equal( typeof testMatch, 'boolean', 'test returns a boolean value' ); + +}); diff --git a/tests/qunit/suites/resources/jquery/jquery.colorUtil.js b/tests/qunit/suites/resources/jquery/jquery.colorUtil.js new file mode 100644 index 00000000..93f12b82 --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.colorUtil.js @@ -0,0 +1,71 @@ +module( 'jquery.colorUtil.js' ); + +test( '-- Initial check', function() { + expect(1); + ok( $.colorUtil, '$.colorUtil defined' ); +}); + +test( 'getRGB', function() { + expect(18); + + strictEqual( $.colorUtil.getRGB(), undefined, 'No arguments' ); + strictEqual( $.colorUtil.getRGB( '' ), undefined, 'Empty string' ); + deepEqual( $.colorUtil.getRGB( [0, 100, 255] ), [0, 100, 255], 'Parse array of rgb values' ); + deepEqual( $.colorUtil.getRGB( 'rgb(0,100,255)' ), [0, 100, 255], 'Parse simple rgb string' ); + deepEqual( $.colorUtil.getRGB( 'rgb(0, 100, 255)' ), [0, 100, 255], 'Parse simple rgb string with spaces' ); + deepEqual( $.colorUtil.getRGB( 'rgb(0%,20%,40%)' ), [0, 51, 102], 'Parse rgb string with percentages' ); + deepEqual( $.colorUtil.getRGB( 'rgb(0%, 20%, 40%)' ), [0, 51, 102], 'Parse rgb string with percentages and spaces' ); + deepEqual( $.colorUtil.getRGB( '#f2ddee' ), [242, 221, 238], 'Hex string: 6 char lowercase' ); + deepEqual( $.colorUtil.getRGB( '#f2DDEE' ), [242, 221, 238], 'Hex string: 6 char uppercase' ); + deepEqual( $.colorUtil.getRGB( '#f2DdEe' ), [242, 221, 238], 'Hex string: 6 char mixed' ); + deepEqual( $.colorUtil.getRGB( '#eee' ), [238, 238, 238], 'Hex string: 3 char lowercase' ); + deepEqual( $.colorUtil.getRGB( '#EEE' ), [238, 238, 238], 'Hex string: 3 char uppercase' ); + deepEqual( $.colorUtil.getRGB( '#eEe' ), [238, 238, 238], 'Hex string: 3 char mixed' ); + deepEqual( $.colorUtil.getRGB( 'rgba(0, 0, 0, 0)' ), [255, 255, 255], 'Zero rgba for Safari 3; Transparent (whitespace)' ); + + // Perhaps this is a bug in colorUtil, but it is the current behaviour so, let's keep + // track of it, so we will know in case it would ever change. + strictEqual( $.colorUtil.getRGB( 'rgba(0,0,0,0)' ), undefined, 'Zero rgba without whitespace' ); + + deepEqual( $.colorUtil.getRGB( 'lightGreen' ), [144, 238, 144], 'Color names (lightGreen)' ); + deepEqual( $.colorUtil.getRGB( 'transparent' ), [255, 255, 255], 'Color names (transparent)' ); + strictEqual( $.colorUtil.getRGB( 'mediaWiki' ), undefined, 'Inexisting color name' ); +}); + +test( 'rgbToHsl', function() { + expect(1); + + var hsl = $.colorUtil.rgbToHsl( 144, 238, 144 ); + + // Cross-browser differences in decimals... + // Round to two decimals so they can be more reliably checked. + var dualDecimals = function(a,b){ + return Math.round(a*100)/100; + }; + // Re-create the rgbToHsl return array items, limited to two decimals. + var ret = [dualDecimals(hsl[0]), dualDecimals(hsl[1]), dualDecimals(hsl[2])]; + + deepEqual( ret, [0.33, 0.73, 0.75], 'rgb(144, 238, 144): hsl(0.33, 0.73, 0.75)' ); +}); + +test( 'hslToRgb', function() { + expect(1); + + var rgb = $.colorUtil.hslToRgb( 0.3, 0.7, 0.8 ); + + // Cross-browser differences in decimals... + // Re-create the hslToRgb return array items, rounded to whole numbers. + var ret = [Math.round(rgb[0]), Math.round(rgb[1]), Math.round(rgb[2])]; + + deepEqual( ret ,[183, 240, 168], 'hsl(0.3, 0.7, 0.8): rgb(183, 240, 168)' ); +}); + +test( 'getColorBrightness', function() { + expect(2); + + var a = $.colorUtil.getColorBrightness( 'red', +0.1 ); + equal( a, 'rgb(255,50,50)', 'Start with named color "red", brighten 10%' ); + + var b = $.colorUtil.getColorBrightness( 'rgb(200,50,50)', -0.2 ); + equal( b, 'rgb(118,29,29)', 'Start with rgb string "rgb(200,50,50)", darken 20%' ); +}); diff --git a/tests/qunit/suites/resources/jquery/jquery.getAttrs.js b/tests/qunit/suites/resources/jquery/jquery.getAttrs.js new file mode 100644 index 00000000..3d3d01e1 --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.getAttrs.js @@ -0,0 +1,17 @@ +module( 'jquery.getAttrs.js' ); + +test( '-- Initial check', function() { + expect(1); + ok( $.fn.getAttrs, 'jQuery.fn.getAttrs defined' ); +} ); + +test( 'Check', function() { + expect(1); + var attrs = { + foo: 'bar', + 'class': 'lorem' + }, + $el = $( '<div>', attrs ); + + deepEqual( $el.getAttrs(), attrs, 'getAttrs() return object should match the attributes set, no more, no less' ); +} ); diff --git a/tests/qunit/suites/resources/jquery/jquery.localize.js b/tests/qunit/suites/resources/jquery/jquery.localize.js new file mode 100644 index 00000000..40b58687 --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.localize.js @@ -0,0 +1,119 @@ +module( 'jquery.localize.js' ); + +test( '-- Initial check', function() { + expect(1); + ok( $.fn.localize, 'jQuery.fn.localize defined' ); +} ); + +test( 'Handle basic replacements', function() { + expect(3); + + var html, $lc; + mw.messages.set( 'basic', 'Basic stuff' ); + + // Tag: html:msg + html = '<div><span><html:msg key="basic" /></span></div>'; + $lc = $( html ).localize().find( 'span' ); + + strictEqual( $lc.text(), 'Basic stuff', 'Tag: html:msg' ); + + // Attribute: title-msg + html = '<div><span title-msg="basic" /></span></div>'; + $lc = $( html ).localize().find( 'span' ); + + strictEqual( $lc.attr( 'title' ), 'Basic stuff', 'Attribute: title-msg' ); + + // Attribute: alt-msg + html = '<div><span alt-msg="basic" /></span></div>'; + $lc = $( html ).localize().find( 'span' ); + + strictEqual( $lc.attr( 'alt' ), 'Basic stuff', 'Attribute: alt-msg' ); +} ); + +test( 'Proper escaping', function() { + expect(2); + + var html, $lc; + mw.messages.set( 'properfoo', '<proper esc="test">' ); + + // This is handled by jQuery inside $.fn.localize, just a simple sanity checked + // making sure it is actually using text() and attr() (or something with the same effect) + + // Text escaping + html = '<div><span><html:msg key="properfoo" /></span></div>'; + $lc = $( html ).localize().find( 'span' ); + + strictEqual( $lc.text(), mw.msg( 'properfoo' ), 'Content is inserted as text, not as html.' ); + + // Attribute escaping + html = '<div><span title-msg="properfoo" /></span></div>'; + $lc = $( html ).localize().find( 'span' ); + + strictEqual( $lc.attr( 'title' ), mw.msg( 'properfoo' ), 'Attributes are not inserted raw.' ); +} ); + +test( 'Options', function() { + expect(7); + + mw.messages.set( { + 'foo-lorem': 'Lorem', + 'foo-ipsum': 'Ipsum', + 'foo-bar-title': 'Read more about bars', + 'foo-bar-label': 'The Bars', + 'foo-bazz-title': 'Read more about bazz at $1 (last modified: $2)', + 'foo-bazz-label': 'The Bazz ($1)', + 'foo-welcome': 'Welcome to $1! (last visit: $2)' + } ); + var html, $lc, attrs, x, sitename = 'Wikipedia'; + + // Message key prefix + html = '<div><span title-msg="lorem"><html:msg key="ipsum" /></span></div>'; + $lc = $( html ).localize( { + prefix: 'foo-' + } ).find( 'span' ); + + strictEqual( $lc.attr( 'title' ), 'Lorem', 'Message key prefix - attr' ); + strictEqual( $lc.text(), 'Ipsum', 'Message key prefix - text' ); + + // Variable keys mapping + x = 'bar'; + html = '<div><span title-msg="title"><html:msg key="label" /></span></div>'; + $lc = $( html ).localize( { + keys: { + 'title': 'foo-' + x + '-title', + 'label': 'foo-' + x + '-label' + } + } ).find( 'span' ); + + strictEqual( $lc.attr( 'title' ), 'Read more about bars', 'Variable keys mapping - attr' ); + strictEqual( $lc.text(), 'The Bars', 'Variable keys mapping - text' ); + + // Passing parameteters to mw.msg + html = '<div><span><html:msg key="foo-welcome" /></span></div>'; + $lc = $( html ).localize( { + params: { + 'foo-welcome': [sitename, 'yesterday'] + } + } ).find( 'span' ); + + strictEqual( $lc.text(), 'Welcome to Wikipedia! (last visit: yesterday)', 'Passing parameteters to mw.msg' ); + + // Combination of options prefix, params and keys + x = 'bazz'; + html = '<div><span title-msg="title"><html:msg key="label" /></span></div>'; + $lc = $( html ).localize( { + prefix: 'foo-', + keys: { + 'title': x + '-title', + 'label': x + '-label' + }, + params: { + 'title': [sitename, '3 minutes ago'], + 'label': [sitename, '3 minutes ago'] + + } + } ).find( 'span' ); + + strictEqual( $lc.text(), 'The Bazz (Wikipedia)', 'Combination of options prefix, params and keys - text' ); + strictEqual( $lc.attr( 'title' ), 'Read more about bazz at Wikipedia (last modified: 3 minutes ago)', 'Combination of options prefix, params and keys - attr' ); +} ); diff --git a/tests/qunit/suites/resources/jquery/jquery.mwPrototypes.js b/tests/qunit/suites/resources/jquery/jquery.mwPrototypes.js new file mode 100644 index 00000000..bb6d2a1b --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.mwPrototypes.js @@ -0,0 +1,56 @@ +module( 'jquery.mwPrototypes.js' ); + +test( 'String functions', function() { + + equal( $.trimLeft( ' foo bar ' ), 'foo bar ', 'trimLeft' ); + equal( $.trimRight( ' foo bar ' ), ' foo bar', 'trimRight' ); + equal( $.ucFirst( 'foo'), 'Foo', 'ucFirst' ); + + equal( $.escapeRE( '<!-- ([{+mW+}]) $^|?>' ), + '<!\\-\\- \\(\\[\\{\\+mW\\+\\}\\]\\) \\$\\^\\|\\?>', 'escapeRE - Escape specials' ); + equal( $.escapeRE( 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ), + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'escapeRE - Leave uppercase alone' ); + equal( $.escapeRE( 'abcdefghijklmnopqrstuvwxyz' ), + 'abcdefghijklmnopqrstuvwxyz', 'escapeRE - Leave lowercase alone' ); + equal( $.escapeRE( '0123456789' ), '0123456789', 'escapeRE - Leave numbers alone' ); +}); + +test( 'Is functions', function() { + + strictEqual( $.isDomElement( document.getElementById( 'qunit-header' ) ), true, + 'isDomElement: #qunit-header Node' ); + strictEqual( $.isDomElement( document.getElementById( 'random-name' ) ), false, + 'isDomElement: #random-name (null)' ); + strictEqual( $.isDomElement( document.getElementsByTagName( 'div' ) ), false, + 'isDomElement: getElementsByTagName Array' ); + strictEqual( $.isDomElement( document.getElementsByTagName( 'div' )[0] ), true, + 'isDomElement: getElementsByTagName(..)[0] Node' ); + strictEqual( $.isDomElement( $( 'div' ) ), false, + 'isDomElement: jQuery object' ); + strictEqual( $.isDomElement( $( 'div' ).get(0) ), true, + 'isDomElement: jQuery object > Get node' ); + strictEqual( $.isDomElement( document.createElement( 'div' ) ), true, + 'isDomElement: createElement' ); + strictEqual( $.isDomElement( { foo: 1 } ), false, + 'isDomElement: Object' ); + + strictEqual( $.isEmpty( 'string' ), false, 'isEmptry: "string"' ); + strictEqual( $.isEmpty( '0' ), true, 'isEmptry: "0"' ); + strictEqual( $.isEmpty( [] ), true, 'isEmptry: []' ); + strictEqual( $.isEmpty( {} ), true, 'isEmptry: {}' ); + + // Documented behaviour + strictEqual( $.isEmpty( { length: 0 } ), true, 'isEmptry: { length: 0 }' ); +}); + +test( 'Comparison functions', function() { + + ok( $.compareArray( [0, 'a', [], [2, 'b'] ], [0, "a", [], [2, "b"] ] ), + 'compareArray: Two deep arrays that are excactly the same' ); + ok( !$.compareArray( [1], [2] ), 'compareArray: Two different arrays (false)' ); + + ok( $.compareObject( {}, {} ), 'compareObject: Two empty objects' ); + ok( $.compareObject( { foo: 1 }, { foo: 1 } ), 'compareObject: Two the same objects' ); + ok( !$.compareObject( { bar: true }, { baz: false } ), + 'compareObject: Two different objects (false)' ); +}); diff --git a/tests/qunit/suites/resources/jquery/jquery.tabIndex.js b/tests/qunit/suites/resources/jquery/jquery.tabIndex.js new file mode 100644 index 00000000..1ff81e58 --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.tabIndex.js @@ -0,0 +1,50 @@ +module( 'jquery.tabIndex.js' ); + +test( '-- Initial check', function() { + expect(2); + + ok( $.fn.firstTabIndex, '$.fn.firstTabIndex defined' ); + ok( $.fn.lastTabIndex, '$.fn.lastTabIndex defined' ); +}); + +test( 'firstTabIndex', function() { + expect(2); + + var testEnvironment = +'<form>' + + '<input tabindex="7" />' + + '<input tabindex="9" />' + + '<textarea tabindex="2">Foobar</textarea>' + + '<textarea tabindex="5">Foobar</textarea>' + +'</form>'; + + var $testA = $( '<div>' ).html( testEnvironment ).appendTo( 'body' ); + 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() { + expect(2); + + var testEnvironment = +'<form>' + + '<input tabindex="7" />' + + '<input tabindex="9" />' + + '<textarea tabindex="2">Foobar</textarea>' + + '<textarea tabindex="5">Foobar</textarea>' + +'</form>'; + + var $testA = $( '<div>' ).html( testEnvironment ).appendTo( 'body' ); + 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 new file mode 100644 index 00000000..f47b7f40 --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js @@ -0,0 +1,475 @@ +(function() { + +module( 'jquery.tablesorter.test.js' ); + +// 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'); + +test( '-- Initial check', function() { + expect(1); + ok( $.tablesorter, '$.tablesorter defined' ); +}); + +/** + * Create an HTML table from an array of row arrays containing text strings. + * First row will be header row. No fancy rowspan/colspan stuff. + * + * @param {String[]} header + * @param {String[][]} data + * @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); + }); + $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.appendTo($tbody); + } + return $table; +}; + +/** + * Extract text from table. + * + * @param {jQuery} $table + * @return String[][] + */ +var tableExtract = function( $table ) { + var data = []; + $table.find('tbody').find('tr').each(function(i, tr) { + var row = []; + $(tr).find('td,th').each(function(i, td) { + row.push($(td).text()); + }); + data.push(row); + }); + return data; +}; + +/** + * Run a table test by building a table with the given data, + * running some callback on it, then checking the results. + * + * @param {String} msg text to pass on to qunit for the comparison + * @param {String[]} header cols to make the table + * @param {String[][]} data rows/cols to make the table + * @param {String[][]} expected rows/cols to compare against at end + * @param {function($table)} callback something to do with the table before we compare + */ +var tableTest = function( msg, header, data, expected, callback ) { + test( msg, function() { + expect(1); + + var $table = tableCreate( header, data ); + //$('body').append($table); + + // Give caller a chance to set up sorting and manipulate the table. + callback( $table ); + + // Table sorting is done synchronously; if it ever needs to change back + // to asynchronous, we'll need a timeout or a callback here. + var extracted = tableExtract( $table ); + deepEqual( extracted, expected, msg ); + }); +}; + +var reversed = function(arr) { + var arr2 = arr.slice(0); + arr2.reverse(); + 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']; + +// Initial data set +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( + 'Basic planet table: ascending by name', + header, + planets, + ascendingName, + function( $table ) { + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click(); + } +); +tableTest( + 'Basic planet table: ascending by name a second time', + header, + planets, + ascendingName, + function( $table ) { + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click(); + } +); +tableTest( + 'Basic planet table: descending by name', + header, + planets, + reversed(ascendingName), + function( $table ) { + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click().click(); + } +); +tableTest( + 'Basic planet table: ascending radius', + header, + planets, + ascendingRadius, + function( $table ) { + $table.tablesorter(); + $table.find('.headerSort:eq(1)').click(); + } +); +tableTest( + 'Basic planet table: descending radius', + header, + planets, + reversed(ascendingRadius), + function( $table ) { + $table.tablesorter(); + $table.find('.headerSort:eq(1)').click().click(); + } +); + + +// Regression tests! +tableTest( + 'Bug 28775: German-style short numeric dates', + ['Date'], + [ + // 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 + ['03.08.2011'], + ['02.10.2011'], + ['01.11.2011'], + ['09.11.2011'], + ['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'); + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click(); + } +); +tableTest( + 'Bug 28775: American-style short numeric dates', + ['Date'], + [ + // 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 + ['01.11.2011'], + ['02.10.2011'], + ['03.08.2011'], + ['09.11.2011'], + ['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'); + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click(); + } +); + +var ipv4 = [ + // Some randomly generated fake IPs + ['45.238.27.109'], + ['44.172.9.22'], + ['247.240.82.209'], + ['204.204.132.158'], + ['170.38.91.162'], + ['197.219.164.9'], + ['45.68.154.72'], + ['182.195.149.80'] +]; +var ipv4Sorted = [ + // Sort order should go octet by octet + ['44.172.9.22'], + ['45.68.154.72'], + ['45.238.27.109'], + ['170.38.91.162'], + ['182.195.149.80'], + ['197.219.164.9'], + ['204.204.132.158'], + ['247.240.82.209'] +]; +tableTest( + 'Bug 17141: IPv4 address sorting', + ['IP'], + ipv4, + ipv4Sorted, + function( $table ) { + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click(); + } +); +tableTest( + 'Bug 17141: IPv4 address sorting (reverse)', + ['IP'], + ipv4, + reversed(ipv4Sorted), + function( $table ) { + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click().click(); + } +); + +var umlautWords = [ + // Some words with Umlauts + ['Günther'], + ['Peter'], + ['Björn'], + ['Bjorn'], + ['Apfel'], + ['Äpfel'], + ['Strasse'], + ['Sträßschen'] +]; + +var umlautWordsSorted = [ + // Some words with Umlauts + ['Äpfel'], + ['Apfel'], + ['Björn'], + ['Bjorn'], + ['Günther'], + ['Peter'], + ['Sträßschen'], + ['Strasse'] +]; + +tableTest( + 'Accented Characters with custom collation', + ['Name'], + umlautWords, + umlautWordsSorted, + function( $table ) { + mw.config.set('tableSorterCollation', {'ä':'ae', 'ö' : 'oe', 'ß': 'ss', 'ü':'ue'}); + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click(); + mw.config.set('tableSorterCollation', {}); + } +); + +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', + 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'); + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click(); + } +); +tableTest( + 'Basic planet table: Same value for multiple rows via rowspan II', + header, + 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'); + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click(); + } +); + +var complexMDYDates = [ + // Some words with Umlauts + ['January, 19 2010'], + ['April 21 1991'], + ['04 22 1991'], + ['5.12.1990'], + ['December 12 \'10'] +]; + +var complexMDYSorted = [ + ["5.12.1990"], + ["April 21 1991"], + ["04 22 1991"], + ["January, 19 2010"], + ["December 12 '10"] +]; + +tableTest( + 'Complex date parsing I', + ['date'], + complexMDYDates, + complexMDYSorted, + function( $table ) { + mw.config.set('wgDefaultDateFormat', window.wgDefaultDateFormat = 'mdy'); + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click(); + } +); + +var ascendingNameLegacy = ascendingName.slice(0); +ascendingNameLegacy[4] = ascendingNameLegacy[5]; +ascendingNameLegacy.pop(); + +tableTest( + 'Legacy compat with .sortbottom', + header, + planets, + ascendingNameLegacy, + function( $table ) { + $table.find('tr:last').addClass('sortbottom'); + $table.tablesorter(); + $table.find('.headerSort:eq(0)').click(); + } +); + +/** FIXME: the diff output is not very readeable. */ +test( 'bug 32047 - caption must be before thead', function() { + var $table; + $table = $( + '<table class="sortable">' + + '<caption>CAPTION</caption>' + + '<tr><th>THEAD</th></tr>' + + '<tr><td>A</td></tr>' + + '<tr><td>B</td></tr>' + + '<tr class="sortbottom"><td>TFOOT</td></tr>' + + '</table>' + ); + $table.tablesorter(); + + equals( + $table.children( ).get( 0 ).nodeName, + 'CAPTION', + 'First element after <thead> must be <caption> (bug 32047)' + ); +}); + +test( 'data-sort-value attribute, when available, should override sorting position', function() { + var $table, data; + + // Simple example, one without data-sort-value which should be sorted at it's text. + $table = $( + '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' + + '<tbody>' + + '<tr><td>Cheetah</td></tr>' + + '<tr><td data-sort-value="Apple">Bird</td></tr>' + + '<tr><td data-sort-value="Bananna">Ferret</td></tr>' + + '<tr><td data-sort-value="Drupe">Elephant</td></tr>' + + '<tr><td data-sort-value="Cherry">Dolphin</td></tr>' + + '</tbody></table>' + ); + $table.tablesorter().find( '.headerSort:eq(0)' ).click(); + + data = []; + $table.find( 'tbody > tr' ).each( function( i, tr ) { + $( tr ).find( 'td' ).each( function( i, td ) { + data.push( { data: $( td ).data( 'sort-value' ), text: $( td ).text() } ); + }); + }); + + deepEqual( data, [ + { + "data": "Apple", + "text": "Bird" + }, { + "data": "Bananna", + "text": "Ferret" + }, { + "data": undefined, + "text": "Cheetah" + }, { + "data": "Cherry", + "text": "Dolphin" + }, { + "data": "Drupe", + "text": "Elephant" + } + ] ); + + // Another example + $table = $( + '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' + + '<tbody>' + + '<tr><td>D</td></tr>' + + '<tr><td data-sort-value="E">A</td></tr>' + + '<tr><td>B</td></tr>' + + '<tr><td>G</td></tr>' + + '<tr><td data-sort-value="F">C</td></tr>' + + '</tbody></table>' + ); + $table.tablesorter().find( '.headerSort:eq(0)' ).click(); + + data = []; + $table.find( 'tbody > tr' ).each( function( i, tr ) { + $( tr ).find( 'td' ).each( function( i, td ) { + data.push( { data: $( td ).data( 'sort-value' ), text: $( td ).text() } ); + }); + }); + + deepEqual( data, [ + { + "data": undefined, + "text": "B" + }, { + "data": undefined, + "text": "D" + }, { + "data": "E", + "text": "A" + }, { + "data": "F", + "text": "C" + }, { + "data": undefined, + "text": "G" + } + ] ); + +}); + +})(); |