jquery.client unit testing

- 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.
This commit is contained in:
Krinkle 2011-07-04 19:11:08 +00:00
parent 1fa782d4fd
commit b4f0c3ea62
2 changed files with 179 additions and 21 deletions

View 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',
@ -25,9 +31,12 @@
* '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,
@ -98,28 +107,28 @@
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];
}
@ -131,13 +140,13 @@
}
// 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,
@ -147,7 +156,7 @@
'versionNumber': versionNumber
};
}
return profile;
return profileCache[nav.userAgent];
},
/**
@ -171,12 +180,14 @@
* }
* }
*
* @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' ) {

View 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 ) {