Extend expect.js rather than modify the source

This commit is contained in:
Tim Schaub
2014-07-06 12:40:03 -06:00
parent d8ca8e7341
commit 93716fc7f0
7 changed files with 281 additions and 1484 deletions

View File

@@ -21,6 +21,7 @@
},
"devDependencies": {
"closure-util": "0.19.0",
"expect.js": "~0.3.1",
"fs-extra": "~0.8.1",
"graceful-fs": "~3.0.2",
"jquery": "~2.1.1",

View File

@@ -4,9 +4,6 @@
- spec - includes the OpenLayers test/spec files.
- expect-0.2.0 - Minimalistic BDD-style assertion framework.
https://github.com/LearnBoost/expect.js/
- test-extensions.js - includes OpenLayers-specific extensions to the
testing frameworks.

File diff suppressed because it is too large Load Diff

View File

@@ -10,8 +10,7 @@
<div id="mocha"></div>
<script type="text/javascript" src="../node_modules/jquery/dist/jquery.min.js"></script>
<!-- Extended expect.js w/ various methods, see #374 for the differences to 0.2.0 -->
<script type="text/javascript" src="expect-0.2.0-ol3/expect.js"></script>
<script type="text/javascript" src="../node_modules/expect.js/index.js"></script>
<script type="text/javascript" src="../node_modules/sinon/pkg/sinon.js"></script>
<script type="text/javascript" src="../node_modules/mocha/mocha.js"></script>
<script type="text/javascript" src="test-extensions.js"></script>

View File

@@ -3,6 +3,21 @@ goog.provide('ol.test.expect.js');
describe('expect.js', function() {
describe('arreqlNaN', function() {
it('considers NaN in array to be equal', function() {
expect([1, NaN, 2]).to.arreqlNaN([1, NaN, 2]);
expect([1, NaN, 2]).not.to.arreqlNaN([1, 1.5, 2]);
});
it('allows a mix of number and string', function() {
expect([1, NaN, 'foo']).to.arreqlNaN([1, NaN, 'foo']);
expect([1, NaN, 'foo']).not.to.arreqlNaN([1, NaN, 'bar']);
expect([1, NaN]).not.to.arreqlNaN([1, 'foo']);
});
});
describe('roughlyEqual', function() {
it('can tell the difference between 1 and 3', function() {

View File

@@ -260,31 +260,31 @@ describe('ol.structs.Buffer', function() {
it('allows multiple adds and removes', function() {
var b = new ol.structs.Buffer(new Array(8), 0);
expect(b.add([0, 1])).to.be(0);
expect(b.getArray()).to.eql([0, 1, NaN, NaN, NaN, NaN, NaN, NaN]);
expect(b.getArray()).to.arreqlNaN([0, 1, NaN, NaN, NaN, NaN, NaN, NaN]);
expect(b.getCount()).to.be(2);
expect(b.add([2, 3, 4, 5])).to.be(2);
expect(b.getArray()).to.eql([0, 1, 2, 3, 4, 5, NaN, NaN]);
expect(b.getArray()).to.arreqlNaN([0, 1, 2, 3, 4, 5, NaN, NaN]);
expect(b.getCount()).to.be(6);
expect(b.add([6, 7])).to.be(6);
expect(b.getArray()).to.eql([0, 1, 2, 3, 4, 5, 6, 7]);
expect(b.getCount()).to.be(8);
b.remove(2, 2);
expect(b.getArray()).to.eql([0, 1, NaN, NaN, 4, 5, 6, 7]);
expect(b.getArray()).to.arreqlNaN([0, 1, NaN, NaN, 4, 5, 6, 7]);
expect(b.getCount()).to.be(6);
expect(b.add([8, 9])).to.be(2);
expect(b.getArray()).to.eql([0, 1, 8, 9, 4, 5, 6, 7]);
expect(b.getCount()).to.be(8);
b.remove(1, 1);
expect(b.getArray()).to.eql([0, NaN, 8, 9, 4, 5, 6, 7]);
expect(b.getArray()).to.arreqlNaN([0, NaN, 8, 9, 4, 5, 6, 7]);
expect(b.getCount()).to.be(7);
b.remove(4, 4);
expect(b.getArray()).to.eql([0, NaN, 8, 9, NaN, NaN, NaN, NaN]);
expect(b.getArray()).to.arreqlNaN([0, NaN, 8, 9, NaN, NaN, NaN, NaN]);
expect(b.getCount()).to.be(3);
expect(b.add([10, 11, 12])).to.be(4);
expect(b.getArray()).to.eql([0, NaN, 8, 9, 10, 11, 12, NaN]);
expect(b.getArray()).to.arreqlNaN([0, NaN, 8, 9, 10, 11, 12, NaN]);
expect(b.getCount()).to.be(6);
expect(b.add([13])).to.be(1);
expect(b.getArray()).to.eql([0, 13, 8, 9, 10, 11, 12, NaN]);
expect(b.getArray()).to.arreqlNaN([0, 13, 8, 9, 10, 11, 12, NaN]);
expect(b.getCount()).to.be(7);
});

View File

@@ -50,4 +50,261 @@
afterLoad('xml', path, next);
};
// extensions to expect.js
var expect = global.expect;
/**
* Assert value is within some tolerance of a number.
* @param {Number} n Number.
* @param {Number} tol Tolerance.
*/
expect.Assertion.prototype.roughlyEqual =
expect.Assertion.prototype.kindaEqual = function(n, tol) {
this.assert(
Math.abs(this.obj - n) <= tol,
function() {
return 'expected ' + expect.stringify(this.obj) + ' to be within ' +
tol + ' of ' + n;
},
function() {
return 'expected ' + expect.stringify(this.obj) +
' not to be within ' + tol + ' of ' + n;
});
return this;
};
/**
* Assert that a sinon spy was called.
*/
expect.Assertion.prototype.called =
expect.Assertion.prototype.totallyWantsToSpeakToYou = function() {
this.assert(
this.obj.called,
function() {
return 'expected ' + expect.stringify(this.obj) + ' to be called';
},
function() {
return 'expected ' + expect.stringify(this.obj) + ' not to be called';
});
return this;
};
function getChildNodes(node, options) {
// check whitespace
if (options && options.includeWhiteSpace) {
return node.childNodes;
} else {
var nodes = [];
for (var i = 0, ii=node.childNodes.length; i < ii; i++ ) {
var child = node.childNodes[i];
if (child.nodeType == 1) {
// element node, add it
nodes.push(child);
} else if (child.nodeType == 3) {
// text node, add if non empty
if (child.nodeValue &&
child.nodeValue.replace(/^\s*(.*?)\s*$/, '$1') != '') {
nodes.push(child);
}
}
}
return nodes;
}
};
function assertElementNodesEqual(node1, node2, options, errors) {
var testPrefix = (options && options.prefix === true);
try {
expect(node1.nodeType).to.equal(node2.nodeType);
} catch(e) {
errors.push('nodeType test failed for: ' + node1.nodeName + ' | ' + node2.nodeName + ' | ' + e.message);
}
if (testPrefix) {
try {
expect(node1.nodeName).to.equal(node2.nodeName);
} catch(e) {
errors.push('nodeName test failed for: ' + node1.nodeName + ' | ' + node2.nodeName + ' | ' + e.message);
}
} else {
try {
expect(node1.nodeName.split(':').pop()).to.equal(node2.nodeName.split(':').pop());
} catch(e) {
errors.push('nodeName test failed for: ' + node1.nodeName + ' | ' + node2.nodeName + ' | ' + e.message);
}
}
// for text nodes compare value
if (node1.nodeType === 3) {
try {
// TODO should we make this optional?
expect(node1.nodeValue.replace(/\s/g, '')).to.equal(node2.nodeValue.replace(/\s/g, ''));
} catch(e) {
errors.push('nodeValue test failed | ' + e.message);
}
}
// for element type nodes compare namespace, attributes, and children
else if (node1.nodeType === 1) {
// test namespace alias and uri
if (node1.prefix || node2.prefix) {
if (testPrefix) {
try {
expect(node1.prefix).to.equal(node2.prefix);
} catch(e) {
errors.push('Prefix test failed for: ' + node1.nodeName + ' | ' + e.message);
}
}
}
if (node1.namespaceURI || node2.namespaceURI) {
try {
expect(node1.namespaceURI).to.equal(node2.namespaceURI);
} catch(e) {
errors.push('namespaceURI test failed for: ' + node1.nodeName + ' | ' + e.message);
}
}
// compare attributes - disregard xmlns given namespace handling above
var node1AttrLen = 0;
var node1Attr = {};
var node2AttrLen = 0;
var node2Attr = {};
var ga, ea, gn, en;
var i, ii;
if (node1.attributes) {
for (i=0, ii=node1.attributes.length; i<ii; ++i) {
ga = node1.attributes[i];
if (ga.specified === undefined || ga.specified === true) {
if (ga.name.split(':').shift() != 'xmlns') {
gn = testPrefix ? ga.name : ga.name.split(':').pop();
node1Attr[gn] = ga;
++node1AttrLen;
}
}
}
}
if (node2.attributes) {
for (i=0, ii=node2.attributes.length; i<ii; ++i) {
ea = node2.attributes[i];
if (ea.specified === undefined || ea.specified === true) {
if (ea.name.split(':').shift() != 'xmlns') {
en = testPrefix ? ea.name : ea.name.split(':').pop();
node2Attr[en] = ea;
++node2AttrLen;
}
}
}
}
try {
expect(node1AttrLen).to.equal(node2AttrLen);
} catch(e) {
errors.push('Number of attributes test failed for: ' + node1.nodeName + ' | ' + e.message);
}
var gv, ev;
for (var name in node1Attr) {
if (node2Attr[name] === undefined) {
errors.push('Attribute name ' + node1Attr[name].name + ' expected for element ' + node1.nodeName);
}
// test attribute namespace
try {
// we do not care about the difference between an empty string and null for namespaceURI
// some tests will fail in IE9 otherwise
// see also http://msdn.microsoft.com/en-us/library/ff460650(v=vs.85).aspx
expect(node1Attr[name].namespaceURI || null).to.be(node2Attr[name].namespaceURI || null);
} catch(e) {
errors.push('namespaceURI attribute test failed for: ' + node1.nodeName + ' | ' + e.message);
}
try {
expect(node1Attr[name].value).to.equal(node2Attr[name].value);
} catch(e) {
errors.push('Attribute value test failed for: ' + node1.nodeName + ' | ' + e.message);
}
}
// compare children
var node1ChildNodes = getChildNodes(node1, options);
var node2ChildNodes = getChildNodes(node2, options);
try {
expect(node1ChildNodes.length).to.equal(node2ChildNodes.length);
} catch(e) {
errors.push('Number of childNodes test failed for: ' + node1.nodeName + ' | ' + e.message);
}
// only compare if they are equal
if (node1ChildNodes.length === node2ChildNodes.length) {
for (var j=0, jj=node1ChildNodes.length; j<jj; ++j) {
assertElementNodesEqual(node1ChildNodes[j], node2ChildNodes[j], options, errors);
}
}
}
};
/**
* Checks if the XML document sort of equals another XML document.
*/
expect.Assertion.prototype.xmleql = function(obj, options) {
if (obj && obj.nodeType == 9) {
obj = obj.documentElement;
}
if (this.obj && this.obj.nodeType == 9) {
this.obj = this.obj.documentElement;
}
var errors = [];
assertElementNodesEqual(obj, this.obj, options, errors);
var result = (errors.length === 0);
this.assert(
!!result,
function() {
return 'expected ' + expect.stringify(this.obj) +
' to sort of equal ' + expect.stringify(obj) + '\n' +
errors.join('\n');
},
function() {
return 'expected ' + expect.stringify(this.obj) +
' to sort of not equal ' + expect.stringify(obj) + '\n' +
errors.join('\n')
});
return this;
};
/**
* Checks if the array sort of equals another array.
*/
expect.Assertion.prototype.arreql = function (obj) {
this.assert(
goog.array.equals(this.obj, obj),
function() {
return 'expected ' + expect.stringify(this.obj) +
' to sort of equal ' + expect.stringify(obj);
},
function() {
return 'expected ' + expect.stringify(this.obj) +
' to sort of not equal ' + expect.stringify(obj);
});
return this;
};
/**
* Checks if the array sort of equals another array (allows NaNs to be equal).
*/
expect.Assertion.prototype.arreqlNaN = function (obj) {
function compare(a, b) {
return a === b || (typeof a === 'number' && typeof b === 'number' &&
isNaN(a) && isNaN(b));
}
this.assert(
goog.array.equals(this.obj, obj, compare),
function() {
return 'expected ' + expect.stringify(this.obj) +
' to sort of equal ' + expect.stringify(obj);
},
function() {
return 'expected ' + expect.stringify(this.obj) +
' to sort of not equal ' + expect.stringify(obj);
});
return this;
};
})(this);