mirror of
https://github.com/chaijs/chai
synced 2024-11-15 08:17:14 +00:00
Merge branch 'feature/saucelabs'
* feature/saucelabs: browser: build support: add mocha cloud runner, client, and html test page test: [saucelabs] add auth placeholder deps: add mocha-cloud
This commit is contained in:
commit
d8f01c0f36
7 changed files with 542 additions and 29 deletions
25
.gitignore
vendored
25
.gitignore
vendored
|
@ -1,7 +1,20 @@
|
|||
.settings.xml
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
.DS_Store
|
||||
*.swp
|
||||
coverage.html
|
||||
lib-cov
|
||||
*.seed
|
||||
*.log
|
||||
*.csv
|
||||
*.dat
|
||||
*.out
|
||||
*.pid
|
||||
*.gz
|
||||
|
||||
pids
|
||||
logs
|
||||
results
|
||||
|
||||
node_modules
|
||||
npm-debug.log
|
||||
|
||||
coverage.html
|
||||
|
||||
test/auth/*
|
||||
!test/auth/.gitkeep
|
||||
|
|
139
chai.js
139
chai.js
|
@ -663,12 +663,13 @@
|
|||
* expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);
|
||||
*
|
||||
* @name eql
|
||||
* @alias eqls
|
||||
* @param {Mixed} value
|
||||
* @param {String} message _optional_
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Assertion.addMethod('eql', function (obj, msg) {
|
||||
function assertEql(obj, msg) {
|
||||
if (msg) flag(this, 'message', msg);
|
||||
this.assert(
|
||||
_.eql(obj, flag(this, 'object'))
|
||||
|
@ -678,7 +679,10 @@
|
|||
, this._obj
|
||||
, true
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Assertion.addMethod('eql', assertEql);
|
||||
Assertion.addMethod('eqls', assertEql);
|
||||
|
||||
/**
|
||||
* ### .above(value)
|
||||
|
@ -1315,20 +1319,21 @@
|
|||
if (!errMsg) return this;
|
||||
}
|
||||
// next, check message
|
||||
if (err.message && errMsg && errMsg instanceof RegExp) {
|
||||
var message = typeof(err) === 'object' && "message" in err ? err.message : '' + err;
|
||||
if (message && errMsg && errMsg instanceof RegExp) {
|
||||
this.assert(
|
||||
errMsg.exec(err.message)
|
||||
, 'expected #{this} to throw error matching ' + errMsg + ' but got ' + _.inspect(err.message)
|
||||
errMsg.exec(message)
|
||||
, 'expected #{this} to throw error matching ' + errMsg + ' but got ' + _.inspect(message)
|
||||
, 'expected #{this} to throw error not matching ' + errMsg
|
||||
);
|
||||
return this;
|
||||
} else if (err.message && errMsg && 'string' === typeof errMsg) {
|
||||
} else if (message && errMsg && 'string' === typeof errMsg) {
|
||||
this.assert(
|
||||
~err.message.indexOf(errMsg)
|
||||
~message.indexOf(errMsg)
|
||||
, 'expected #{this} to throw error including #{exp} but got #{act}'
|
||||
, 'expected #{this} to throw error not including #{act}'
|
||||
, errMsg
|
||||
, err.message
|
||||
, message
|
||||
);
|
||||
return this;
|
||||
} else {
|
||||
|
@ -2626,6 +2631,18 @@
|
|||
|
||||
var transferFlags = require('./transferFlags');
|
||||
|
||||
/*!
|
||||
* Module variables
|
||||
*/
|
||||
|
||||
// Check whether `__proto__` is supported
|
||||
var hasProtoSupport = '__proto__' in Object;
|
||||
|
||||
// Without `__proto__` support, this module will need to add properties to a function.
|
||||
// However, some Function.prototype methods cannot be overwritten,
|
||||
// and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69).
|
||||
var excludeNames = /^(?:length|name|arguments|caller)$/;
|
||||
|
||||
/**
|
||||
* ### addChainableMethod (ctx, name, method, chainingBehavior)
|
||||
*
|
||||
|
@ -2667,16 +2684,20 @@
|
|||
return result === undefined ? this : result;
|
||||
};
|
||||
|
||||
// Re-enumerate every time to better accomodate plugins.
|
||||
var asserterNames = Object.getOwnPropertyNames(ctx);
|
||||
asserterNames.forEach(function (asserterName) {
|
||||
var pd = Object.getOwnPropertyDescriptor(ctx, asserterName)
|
||||
, functionProtoPD = Object.getOwnPropertyDescriptor(Function.prototype, asserterName);
|
||||
// Avoid trying to overwrite things that we can't, like `length` and `arguments`.
|
||||
if (functionProtoPD && !functionProtoPD.configurable) return;
|
||||
if (asserterName === 'arguments') return; // @see chaijs/chai/issues/69
|
||||
Object.defineProperty(assert, asserterName, pd);
|
||||
});
|
||||
// Use `__proto__` if available
|
||||
if (hasProtoSupport) {
|
||||
assert.__proto__ = this;
|
||||
}
|
||||
// Otherwise, redefine all properties (slow!)
|
||||
else {
|
||||
var asserterNames = Object.getOwnPropertyNames(ctx);
|
||||
asserterNames.forEach(function (asserterName) {
|
||||
if (!excludeNames.test(asserterName)) {
|
||||
var pd = Object.getOwnPropertyDescriptor(ctx, asserterName);
|
||||
Object.defineProperty(assert, asserterName, pd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
transferFlags(this, assert);
|
||||
return assert;
|
||||
|
@ -2778,6 +2799,8 @@
|
|||
|
||||
module.exports = _deepEqual;
|
||||
|
||||
var getEnumerableProperties = require('./getEnumerableProperties');
|
||||
|
||||
// for the browser
|
||||
var Buffer;
|
||||
try {
|
||||
|
@ -2862,8 +2885,8 @@
|
|||
return _deepEqual(a, b, memos);
|
||||
}
|
||||
try {
|
||||
var ka = Object.keys(a),
|
||||
kb = Object.keys(b),
|
||||
var ka = getEnumerableProperties(a),
|
||||
kb = getEnumerableProperties(b),
|
||||
key;
|
||||
} catch (e) {//happens when one is a string literal and the other isn't
|
||||
return false;
|
||||
|
@ -2957,6 +2980,35 @@
|
|||
|
||||
}); // module: chai/utils/getActual.js
|
||||
|
||||
require.register("chai/utils/getEnumerableProperties.js", function(module, exports, require){
|
||||
/*!
|
||||
* Chai - getEnumerableProperties utility
|
||||
* Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* ### .getEnumerableProperties(object)
|
||||
*
|
||||
* This allows the retrieval of enumerable property names of an object,
|
||||
* inherited or not.
|
||||
*
|
||||
* @param {Object} object
|
||||
* @returns {Array}
|
||||
* @name getEnumerableProperties
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function getEnumerableProperties(object) {
|
||||
var result = [];
|
||||
for (var name in object) {
|
||||
result.push(name);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
}); // module: chai/utils/getEnumerableProperties.js
|
||||
|
||||
require.register("chai/utils/getMessage.js", function(module, exports, require){
|
||||
/*!
|
||||
* Chai - message composition utility
|
||||
|
@ -3140,6 +3192,45 @@
|
|||
|
||||
}); // module: chai/utils/getPathValue.js
|
||||
|
||||
require.register("chai/utils/getProperties.js", function(module, exports, require){
|
||||
/*!
|
||||
* Chai - getProperties utility
|
||||
* Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* ### .getProperties(object)
|
||||
*
|
||||
* This allows the retrieval of property names of an object, enumerable or not,
|
||||
* inherited or not.
|
||||
*
|
||||
* @param {Object} object
|
||||
* @returns {Array}
|
||||
* @name getProperties
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function getProperties(object) {
|
||||
var result = Object.getOwnPropertyNames(subject);
|
||||
|
||||
function addProperty(property) {
|
||||
if (result.indexOf(property) === -1) {
|
||||
result.push(property);
|
||||
}
|
||||
}
|
||||
|
||||
var proto = Object.getPrototypeOf(subject);
|
||||
while (proto !== null) {
|
||||
Object.getOwnPropertyNames(proto).forEach(addProperty);
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
}); // module: chai/utils/getProperties.js
|
||||
|
||||
require.register("chai/utils/index.js", function(module, exports, require){
|
||||
/*!
|
||||
* chai
|
||||
|
@ -3251,6 +3342,8 @@
|
|||
// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js
|
||||
|
||||
var getName = require('./getName');
|
||||
var getProperties = require('./getProperties');
|
||||
var getEnumerableProperties = require('./getEnumerableProperties');
|
||||
|
||||
module.exports = inspect;
|
||||
|
||||
|
@ -3291,7 +3384,7 @@
|
|||
return html;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Returns true if object is a DOM element.
|
||||
var isDOMElement = function (object) {
|
||||
if (typeof HTMLElement === 'object') {
|
||||
|
@ -3327,8 +3420,8 @@
|
|||
}
|
||||
|
||||
// Look up the keys of the object.
|
||||
var visibleKeys = Object.keys(value);
|
||||
var keys = ctx.showHidden ? Object.getOwnPropertyNames(value) : visibleKeys;
|
||||
var visibleKeys = getEnumerableProperties(value);
|
||||
var keys = ctx.showHidden ? getProperties(value) : visibleKeys;
|
||||
|
||||
// Some type of object without properties can be shortcutted.
|
||||
// In IE, errors have a single `stack` property, or if they are vanilla `Error`,
|
||||
|
|
|
@ -30,5 +30,7 @@
|
|||
"devDependencies": {
|
||||
"folio": "0.3.x"
|
||||
, "mocha": "*"
|
||||
, "mocha-cloud": "*"
|
||||
, "connect": "2.7.x"
|
||||
}
|
||||
}
|
||||
|
|
120
support/mocha-cloud.js
Normal file
120
support/mocha-cloud.js
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*!
|
||||
* Mocha Cloud (SauceLabs) Test Runner
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Module dependencies
|
||||
*/
|
||||
|
||||
var Cloud = require('mocha-cloud')
|
||||
, connect = require('connect')
|
||||
, http = require('http')
|
||||
, resolve = require('path').resolve
|
||||
, auth;
|
||||
|
||||
/*!
|
||||
* Attempt to load saucelabs authentication
|
||||
*/
|
||||
|
||||
try {
|
||||
auth = require('../test/auth/sauce.json');
|
||||
} catch (ex) {
|
||||
console.error('Error loading SauceLabs authentication at "./test/auth/sauce.json"');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Create cloud and test server
|
||||
*/
|
||||
|
||||
var app = connect()
|
||||
, cloud = new Cloud('chai.js', auth.username, auth.key)
|
||||
, server = http.createServer(app);
|
||||
|
||||
/*!
|
||||
* Connect Middleware
|
||||
*/
|
||||
|
||||
app.use(connect.static(resolve(__dirname, '..')))
|
||||
|
||||
/*!
|
||||
* SauceLabs configuration
|
||||
*/
|
||||
|
||||
cloud.url('http://localhost:3000/test/browser/sauce.html');
|
||||
|
||||
/*!
|
||||
* Chrome
|
||||
*/
|
||||
|
||||
cloud.browser('chrome', null, 'Mac 10.6');
|
||||
cloud.browser('chrome', null, 'Mac 10.8');
|
||||
|
||||
/*!
|
||||
* Firefox
|
||||
*/
|
||||
|
||||
//cloud.browser('firefox', '17', 'Windows 2012');
|
||||
//cloud.browser('firefox', '18', 'Windows 2012');
|
||||
|
||||
/*!
|
||||
* Safari
|
||||
*/
|
||||
|
||||
// osx
|
||||
cloud.browser('safari', '5', 'Mac 10.6');
|
||||
cloud.browser('safari', '6', 'Mac 10.8');
|
||||
|
||||
// win
|
||||
//cloud.browser('safari', '5', 'Windows 2008');
|
||||
|
||||
/*!
|
||||
* Internet Explorer
|
||||
*/
|
||||
|
||||
//cloud.browser('iexplore', '10', 'Windows 2012');
|
||||
|
||||
/*!
|
||||
* iPad
|
||||
*/
|
||||
|
||||
cloud.browser('ipad', '4.3', 'Mac 10.6');
|
||||
cloud.browser('ipad', '5', 'Mac 10.6');
|
||||
cloud.browser('ipad', '5.1', 'Mac 10.8');
|
||||
cloud.browser('ipad', '6', 'Mac 10.8');
|
||||
|
||||
/*!
|
||||
* iPhone
|
||||
*/
|
||||
|
||||
cloud.browser('iphone', '4.3', 'Mac 10.6');
|
||||
cloud.browser('iphone', '5', 'Mac 10.6');
|
||||
cloud.browser('iphone', '5.1', 'Mac 10.8');
|
||||
cloud.browser('iphone', '6', 'Mac 10.8');
|
||||
|
||||
/*!
|
||||
* SauceLabs events
|
||||
*/
|
||||
|
||||
cloud.on('init', function (browser) {
|
||||
console.log(' init : %s %s', browser.browserName, browser.version);
|
||||
});
|
||||
|
||||
cloud.on('start', function (browser) {
|
||||
console.log(' start : %s %s', browser.browserName, browser.version);
|
||||
});
|
||||
|
||||
cloud.on('end', function (browser, res) {
|
||||
console.log(' end : %s %s : %d failures', browser.browserName, browser.version, res.failures);
|
||||
});
|
||||
|
||||
/*!
|
||||
* Start server
|
||||
*/
|
||||
|
||||
server.listen(3000, function () {
|
||||
cloud.start(function () {
|
||||
console.log('done');
|
||||
server.close();
|
||||
});
|
||||
});
|
0
test/auth/.gitkeep
Normal file
0
test/auth/.gitkeep
Normal file
249
test/browser/mocha-cloud-client.js
Normal file
249
test/browser/mocha-cloud-client.js
Normal file
|
@ -0,0 +1,249 @@
|
|||
;(function(){
|
||||
|
||||
|
||||
/**
|
||||
* hasOwnProperty.
|
||||
*/
|
||||
|
||||
var has = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* Require the given path.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Object} exports
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function require(path, parent, orig) {
|
||||
var resolved = require.resolve(path);
|
||||
|
||||
// lookup failed
|
||||
if (null == resolved) {
|
||||
orig = orig || path;
|
||||
parent = parent || 'root';
|
||||
var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
|
||||
err.path = orig;
|
||||
err.parent = parent;
|
||||
err.require = true;
|
||||
throw err;
|
||||
}
|
||||
|
||||
var module = require.modules[resolved];
|
||||
|
||||
// perform real require()
|
||||
// by invoking the module's
|
||||
// registered function
|
||||
if (!module.exports) {
|
||||
module.exports = {};
|
||||
module.client = module.component = true;
|
||||
module.call(this, module.exports, require.relative(resolved), module);
|
||||
}
|
||||
|
||||
return module.exports;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registered modules.
|
||||
*/
|
||||
|
||||
require.modules = {};
|
||||
|
||||
/**
|
||||
* Registered aliases.
|
||||
*/
|
||||
|
||||
require.aliases = {};
|
||||
|
||||
/**
|
||||
* Resolve `path`.
|
||||
*
|
||||
* Lookup:
|
||||
*
|
||||
* - PATH/index.js
|
||||
* - PATH.js
|
||||
* - PATH
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {String} path or null
|
||||
* @api private
|
||||
*/
|
||||
|
||||
require.resolve = function(path) {
|
||||
var index = path + '/index.js';
|
||||
|
||||
var paths = [
|
||||
path,
|
||||
path + '.js',
|
||||
path + '.json',
|
||||
path + '/index.js',
|
||||
path + '/index.json'
|
||||
];
|
||||
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
var path = paths[i];
|
||||
if (has.call(require.modules, path)) return path;
|
||||
}
|
||||
|
||||
if (has.call(require.aliases, index)) {
|
||||
return require.aliases[index];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize `path` relative to the current path.
|
||||
*
|
||||
* @param {String} curr
|
||||
* @param {String} path
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
require.normalize = function(curr, path) {
|
||||
var segs = [];
|
||||
|
||||
if ('.' != path.charAt(0)) return path;
|
||||
|
||||
curr = curr.split('/');
|
||||
path = path.split('/');
|
||||
|
||||
for (var i = 0; i < path.length; ++i) {
|
||||
if ('..' == path[i]) {
|
||||
curr.pop();
|
||||
} else if ('.' != path[i] && '' != path[i]) {
|
||||
segs.push(path[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return curr.concat(segs).join('/');
|
||||
};
|
||||
|
||||
/**
|
||||
* Register module at `path` with callback `definition`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} definition
|
||||
* @api private
|
||||
*/
|
||||
|
||||
require.register = function(path, definition) {
|
||||
require.modules[path] = definition;
|
||||
};
|
||||
|
||||
/**
|
||||
* Alias a module definition.
|
||||
*
|
||||
* @param {String} from
|
||||
* @param {String} to
|
||||
* @api private
|
||||
*/
|
||||
|
||||
require.alias = function(from, to) {
|
||||
if (!has.call(require.modules, from)) {
|
||||
throw new Error('Failed to alias "' + from + '", it does not exist');
|
||||
}
|
||||
require.aliases[to] = from;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a require function relative to the `parent` path.
|
||||
*
|
||||
* @param {String} parent
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
require.relative = function(parent) {
|
||||
var p = require.normalize(parent, '..');
|
||||
|
||||
/**
|
||||
* lastIndexOf helper.
|
||||
*/
|
||||
|
||||
function lastIndexOf(arr, obj) {
|
||||
var i = arr.length;
|
||||
while (i--) {
|
||||
if (arr[i] === obj) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The relative require() itself.
|
||||
*/
|
||||
|
||||
function localRequire(path) {
|
||||
var resolved = localRequire.resolve(path);
|
||||
return require(resolved, parent, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve relative to the parent.
|
||||
*/
|
||||
|
||||
localRequire.resolve = function(path) {
|
||||
// resolve deps by returning
|
||||
// the dep in the nearest "deps"
|
||||
// directory
|
||||
if ('.' != path.charAt(0)) {
|
||||
var segs = parent.split('/');
|
||||
var i = lastIndexOf(segs, 'deps') + 1;
|
||||
if (!i) i = 0;
|
||||
path = segs.slice(0, i + 1).join('/') + '/deps/' + path;
|
||||
return path;
|
||||
}
|
||||
return require.normalize(p, path);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if module is defined at `path`.
|
||||
*/
|
||||
|
||||
localRequire.exists = function(path) {
|
||||
return has.call(require.modules, localRequire.resolve(path));
|
||||
};
|
||||
|
||||
return localRequire;
|
||||
};
|
||||
require.register("mocha-cloud/client.js", function(exports, require, module){
|
||||
|
||||
/**
|
||||
* Listen to `runner` events to populate a global
|
||||
* `.mochaResults` var which may be used by selenium
|
||||
* to report on results.
|
||||
*
|
||||
* cloud(mocha.run());
|
||||
*
|
||||
* @param {Runner} runner
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function(runner){
|
||||
var failed = [];
|
||||
|
||||
runner.on('fail', function(test, err){
|
||||
failed.push({
|
||||
title: test.title,
|
||||
fullTitle: test.fullTitle(),
|
||||
error: {
|
||||
message: err.message,
|
||||
stack: err.stack
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
runner.on('end', function(){
|
||||
runner.stats.failed = failed;
|
||||
global.mochaResults = runner.stats;
|
||||
});
|
||||
};
|
||||
});
|
||||
require.alias("mocha-cloud/client.js", "mocha-cloud/index.js");
|
||||
|
||||
if (typeof exports == "object") {
|
||||
module.exports = require("mocha-cloud");
|
||||
} else if (typeof define == "function" && define.amd) {
|
||||
define(require("mocha-cloud"));
|
||||
} else {
|
||||
window["cloud"] = require("mocha-cloud");
|
||||
}})();
|
36
test/browser/sauce.html
Normal file
36
test/browser/sauce.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Mocha</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" href="../../node_modules/mocha/mocha.css" />
|
||||
<script src="../../node_modules/mocha/mocha.js"></script>
|
||||
<script src="./mocha-cloud-client.js"></script>
|
||||
<script>mocha.setup('tdd')</script>
|
||||
<script src="../../chai.js"></script>
|
||||
<script>
|
||||
err = function (fn, msg) {
|
||||
try {
|
||||
fn();
|
||||
throw new chai.AssertionError({ message: 'Expected an error' });
|
||||
} catch (err) {
|
||||
chai.expect(err.message).to.equal(msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script src="../configuration.js"></script>
|
||||
<script src="../expect.js"></script>
|
||||
<script src="../should.js"></script>
|
||||
<script src="../assert.js"></script>
|
||||
<script src="../plugins.js"></script>
|
||||
<script src="../utilities.js"></script>
|
||||
<script src="../globalShould.js"></script>
|
||||
<script>onload = function() {
|
||||
cloud(mocha.run());
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue