jquery.client unit testing
authorKrinkle <krinkle@users.mediawiki.org>
Mon, 4 Jul 2011 19:11:08 +0000 (19:11 +0000)
committerKrinkle <krinkle@users.mediawiki.org>
Mon, 4 Jul 2011 19:11:08 +0000 (19:11 +0000)
- More elaborate caching in the plugin in order for the code to be testable
- Added support for passing custom user agents (although the default behavior remains unchanged)
- Added support for passing custom profile-objects to $.client.test
- Added test case for all supported browsers according to http://www.mediawiki.org/wiki/Compatibility#Browser
- Replaced userAgent.toLowerCase() with userAgent since this string was already converted to lower case a few lines up

This will likely prevent bugs like bug 27652 and bug 29446.

resources/jquery/jquery.client.js
tests/qunit/suites/resources/jquery/jquery.client.js

index 74a2e52..8082fa7 100644 (file)
@@ -5,16 +5,22 @@
 
        /* Private Members */
 
-       var profile;
+       /**
+        * @var profileCache {Object} Keyed by userAgent string,
+        * value is the parsed $.client.profile object for that user agent.
+        */
+       var profileCache = {};
 
        /* Public Methods */
 
        $.client = {
        
                /**
-                * Returns an object containing information about the browser
+                * Get an object containing information about the client.
                 *
-                * The resulting client object will be in the following format:
+                * @param nav {Object} An object with atleast a 'userAgent' and 'platform' key.=
+                * Defaults to the global Navigator object.
+                * @return {Object} The resulting client object will be in the following format:
                 *  {
                 *   'name': 'firefox',
                 *   'layout': 'gecko',
                 *   'versionNumber': 3.5,
                 *  }
                 */
-               profile: function() {
+               profile: function( nav ) {
+                       if ( nav === undefined ) {
+                               nav = window.navigator;
+                       }
                        // Use the cached version if possible
-                       if ( profile === undefined ) {
+                       if ( profileCache[nav.userAgent] === undefined ) {
        
                                /* Configuration */
        
@@ -90,7 +99,7 @@
        
                                /* Pre-processing  */
        
-                               var     userAgent = navigator.userAgent,
+                               var     ua = nav.userAgent,
                                        match,
                                        name = uk,
                                        layout = uk,
                                        platform = uk,
                                        version = x;
 
-                               if ( match = new RegExp( '(' + wildUserAgents.join( '|' ) + ')' ).exec( userAgent ) ) {
+                               if ( match = new RegExp( '(' + wildUserAgents.join( '|' ) + ')' ).exec( ua ) ) {
                                        // Takes a userAgent string and translates given text into something we can more easily work with
-                                       userAgent = translate( userAgent, userAgentTranslations );
+                                       ua = translate( ua, userAgentTranslations );
                                }
                                // Everything will be in lowercase from now on
-                               userAgent = userAgent.toLowerCase();
+                               ua = ua.toLowerCase();
        
                                /* Extraction */
        
-                               if ( match = new RegExp( '(' + names.join( '|' ) + ')' ).exec( userAgent ) ) {
+                               if ( match = new RegExp( '(' + names.join( '|' ) + ')' ).exec( ua ) ) {
                                        name = translate( match[1], nameTranslations );
                                }
-                               if ( match = new RegExp( '(' + layouts.join( '|' ) + ')' ).exec( userAgent ) ) {
+                               if ( match = new RegExp( '(' + layouts.join( '|' ) + ')' ).exec( ua ) ) {
                                        layout = translate( match[1], layoutTranslations );
                                }
-                               if ( match = new RegExp( '(' + layoutVersions.join( '|' ) + ')\\\/(\\d+)').exec( navigator.userAgent.toLowerCase() ) ) {
+                               if ( match = new RegExp( '(' + layoutVersions.join( '|' ) + ')\\\/(\\d+)').exec( ua ) ) {
                                        layoutversion = parseInt( match[2], 10 );
                                }
-                               if ( match = new RegExp( '(' + platforms.join( '|' ) + ')' ).exec( navigator.platform.toLowerCase() ) ) {
+                               if ( match = new RegExp( '(' + platforms.join( '|' ) + ')' ).exec( nav.platform.toLowerCase() ) ) {
                                        platform = translate( match[1], platformTranslations );
                                }
-                               if ( match = new RegExp( '(' + versionPrefixes.join( '|' ) + ')' + versionSuffix ).exec( userAgent ) ) {
+                               if ( match = new RegExp( '(' + versionPrefixes.join( '|' ) + ')' + versionSuffix ).exec( ua ) ) {
                                        version = match[3];
                                }
        
                                }
                                // Expose Opera 10's lies about being Opera 9.8
                                if ( name === 'opera' && version >= 9.8) {
-                                       version = userAgent.match( /version\/([0-9\.]*)/i )[1] || 10;
+                                       version = ua.match( /version\/([0-9\.]*)/i )[1] || 10;
                                }
                                var versionNumber = parseFloat( version, 10 ) || 0.0;
        
                                /* Caching */
        
-                               profile = {
+                               profileCache[nav.userAgent] = {
                                        'name': name,
                                        'layout': layout,
                                        'layoutVersion': layoutversion,
                                        'versionNumber': versionNumber
                                };
                        }
-                       return profile;
+                       return profileCache[nav.userAgent];
                },
        
                /**
                 *   }
                 * }
                 *
-                * @param map Object of browser support map
+                * @param map {Object} Browser support map
+                * @param profile {Object} (optional) a client-profile object.
                 *
                 * @return Boolean true if browser known or assumed to be supported, false if blacklisted
                 */
-               test: function( map ) {
-                       var profile = $.client.profile();
+               test: function( map, profile ) {
+                       profile = $.isPlainObject( profile ) ? profile : $.client.profile();
+
                        var dir = $( 'body' ).is( '.rtl' ) ? 'rtl' : 'ltr';
                        // Check over each browser condition to determine if we are running in a compatible client
                        if ( typeof map[dir] !== 'object' || typeof map[dir][profile.name] === 'undefined' ) {
index 56d1aec..50df292 100644 (file)
@@ -5,7 +5,154 @@ test( '-- Initial check', function() {
        ok( jQuery.client, 'jQuery.client defined' );
 });
 
-test( 'profile', function() {
+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 ) {