Squashed matchers refactor - matchers now unit-testable apart from Expectation and Spec.
This commit is contained in:
51
GOALS_2.0.md
51
GOALS_2.0.md
@@ -18,37 +18,42 @@
|
|||||||
* New objects can have constructors on `jasmine`
|
* New objects can have constructors on `jasmine`
|
||||||
* Top level functions can live on `jasmine`
|
* Top level functions can live on `jasmine`
|
||||||
* Top level (i.e., any `jasmine` property) should only be referenced inside the `Env` constructor
|
* Top level (i.e., any `jasmine` property) should only be referenced inside the `Env` constructor
|
||||||
* Spies
|
* should better allow any object to get jasmine code (Node-friendly)
|
||||||
* isA functions:
|
* review everything in base.js
|
||||||
* isArray_ - used in matchers and spies
|
* Spies
|
||||||
* isString_
|
* break these out into their own tests/file
|
||||||
* isDOMNode_
|
* Remove isA functions:
|
||||||
* isA_
|
* isArray_ - used in matchers and spies
|
||||||
|
* isString_
|
||||||
|
* isDOMNode_
|
||||||
|
* isA_
|
||||||
* unimplementedMethod_, used by PrettyPrinter
|
* unimplementedMethod_, used by PrettyPrinter
|
||||||
* jasmine.util should be util closure inside of env or something
|
* jasmine.util should be util closure inside of env or something
|
||||||
* argsToArray is used for Spies and matching
|
* argsToArray is used for Spies and matching (and can be replaced)
|
||||||
* inherit is for how matchers are added/mixed in, reporters, and pretty printers
|
* inherit is only for PrettyPrinter now
|
||||||
* formatException is used only inside Env/spec
|
* formatException is used only inside Env/spec
|
||||||
* htmlEscape is for messages in matchers - should this be HTML at all? Is that * Matchers improvements
|
* htmlEscape is for messages in matchers - should this be HTML at all?
|
||||||
* move AddMatchers to Env & global (away from spec)
|
* Matchers improvements
|
||||||
* make matchers unit-testable
|
* unit testable DONE
|
||||||
* write doc on how to make a matcher
|
* better equality (from Underscore) DONE
|
||||||
|
* refactor equals function so that it just loops & recurses over a list of fns (custom and built-in) - 2.1?
|
||||||
|
* addCustomMatchers doesn't explode stack
|
||||||
|
* Pretty printing
|
||||||
|
* move away from pretty printer and to a JSON.stringify implementation?
|
||||||
|
* jasmineToString vs. custom toString ?
|
||||||
|
|
||||||
### Easy
|
### Easy
|
||||||
|
|
||||||
|
* unify params to ctors: options vs. attrs.
|
||||||
|
* This will be a lot of the TODOs, but clean up & simplify Env.js (is this a 2.1 task?)
|
||||||
|
|
||||||
## Other Topics
|
## Other Topics
|
||||||
|
|
||||||
* Build - can we, should we redo the build and release process AGAIN in order to make it less arcane
|
|
||||||
* Want to add JSHint to build
|
|
||||||
* Use a standard JS/Node based concat system instead of custom Ruby?
|
|
||||||
* Docs
|
* Docs
|
||||||
* JsDoc is a pain to host and RubyMine is pretty good at navigating. I say we kill it officially
|
|
||||||
* Docco has gone over well. Should we annotate all the sources and then have Pages be more complex, having tutorials and annotated source like Backbone? Are we small enough?
|
* Docco has gone over well. Should we annotate all the sources and then have Pages be more complex, having tutorials and annotated source like Backbone? Are we small enough?
|
||||||
|
* Need examples for:
|
||||||
# Build
|
* How to build a Custom Matcher
|
||||||
|
* How to add a custom equality tester
|
||||||
* lib -> generated
|
|
||||||
*
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
39
spec/core/AnySpec.js
Normal file
39
spec/core/AnySpec.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
describe("Any", function() {
|
||||||
|
it("matches a string", function() {
|
||||||
|
var any = new j$.Any(String);
|
||||||
|
|
||||||
|
expect(any.jasmineMatches("foo")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches a number", function() {
|
||||||
|
var any = new j$.Any(Number);
|
||||||
|
|
||||||
|
expect(any.jasmineMatches(1)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches a function", function() {
|
||||||
|
var any = new j$.Any(Function);
|
||||||
|
|
||||||
|
expect(any.jasmineMatches(function(){})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches an Object", function() {
|
||||||
|
var any = new j$.Any(Object);
|
||||||
|
|
||||||
|
expect(any.jasmineMatches({})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches another constructed object", function() {
|
||||||
|
var Thing = function() {},
|
||||||
|
any = new j$.Any(Thing);
|
||||||
|
|
||||||
|
expect(any.jasmineMatches(new Thing())).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("jasmineToString's itself", function() {
|
||||||
|
var any = new j$.Any(Number);
|
||||||
|
|
||||||
|
expect(any.jasmineToString()).toMatch('<jasmine.any');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -28,85 +28,6 @@ describe("Env", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("equality testing", function() {
|
|
||||||
describe("with custom equality testers", function() {
|
|
||||||
var aObj, bObj, isEqual;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
env.addEqualityTester(function(a, b) {
|
|
||||||
aObj = a;
|
|
||||||
bObj = b;
|
|
||||||
return isEqual;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the custom equality tester with two objects for comparison", function() {
|
|
||||||
env.equals_("1", "2");
|
|
||||||
expect(aObj).toEqual("1");
|
|
||||||
expect(bObj).toEqual("2");
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when the custom equality tester returns false", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
isEqual = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should give custom equality testers precedence", function() {
|
|
||||||
expect(env.equals_('abc', 'abc')).toBeFalsy();
|
|
||||||
var o = {};
|
|
||||||
expect(env.equals_(o, o)).toBeFalsy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe("when the custom equality tester returns true", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
isEqual = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should give custom equality testers precedence", function() {
|
|
||||||
expect(env.equals_('abc', 'def')).toBeTruthy();
|
|
||||||
expect(env.equals_(true, false)).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when the custom equality tester returns undefined", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
isEqual = jasmine.undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should use normal equality rules", function() {
|
|
||||||
expect(env.equals_('abc', 'abc')).toBeTruthy();
|
|
||||||
expect(env.equals_('abc', 'def')).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("even if there are several", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
env.addEqualityTester(function(a, b) {
|
|
||||||
return jasmine.undefined;
|
|
||||||
});
|
|
||||||
env.addEqualityTester(function(a, b) {
|
|
||||||
return jasmine.undefined;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should use normal equality rules", function() {
|
|
||||||
expect(env.equals_('abc', 'abc')).toBeTruthy();
|
|
||||||
expect(env.equals_('abc', 'def')).toBeFalsy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should evaluate custom equality testers in the order they are declared", function() {
|
|
||||||
isEqual = false;
|
|
||||||
env.addEqualityTester(function(a, b) {
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
expect(env.equals_('abc', 'abc')).toBeFalsy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#catchException", function() {
|
describe("#catchException", function() {
|
||||||
it("returns true if the exception is a pending spec exception", function() {
|
it("returns true if the exception is a pending spec exception", function() {
|
||||||
env.catchExceptions(false);
|
env.catchExceptions(false);
|
||||||
@@ -129,8 +50,10 @@ describe("Env", function() {
|
|||||||
}).toThrow(j$.Spec.pendingSpecExceptionMessage);
|
}).toThrow(j$.Spec.pendingSpecExceptionMessage);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: move these into a separate file
|
||||||
describe("Env (integration)", function() {
|
describe("Env (integration)", function() {
|
||||||
|
|
||||||
it("Suites execute as expected (no nesting)", function() {
|
it("Suites execute as expected (no nesting)", function() {
|
||||||
@@ -301,4 +224,100 @@ describe("Env (integration)", function() {
|
|||||||
expect(nestedSpec.getFullName()).toBe("my tests are sometimes singly nested.");
|
expect(nestedSpec.getFullName()).toBe("my tests are sometimes singly nested.");
|
||||||
expect(doublyNestedSpec.getFullName()).toBe("my tests are sometimes even doubly nested.");
|
expect(doublyNestedSpec.getFullName()).toBe("my tests are sometimes even doubly nested.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Custom equality testers should be per spec", function() {
|
||||||
|
var env = new j$.Env({global: { setTimeout: setTimeout }}),
|
||||||
|
reporter = jasmine.createSpyObj('fakeReproter', [
|
||||||
|
"jasmineStarted",
|
||||||
|
"jasmineDone",
|
||||||
|
"suiteStarted",
|
||||||
|
"suiteDone",
|
||||||
|
"specStarted",
|
||||||
|
"specDone"
|
||||||
|
]);
|
||||||
|
|
||||||
|
env.addReporter(reporter);
|
||||||
|
|
||||||
|
env.describe("testing custom equality testers", function() {
|
||||||
|
env.it("with a custom tester", function() {
|
||||||
|
env.addCustomEqualityTester(function(a, b) { return true; });
|
||||||
|
env.expect("a").toEqual("b");
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it("without a custom tester", function() {
|
||||||
|
env.expect("a").toEqual("b");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.execute();
|
||||||
|
|
||||||
|
var firstSpecResult = reporter.specDone.argsForCall[0][0],
|
||||||
|
secondSpecResult = reporter.specDone.argsForCall[1][0];
|
||||||
|
|
||||||
|
expect(firstSpecResult.status).toEqual("passed");
|
||||||
|
expect(secondSpecResult.status).toEqual("failed");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Custom matchers should be per spec", function() {
|
||||||
|
var env = new j$.Env({global: { setTimeout: setTimeout }}),
|
||||||
|
matchers = {
|
||||||
|
toFoo: function() {}
|
||||||
|
},
|
||||||
|
reporter = jasmine.createSpyObj('fakeReproter', [
|
||||||
|
"jasmineStarted",
|
||||||
|
"jasmineDone",
|
||||||
|
"suiteStarted",
|
||||||
|
"suiteDone",
|
||||||
|
"specStarted",
|
||||||
|
"specDone"
|
||||||
|
]);
|
||||||
|
|
||||||
|
env.addReporter(reporter);
|
||||||
|
|
||||||
|
env.describe("testing custom matchers", function() {
|
||||||
|
env.it("with a custom matcher", function() {
|
||||||
|
env.addMatchers(matchers);
|
||||||
|
expect(env.expect().toFoo).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it("without a custom matcher", function() {
|
||||||
|
expect(env.expect().toFoo).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.execute();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Custom equality testers for toContain should be per spec", function() {
|
||||||
|
var env = new j$.Env({global: { setTimeout: setTimeout }}),
|
||||||
|
reporter = jasmine.createSpyObj('fakeReproter', [
|
||||||
|
"jasmineStarted",
|
||||||
|
"jasmineDone",
|
||||||
|
"suiteStarted",
|
||||||
|
"suiteDone",
|
||||||
|
"specStarted",
|
||||||
|
"specDone"
|
||||||
|
]);
|
||||||
|
|
||||||
|
env.addReporter(reporter);
|
||||||
|
|
||||||
|
env.describe("testing custom equality testers", function() {
|
||||||
|
env.it("with a custom tester", function() {
|
||||||
|
env.addCustomEqualityTester(function(a, b) { return true; });
|
||||||
|
env.expect(["a"]).toContain("b");
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it("without a custom tester", function() {
|
||||||
|
env.expect("a").toContain("b");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.execute();
|
||||||
|
|
||||||
|
var firstSpecResult = reporter.specDone.argsForCall[0][0],
|
||||||
|
secondSpecResult = reporter.specDone.argsForCall[1][0];
|
||||||
|
|
||||||
|
expect(firstSpecResult.status).toEqual("passed");
|
||||||
|
expect(secondSpecResult.status).toEqual("failed");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
320
spec/core/ExpectationSpec.js
Normal file
320
spec/core/ExpectationSpec.js
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
describe("Expectation", function() {
|
||||||
|
it(".addMatchers makes matchers available to any expectation", function() {
|
||||||
|
var matchers = {
|
||||||
|
toFoo: function() {},
|
||||||
|
toBar: function() {}
|
||||||
|
},
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addMatchers(matchers);
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({});
|
||||||
|
|
||||||
|
expect(expectation.toFoo).toBeDefined();
|
||||||
|
expect(expectation.toBar).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(".addCoreMatchers makes matchers available to any expectation", function() {
|
||||||
|
var coreMatchers = {
|
||||||
|
toQuux: function() {}
|
||||||
|
},
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addCoreMatchers(coreMatchers);
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({});
|
||||||
|
|
||||||
|
expect(expectation.toQuux).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(".resetMatchers should keep only core matchers", function() {
|
||||||
|
var matchers = {
|
||||||
|
toFoo: function() {}
|
||||||
|
},
|
||||||
|
coreMatchers = {
|
||||||
|
toQuux: function() {}
|
||||||
|
},
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addCoreMatchers(coreMatchers);
|
||||||
|
j$.Expectation.addMatchers(matchers);
|
||||||
|
j$.Expectation.resetMatchers();
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({});
|
||||||
|
|
||||||
|
expect(expectation.toQuux).toBeDefined();
|
||||||
|
expect(expectation.toFoo).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Factory builds an expectaion/negative expectation", function() {
|
||||||
|
var builtExpectation = j$.Expectation.Factory();
|
||||||
|
|
||||||
|
expect(builtExpectation instanceof j$.Expectation).toBe(true);
|
||||||
|
expect(builtExpectation.not instanceof j$.Expectation).toBe(true);
|
||||||
|
expect(builtExpectation.not.isNot).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("wraps matchers's compare functions, passing in matcher dependencies", function() {
|
||||||
|
var fakeCompare = function() { return { pass: true }; },
|
||||||
|
matcherFactory = jasmine.createSpy("matcher").andReturn({ compare: fakeCompare }),
|
||||||
|
matchers = {
|
||||||
|
toFoo: matcherFactory
|
||||||
|
},
|
||||||
|
util = {},
|
||||||
|
customEqualityTesters = ['a'],
|
||||||
|
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addMatchers(matchers);
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({
|
||||||
|
util: util,
|
||||||
|
customEqualityTesters: customEqualityTesters,
|
||||||
|
actual: "an actual",
|
||||||
|
addExpectationResult: addExpectationResult
|
||||||
|
});
|
||||||
|
|
||||||
|
expectation.toFoo("hello");
|
||||||
|
|
||||||
|
expect(matcherFactory).toHaveBeenCalledWith(util, customEqualityTesters)
|
||||||
|
});
|
||||||
|
|
||||||
|
it("wraps matchers's compare functions, passing the actual and expected", function() {
|
||||||
|
var fakeCompare = jasmine.createSpy('fake-compare').andReturn({pass: true}),
|
||||||
|
matchers = {
|
||||||
|
toFoo: function() {
|
||||||
|
return {
|
||||||
|
compare: fakeCompare
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
util = {
|
||||||
|
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
|
||||||
|
},
|
||||||
|
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addMatchers(matchers);
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({
|
||||||
|
util: util,
|
||||||
|
actual: "an actual",
|
||||||
|
addExpectationResult: addExpectationResult
|
||||||
|
});
|
||||||
|
|
||||||
|
expectation.toFoo("hello");
|
||||||
|
|
||||||
|
expect(fakeCompare).toHaveBeenCalledWith("an actual", "hello");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports a passing result to the spec when the comparison passes", function() {
|
||||||
|
var matchers = {
|
||||||
|
toFoo: function() {
|
||||||
|
return {
|
||||||
|
compare: function() { return { pass: true }; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
util = {
|
||||||
|
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
|
||||||
|
},
|
||||||
|
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addMatchers(matchers);
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({
|
||||||
|
matchers: matchers,
|
||||||
|
util: util,
|
||||||
|
actual: "an actual",
|
||||||
|
addExpectationResult: addExpectationResult
|
||||||
|
});
|
||||||
|
|
||||||
|
expectation.toFoo("hello");
|
||||||
|
|
||||||
|
expect(addExpectationResult).toHaveBeenCalledWith(true, {
|
||||||
|
matcherName: "toFoo",
|
||||||
|
passed: true,
|
||||||
|
message: "",
|
||||||
|
expected: "hello",
|
||||||
|
actual: "an actual"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports a failing result to the spec when the comparison fails", function() {
|
||||||
|
var matchers = {
|
||||||
|
toFoo: function() {
|
||||||
|
return {
|
||||||
|
compare: function() { return { pass: false }; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
util = {
|
||||||
|
buildFailureMessage: function() { return ""; }
|
||||||
|
},
|
||||||
|
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addMatchers(matchers);
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({
|
||||||
|
matchers: matchers,
|
||||||
|
util: util,
|
||||||
|
actual: "an actual",
|
||||||
|
addExpectationResult: addExpectationResult
|
||||||
|
});
|
||||||
|
|
||||||
|
expectation.toFoo("hello");
|
||||||
|
|
||||||
|
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||||
|
matcherName: "toFoo",
|
||||||
|
passed: false,
|
||||||
|
expected: "hello",
|
||||||
|
actual: "an actual",
|
||||||
|
message: ""
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports a failing result and a custom fail message to the spec when the comparison fails", function() {
|
||||||
|
var matchers = {
|
||||||
|
toFoo: function() {
|
||||||
|
return {
|
||||||
|
compare: function() {
|
||||||
|
return {
|
||||||
|
pass: false,
|
||||||
|
message: "I am a custom message"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addMatchers(matchers);
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({
|
||||||
|
matchers: matchers,
|
||||||
|
actual: "an actual",
|
||||||
|
addExpectationResult: addExpectationResult
|
||||||
|
});
|
||||||
|
|
||||||
|
expectation.toFoo("hello");
|
||||||
|
|
||||||
|
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||||
|
matcherName: "toFoo",
|
||||||
|
passed: false,
|
||||||
|
expected: "hello",
|
||||||
|
actual: "an actual",
|
||||||
|
message: "I am a custom message"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports a passing result to the spec when the comparison fails for a negative expectation", function() {
|
||||||
|
var matchers = {
|
||||||
|
toFoo: function() {
|
||||||
|
return {
|
||||||
|
compare: function() { return { pass: false }; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
util = {
|
||||||
|
buildFailureMessage: function() { return ""; }
|
||||||
|
},
|
||||||
|
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||||
|
actual = "an actual",
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addMatchers(matchers);
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({
|
||||||
|
matchers: matchers,
|
||||||
|
actual: "an actual",
|
||||||
|
addExpectationResult: addExpectationResult,
|
||||||
|
isNot: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expectation.toFoo("hello");
|
||||||
|
|
||||||
|
expect(addExpectationResult).toHaveBeenCalledWith(true, {
|
||||||
|
matcherName: "toFoo",
|
||||||
|
passed: true,
|
||||||
|
message: "",
|
||||||
|
expected: "hello",
|
||||||
|
actual: actual
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports a failing result to the spec when the comparison passes for a negative expectation", function() {
|
||||||
|
var matchers = {
|
||||||
|
toFoo: function() {
|
||||||
|
return {
|
||||||
|
compare: function() { return { pass: true }; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
util = {
|
||||||
|
buildFailureMessage: function() { return "default messge"; }
|
||||||
|
},
|
||||||
|
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||||
|
actual = "an actual",
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addMatchers(matchers);
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({
|
||||||
|
matchers: matchers,
|
||||||
|
actual: "an actual",
|
||||||
|
util: util,
|
||||||
|
addExpectationResult: addExpectationResult,
|
||||||
|
isNot: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expectation.toFoo("hello");
|
||||||
|
|
||||||
|
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||||
|
matcherName: "toFoo",
|
||||||
|
passed: false,
|
||||||
|
expected: "hello",
|
||||||
|
actual: actual,
|
||||||
|
message: "default messge"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports a failing result and a custom fail message to the spec when the comparison passes for a negative expectation", function() {
|
||||||
|
var matchers = {
|
||||||
|
toFoo: function() {
|
||||||
|
return {
|
||||||
|
compare: function() {
|
||||||
|
return {
|
||||||
|
pass: true,
|
||||||
|
message: "I am a custom message"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||||
|
actual = "an actual",
|
||||||
|
expectation;
|
||||||
|
|
||||||
|
j$.Expectation.addMatchers(matchers);
|
||||||
|
|
||||||
|
expectation = new j$.Expectation({
|
||||||
|
matchers: matchers,
|
||||||
|
actual: "an actual",
|
||||||
|
addExpectationResult: addExpectationResult,
|
||||||
|
isNot: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expectation.toFoo("hello");
|
||||||
|
|
||||||
|
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||||
|
matcherName: "toFoo",
|
||||||
|
passed: false,
|
||||||
|
expected: "hello",
|
||||||
|
actual: actual,
|
||||||
|
message: "I am a custom message"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
File diff suppressed because it is too large
Load Diff
38
spec/core/ObjectContainingSpec.js
Normal file
38
spec/core/ObjectContainingSpec.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
describe("ObjectContaining", function() {
|
||||||
|
|
||||||
|
it("matches any actual to an empty object", function() {
|
||||||
|
var containing = new j$.ObjectContaining({});
|
||||||
|
|
||||||
|
expect(containing.jasmineMatches("foo")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not match an empty object actual", function() {
|
||||||
|
var containing = new j$.ObjectContaining("foo");
|
||||||
|
|
||||||
|
expect(containing.jasmineMatches({})).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches when the key/value pair is present in the actual", function() {
|
||||||
|
var containing = new jasmine.Matchers.ObjectContaining({foo: "fooVal"});
|
||||||
|
|
||||||
|
expect(containing.jasmineMatches({foo: "fooVal", bar: "barVal"})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not match when the key/value pair is not present in the actual", function() {
|
||||||
|
var containing = new jasmine.Matchers.ObjectContaining({foo: "fooVal"});
|
||||||
|
|
||||||
|
expect(containing.jasmineMatches({bar: "barVal", quux: "quuxVal"})).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not match when the key is present but the value is different in the actual", function() {
|
||||||
|
var containing = new jasmine.Matchers.ObjectContaining({foo: "other"});
|
||||||
|
|
||||||
|
expect(containing.jasmineMatches({foo: "fooVal", bar: "barVal"})).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("jasmineToString's itself", function() {
|
||||||
|
var containing = new j$.ObjectContaining({});
|
||||||
|
|
||||||
|
expect(containing.jasmineToString()).toMatch("<jasmine.objectContaining");
|
||||||
|
});
|
||||||
|
});
|
||||||
600
spec/core/matchersSpec.js
Normal file
600
spec/core/matchersSpec.js
Normal file
@@ -0,0 +1,600 @@
|
|||||||
|
describe("Matchers", function() {
|
||||||
|
describe("toBe", function() {
|
||||||
|
it("passes when actual === expected", function() {
|
||||||
|
var matcher = j$.matchers.toBe(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(1, 1);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when actual !== expected", function() {
|
||||||
|
var matcher = j$.matchers.toBe(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(1, 2);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toBeCloseTo", function() {
|
||||||
|
it("passes when within two decimal places by default", function() {
|
||||||
|
var matcher = j$.matchers.toBeCloseTo(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(0, 0);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare(0, 0.001);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when not within two decimal places by default", function() {
|
||||||
|
var matcher = j$.matchers.toBeCloseTo(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(0, 0.01);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("accepts an optional precision argument", function() {
|
||||||
|
var matcher = j$.matchers.toBeCloseTo(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(0, 0.1, 0);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare(0, 0.0001, 3);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rounds expected values", function() {
|
||||||
|
var matcher = j$.matchers.toBeCloseTo(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(1.23, 1.229);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare(1.23, 1.226);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare(1.23, 1.225);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare(1.23, 1.2249999);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare(1.23, 1.234);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toBeDefined", function() {
|
||||||
|
it("matches for defined values", function() {
|
||||||
|
var matcher = j$.matchers.toBeDefined(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
|
||||||
|
result = matcher.compare('foo');
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when matching undefined values", function() {
|
||||||
|
var matcher = j$.matchers.toBeDefined(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(void 0);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toBeFalsy", function() {
|
||||||
|
it("passes for 'falsy' values", function() {
|
||||||
|
var matcher = j$.matchers.toBeFalsy(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(false);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare(0);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare('');
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare(null);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare(void 0);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for 'truthy' values", function() {
|
||||||
|
var matcher = j$.matchers.toBeFalsy(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(true);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare(1);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare("foo");
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare({});
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toBeGreaterThan", function() {
|
||||||
|
it("passes when actual > expected", function() {
|
||||||
|
var matcher = j$.matchers.toBeGreaterThan(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(2, 1);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when actual <= expected", function() {
|
||||||
|
var matcher = j$.matchers.toBeGreaterThan();
|
||||||
|
|
||||||
|
result = matcher.compare(1, 1);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare(1, 2);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toBeLessThan", function() {
|
||||||
|
it("passes when actual < expected", function() {
|
||||||
|
var matcher = j$.matchers.toBeLessThan(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(1, 2);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when actual <= expected", function() {
|
||||||
|
var matcher = j$.matchers.toBeLessThan(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(1, 1);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare(2, 1);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toBeNaN", function() {
|
||||||
|
it("passes for NaN with a custom .not fail", function() {
|
||||||
|
var matcher = j$.matchers.toBeNaN(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(Number.NaN);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
expect(result.message).toEqual("Expected actual not to be NaN.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for anything not a NaN", function() {
|
||||||
|
var matcher = j$.matchers.toBeNaN();
|
||||||
|
|
||||||
|
result = matcher.compare(1);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare(null);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare(void 0);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare('');
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare(Number.POSITIVE_INFINITY);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has a custom message on failure", function() {
|
||||||
|
var matcher = j$.matchers.toBeNaN(),
|
||||||
|
result = matcher.compare(0);
|
||||||
|
|
||||||
|
expect(result.message).toEqual("Expected 0 to be NaN.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toBeNull", function() {
|
||||||
|
it("passes for null", function() {
|
||||||
|
var matcher = j$.matchers.toBeNull(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(null);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for non-null", function() {
|
||||||
|
var matcher = j$.matchers.toBeNull(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare('foo');
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toBeTruthy", function() {
|
||||||
|
it("passes for 'truthy' values", function() {
|
||||||
|
var matcher = j$.matchers.toBeTruthy(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(true);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare(1);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare("foo");
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
result = matcher.compare({});
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for 'falsy' values", function() {
|
||||||
|
var matcher = j$.matchers.toBeTruthy(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(false);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare(0);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare('');
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare(null);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
|
||||||
|
result = matcher.compare(void 0);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toBeUndefined", function() {
|
||||||
|
it("passes for undefined values", function() {
|
||||||
|
var matcher = j$.matchers.toBeUndefined(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(void 0);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when matching defined values", function() {
|
||||||
|
var matcher = j$.matchers.toBeUndefined();
|
||||||
|
|
||||||
|
result = matcher.compare('foo');
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toContain", function() {
|
||||||
|
it("delegates to j$.matchersUtil.contains", function() {
|
||||||
|
var util = {
|
||||||
|
contains: j$.createSpy('delegated-contains').andReturn(true)
|
||||||
|
},
|
||||||
|
matcher = j$.matchers.toContain(util);
|
||||||
|
|
||||||
|
result = matcher.compare("ABC", "B");
|
||||||
|
expect(util.contains).toHaveBeenCalledWith("ABC", "B", []);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("delegates to j$.matchersUtil.contains, passing in equality testers if present", function() {
|
||||||
|
var util = {
|
||||||
|
contains: j$.createSpy('delegated-contains').andReturn(true)
|
||||||
|
},
|
||||||
|
customEqualityTesters = ['a', 'b'],
|
||||||
|
matcher = j$.matchers.toContain(util, customEqualityTesters);
|
||||||
|
|
||||||
|
result = matcher.compare("ABC", "B");
|
||||||
|
expect(util.contains).toHaveBeenCalledWith("ABC", "B", ['a', 'b']);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toEqual", function() {
|
||||||
|
it("delegates to equals function", function() {
|
||||||
|
var util = {
|
||||||
|
equals: j$.createSpy('delegated-equals').andReturn(true)
|
||||||
|
},
|
||||||
|
matcher = j$.matchers.toEqual(util),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(1, 1);
|
||||||
|
|
||||||
|
expect(util.equals).toHaveBeenCalledWith(1, 1, []);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("delegates custom equality testers, if present", function() {
|
||||||
|
var util = {
|
||||||
|
equals: j$.createSpy('delegated-equals').andReturn(true)
|
||||||
|
},
|
||||||
|
customEqualityTesters = ['a', 'b'],
|
||||||
|
matcher = j$.matchers.toEqual(util, customEqualityTesters),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(1, 1);
|
||||||
|
|
||||||
|
expect(util.equals).toHaveBeenCalledWith(1, 1, ['a', 'b']);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toHaveBeenCalled", function() {
|
||||||
|
it("passes when the actual was called, with a custom .not fail message", function() {
|
||||||
|
var matcher = j$.matchers.toHaveBeenCalled(),
|
||||||
|
calledSpy = j$.createSpy('called-spy'),
|
||||||
|
result;
|
||||||
|
|
||||||
|
calledSpy();
|
||||||
|
|
||||||
|
result = matcher.compare(calledSpy);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
expect(result.message).toEqual("Expected spy called-spy not to have been called.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when the actual was not called", function() {
|
||||||
|
var matcher = j$.matchers.toHaveBeenCalled(),
|
||||||
|
uncalledSpy = j$.createSpy('uncalled spy');
|
||||||
|
|
||||||
|
result = matcher.compare(uncalledSpy);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws an exception when the actual is not a spy", function() {
|
||||||
|
var matcher = j$.matchers.toHaveBeenCalled(),
|
||||||
|
fn = function() {};
|
||||||
|
|
||||||
|
expect(function() { matcher.compare(fn) }).toThrow(new Error("Expected a spy, but got Function."));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws an exception when invoked with any arguments", function() {
|
||||||
|
var matcher = j$.matchers.toHaveBeenCalled(),
|
||||||
|
spy = j$.createSpy('sample spy');
|
||||||
|
|
||||||
|
expect(function() { matcher.compare(spy, 'foo') }).toThrow(new Error("toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has a custom message on failure", function() {
|
||||||
|
var matcher = j$.matchers.toHaveBeenCalled(),
|
||||||
|
spy = j$.createSpy('sample-spy'),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(spy);
|
||||||
|
|
||||||
|
expect(result.message).toEqual("Expected spy sample-spy to have been called.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toHaveBeenCalledWith", function() {
|
||||||
|
it("passes when the actual was called with matching parameters", function() {
|
||||||
|
var util = {
|
||||||
|
contains: j$.createSpy('delegated-contains').andReturn(true)
|
||||||
|
},
|
||||||
|
matcher = j$.matchers.toHaveBeenCalledWith(util)
|
||||||
|
calledSpy = j$.createSpy('called-spy'),
|
||||||
|
result;
|
||||||
|
|
||||||
|
calledSpy('a', 'b');
|
||||||
|
result = matcher.compare(calledSpy, 'a', 'b');
|
||||||
|
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when the actual was not called", function() {
|
||||||
|
var util = {
|
||||||
|
contains: j$.createSpy('delegated-contains').andReturn(false)
|
||||||
|
},
|
||||||
|
matcher = j$.matchers.toHaveBeenCalledWith(util),
|
||||||
|
uncalledSpy = j$.createSpy('uncalled spy'),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(uncalledSpy);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when the actual was called with different parameters", function() {
|
||||||
|
var util = {
|
||||||
|
contains: j$.createSpy('delegated-contains').andReturn(false)
|
||||||
|
},
|
||||||
|
matcher = j$.matchers.toHaveBeenCalledWith(util),
|
||||||
|
calledSpy = j$.createSpy('called spy'),
|
||||||
|
result;
|
||||||
|
|
||||||
|
calledSpy('a');
|
||||||
|
result = matcher.compare(calledSpy, 'a', 'b');
|
||||||
|
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws an exception when the actual is not a spy", function() {
|
||||||
|
var matcher = j$.matchers.toHaveBeenCalledWith(),
|
||||||
|
fn = function() {};
|
||||||
|
|
||||||
|
expect(function() { matcher.compare(fn) }).toThrow(new Error("Expected a spy, but got Function."));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has a custom message on failure", function() {
|
||||||
|
var matcher = j$.matchers.toHaveBeenCalledWith(),
|
||||||
|
spy = j$.createSpy('sample-spy'),
|
||||||
|
messages = matcher.message(spy);
|
||||||
|
|
||||||
|
expect(messages.affirmative).toEqual("Expected spy sample-spy to have been called.")
|
||||||
|
expect(messages.negative).toEqual("Expected spy sample-spy not to have been called.")
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toMatch", function() {
|
||||||
|
it("passes when RegExps are equivalent", function() {
|
||||||
|
var matcher = j$.matchers.toMatch(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(/foo/, /foo/);
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when RegExps are not equivalent", function() {
|
||||||
|
var matcher = j$.matchers.toMatch(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(/bar/, /foo/);
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes when the actual matches the expected string as a pattern", function() {
|
||||||
|
var matcher = j$.matchers.toMatch(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare('foosball', 'foo');
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when the actual matches the expected string as a pattern", function() {
|
||||||
|
var matcher = j$.matchers.toMatch(),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare('bar', 'foo');
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("toThrow", function() {
|
||||||
|
it("throw an error when the acutal is not a function ", function() {
|
||||||
|
var matcher = j$.matchers.toThrow();
|
||||||
|
|
||||||
|
expect(function() {
|
||||||
|
matcher.compare({});
|
||||||
|
}).toThrow(new Error("Actual is not a Function"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws an error when the expected can't be turned into an exception", function() {
|
||||||
|
var matcher = j$.matchers.toThrow(),
|
||||||
|
fn = function() {
|
||||||
|
throw "foo";
|
||||||
|
},
|
||||||
|
result;
|
||||||
|
|
||||||
|
expect(function() {
|
||||||
|
matcher.compare(fn, 1);
|
||||||
|
}).toThrow(new Error("Expected cannot be treated as an exception."));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes if the actual throws any exception", function() {
|
||||||
|
var matcher = j$.matchers.toThrow(),
|
||||||
|
fn = function() {
|
||||||
|
throw "foo";
|
||||||
|
},
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(fn);
|
||||||
|
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
expect(result.message).toEqual("Expected function not to throw an exception.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails if the actual does not throw an exception", function() {
|
||||||
|
var matcher = j$.matchers.toThrow(),
|
||||||
|
fn = function() {
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(fn);
|
||||||
|
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
expect(result.message).toEqual("Expected function to throw an exception.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes if the actual throws an exception with the expected message", function() {
|
||||||
|
var matcher = j$.matchers.toThrow(),
|
||||||
|
fn = function() {
|
||||||
|
throw "foo";
|
||||||
|
},
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(fn, "foo");
|
||||||
|
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
expect(result.message).toEqual("Expected function not to throw an exception \"foo\".");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails if the actual throws an exception with a different message", function() {
|
||||||
|
var matcher = j$.matchers.toThrow(),
|
||||||
|
fn = function() {
|
||||||
|
throw "foo";
|
||||||
|
},
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(fn, "bar");
|
||||||
|
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
expect(result.message).toEqual("Expected function to throw an exception \"bar\".");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes if the actual throws an exception and matches the message of the expected exception", function() {
|
||||||
|
var matcher = j$.matchers.toThrow(),
|
||||||
|
fn = function() {
|
||||||
|
throw "foo";
|
||||||
|
},
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(fn, new Error("foo"));
|
||||||
|
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
expect(result.message).toEqual("Expected function not to throw an exception \"foo\".");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails if the actual throws an exception and it does not match the message of the expected exception with a custom message", function() {
|
||||||
|
var matcher = j$.matchers.toThrow(),
|
||||||
|
fn = function() {
|
||||||
|
throw "foo";
|
||||||
|
},
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(fn, new Error("bar"));
|
||||||
|
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
expect(result.message).toEqual("Expected function to throw an exception \"bar\".");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes if the actual throws an exception and the message matches the expected regular expression", function() {
|
||||||
|
var matcher = j$.matchers.toThrow(),
|
||||||
|
fn = function() {
|
||||||
|
throw "a long message";
|
||||||
|
},
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(fn, /long/);
|
||||||
|
|
||||||
|
expect(result.pass).toBe(true);
|
||||||
|
expect(result.message).toEqual("Expected function not to throw an exception matching /long/.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails if the actual throws an exception and the message does not match the expected regular expression", function() {
|
||||||
|
var matcher = j$.matchers.toThrow(),
|
||||||
|
fn = function() {
|
||||||
|
throw "a long message";
|
||||||
|
},
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare(fn, /short/);
|
||||||
|
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
expect(result.message).toEqual("Expected function to throw an exception matching /short/.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
199
spec/core/matchersUtilSpec.js
Normal file
199
spec/core/matchersUtilSpec.js
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
describe("matchersUtil", function() {
|
||||||
|
describe("equals", function() {
|
||||||
|
it("passes for literals that are threequal", function() {
|
||||||
|
expect(j$.matchersUtil.equals(null, null)).toBe(true);
|
||||||
|
expect(j$.matchersUtil.equals(void 0, void 0)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for things that are not equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals({a: "foo"}, 1)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes for Strings that are equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals("foo", "foo")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for Strings that are not equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals("foo", "bar")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes for Numbers that are equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals(123, 123)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for Numbers that are not equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals(123, 456)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes for Dates that are equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals(new Date("Jan 1, 1970"), new Date("Jan 1, 1970"))).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for Dates that are not equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals(new Date("Jan 1, 1970"), new Date("Feb 3, 1991"))).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes for Booleans that are equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals(true, true)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for Booleans that are not equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals(true, false)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes for RegExps that are equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals(/foo/, /foo/)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for RegExps that are not equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals(/foo/, /bar/)).toBe(false);
|
||||||
|
expect(j$.matchersUtil.equals(new RegExp("foo", "i"), new RegExp("foo"))).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes for Arrays that are equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals([1, 2], [1, 2])).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for Arrays that are not equivalent", function() {
|
||||||
|
expect(j$.matchersUtil.equals([1, 2], [1, 2, 3])).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes for Objects that are equivalent (simple case)", function() {
|
||||||
|
expect(j$.matchersUtil.equals({a: "foo"}, {a: "foo"})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for Objects that are not equivalent (simple case)", function() {
|
||||||
|
expect(j$.matchersUtil.equals({a: "foo"}, {a: "bar"})).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes for Objects that are equivalent (deep case)", function() {
|
||||||
|
expect(j$.matchersUtil.equals({a: "foo", b: { c: "bar"}}, {a: "foo", b: { c: "bar"}})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for Objects that are not equivalent (deep case)", function() {
|
||||||
|
expect(j$.matchersUtil.equals({a: "foo", b: { c: "baz"}}, {a: "foo", b: { c: "bar"}})).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes for Objects that are equivalent (with cycles)", function() {
|
||||||
|
var actual = { a: "foo" },
|
||||||
|
expected = { a: "foo" };
|
||||||
|
|
||||||
|
actual.b = actual;
|
||||||
|
expected.b = actual;
|
||||||
|
|
||||||
|
expect(j$.matchersUtil.equals(actual, expected)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for Objects that are not equivalent (with cycles)", function() {
|
||||||
|
var actual = { a: "foo" },
|
||||||
|
expected = { a: "bar" };
|
||||||
|
|
||||||
|
actual.b = actual;
|
||||||
|
expected.b = actual;
|
||||||
|
|
||||||
|
expect(j$.matchersUtil.equals(actual, expected)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when comparing an empty object to an empty array (issue #114)", function() {
|
||||||
|
var emptyObject = {},
|
||||||
|
emptyArray = [];
|
||||||
|
|
||||||
|
expect(j$.matchersUtil.equals(emptyObject, emptyArray)).toBe(false);
|
||||||
|
expect(j$.matchersUtil.equals(emptyArray, emptyObject)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes when Any is used", function() {
|
||||||
|
var number = 3,
|
||||||
|
anyNumber = new j$.Any(Number);
|
||||||
|
|
||||||
|
expect(j$.matchersUtil.equals(number, anyNumber)).toBe(true);
|
||||||
|
expect(j$.matchersUtil.equals(anyNumber, number)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when Any is compared to something unexepcted", function() {
|
||||||
|
var number = 3,
|
||||||
|
anyString = new j$.Any(String);
|
||||||
|
|
||||||
|
expect(j$.matchersUtil.equals(number, anyString)).toBe(false);
|
||||||
|
expect(j$.matchersUtil.equals(anyString, number)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes when ObjectContaining is used", function() {
|
||||||
|
var obj = {
|
||||||
|
foo: 3,
|
||||||
|
bar: 7
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(j$.matchersUtil.equals(obj, new j$.ObjectContaining({foo: 3}))).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes when a custom equality matcher returns true", function() {
|
||||||
|
var tester = function(a, b) { return true; };
|
||||||
|
|
||||||
|
expect(j$.matchersUtil.equals(1, 2, [tester])).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails for equivalents when a custom equality matcher returns false", function() {
|
||||||
|
var tester = function(a, b) { return false; };
|
||||||
|
|
||||||
|
expect(j$.matchersUtil.equals(1, 2, [tester])).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("contains", function() {
|
||||||
|
it("passes when expected is a substring of actual", function() {
|
||||||
|
expect(j$.matchersUtil.contains("ABC", "B")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when expected is a not substring of actual", function() {
|
||||||
|
expect(j$.matchersUtil.contains("ABC", "X")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes when expected is an element in an actual array", function() {
|
||||||
|
expect(j$.matchersUtil.contains(['foo', 'bar'], 'foo')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when expected is not an element in an actual array", function() {
|
||||||
|
expect(j$.matchersUtil.contains(['foo', 'bar'], 'baz')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes with mixed-element arrays", function() {
|
||||||
|
expect(j$.matchersUtil.contains(["foo", {some: "bar"}], "foo")).toBe(true);
|
||||||
|
expect(j$.matchersUtil.contains(["foo", {some: "bar"}], {some: "bar"})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses custom equality testers if passed in and actual is an Array", function() {
|
||||||
|
var customTester = function(a,b) {return true;};
|
||||||
|
|
||||||
|
expect(j$.matchersUtil.contains([1,2], 2, [customTester])).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("buildMessage", function() {
|
||||||
|
|
||||||
|
it("builds an English sentence for a failure case", function() {
|
||||||
|
var actual = "foo",
|
||||||
|
name = "toBar",
|
||||||
|
message = j$.matchersUtil.buildFailureMessage(name, false, actual);
|
||||||
|
|
||||||
|
expect(message).toEqual("Expected 'foo' to bar.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds an English sentence for a 'not' failure case", function() {
|
||||||
|
var actual = "foo",
|
||||||
|
name = "toBar",
|
||||||
|
isNot = true,
|
||||||
|
message = message = j$.matchersUtil.buildFailureMessage(name, isNot, actual);
|
||||||
|
|
||||||
|
expect(message).toEqual("Expected 'foo' not to bar.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds an English sentence for an arbitrary array of expected arguments", function(){
|
||||||
|
var actual = "foo",
|
||||||
|
name = "toBar",
|
||||||
|
message = j$.matchersUtil.buildFailureMessage(name, false, actual, "quux", "corge");
|
||||||
|
|
||||||
|
expect(message).toEqual("Expected 'foo' to bar 'quux', 'corge'.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
32
src/core/Any.js
Normal file
32
src/core/Any.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
getJasmineRequireObj().Any = function() {
|
||||||
|
|
||||||
|
function Any(expectedObject) {
|
||||||
|
this.expectedObject = expectedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
Any.prototype.jasmineMatches = function(other) {
|
||||||
|
if (this.expectedObject == String) {
|
||||||
|
return typeof other == 'string' || other instanceof String;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.expectedObject == Number) {
|
||||||
|
return typeof other == 'number' || other instanceof Number;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.expectedObject == Function) {
|
||||||
|
return typeof other == 'function' || other instanceof Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.expectedObject == Object) {
|
||||||
|
return typeof other == 'object';
|
||||||
|
}
|
||||||
|
|
||||||
|
return other instanceof this.expectedObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
Any.prototype.jasmineToString = function() {
|
||||||
|
return '<jasmine.any(' + this.expectedClass + ')>';
|
||||||
|
};
|
||||||
|
|
||||||
|
return Any;
|
||||||
|
};
|
||||||
170
src/core/Env.js
170
src/core/Env.js
@@ -29,18 +29,24 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
this.nextSuiteId_ = 0;
|
this.nextSuiteId_ = 0;
|
||||||
this.equalityTesters_ = [];
|
this.equalityTesters_ = [];
|
||||||
|
|
||||||
// wrap matchers
|
var customEqualityTesters = [];
|
||||||
this.matchersClass = function() {
|
this.addCustomEqualityTester = function(tester) {
|
||||||
j$.Matchers.apply(this, arguments);
|
customEqualityTesters.push(tester);
|
||||||
};
|
};
|
||||||
j$.util.inherit(this.matchersClass, j$.Matchers);
|
|
||||||
|
|
||||||
j$.Matchers.wrapInto_(j$.Matchers.prototype, this.matchersClass);
|
j$.Expectation.addCoreMatchers(j$.matchers);
|
||||||
|
|
||||||
var expectationFactory = function(actual, spec) {
|
var expectationFactory = function(actual, spec) {
|
||||||
var expect = new (self.matchersClass)(self, actual, spec);
|
return j$.Expectation.Factory({
|
||||||
expect.not = new (self.matchersClass)(self, actual, spec, true);
|
util: j$.matchersUtil,
|
||||||
return expect;
|
customEqualityTesters: customEqualityTesters,
|
||||||
|
actual: actual,
|
||||||
|
addExpectationResult: addExpectationResult
|
||||||
|
});
|
||||||
|
|
||||||
|
function addExpectationResult(passed, result) {
|
||||||
|
return spec.addExpectationResult(passed, result);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var specStarted = function(spec) {
|
var specStarted = function(spec) {
|
||||||
@@ -68,7 +74,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
var specConstructor = j$.Spec;
|
var specConstructor = j$.Spec; // TODO: inline this
|
||||||
|
|
||||||
var getSpecName = function(spec, currentSuite) {
|
var getSpecName = function(spec, currentSuite) {
|
||||||
return currentSuite.getFullName() + ' ' + spec.description + '.';
|
return currentSuite.getFullName() + ' ' + spec.description + '.';
|
||||||
@@ -147,6 +153,8 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
function specResultCallback(result) {
|
function specResultCallback(result) {
|
||||||
self.removeAllSpies();
|
self.removeAllSpies();
|
||||||
|
j$.Expectation.resetMatchers();
|
||||||
|
customEqualityTesters.length = 0;
|
||||||
self.clock.uninstall();
|
self.clock.uninstall();
|
||||||
self.currentSpec = null;
|
self.currentSpec = null;
|
||||||
self.reporter.specDone(result);
|
self.reporter.specDone(result);
|
||||||
@@ -191,15 +199,8 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: shim Spec addMatchers behavior into Env. Should be rewritten to remove globals, etc.
|
Env.prototype.addMatchers = function(matchersToAdd) {
|
||||||
Env.prototype.addMatchers = function(matchersPrototype) {
|
j$.Expectation.addMatchers(matchersToAdd);
|
||||||
var parent = this.matchersClass;
|
|
||||||
var newMatchersClass = function() {
|
|
||||||
parent.apply(this, arguments);
|
|
||||||
};
|
|
||||||
j$.util.inherit(newMatchersClass, parent);
|
|
||||||
j$.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
|
|
||||||
this.matchersClass = newMatchersClass;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Env.prototype.version = function() {
|
Env.prototype.version = function() {
|
||||||
@@ -333,138 +334,5 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
return this.topSuite;
|
return this.topSuite;
|
||||||
};
|
};
|
||||||
|
|
||||||
Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
|
|
||||||
if (a.source != b.source)
|
|
||||||
mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/");
|
|
||||||
|
|
||||||
if (a.ignoreCase != b.ignoreCase)
|
|
||||||
mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier");
|
|
||||||
|
|
||||||
if (a.global != b.global)
|
|
||||||
mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier");
|
|
||||||
|
|
||||||
if (a.multiline != b.multiline)
|
|
||||||
mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier");
|
|
||||||
|
|
||||||
if (a.sticky != b.sticky)
|
|
||||||
mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier");
|
|
||||||
|
|
||||||
return (mismatchValues.length === 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
|
|
||||||
if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.__Jasmine_been_here_before__ = b;
|
|
||||||
b.__Jasmine_been_here_before__ = a;
|
|
||||||
|
|
||||||
var hasKey = function(obj, keyName) {
|
|
||||||
return obj !== null && !j$.util.isUndefined(obj[keyName]);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var property in b) {
|
|
||||||
if (!hasKey(a, property) && hasKey(b, property)) {
|
|
||||||
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (property in a) {
|
|
||||||
if (!hasKey(b, property) && hasKey(a, property)) {
|
|
||||||
mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (property in b) {
|
|
||||||
if (property == '__Jasmine_been_here_before__') continue;
|
|
||||||
if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
|
|
||||||
mismatchValues.push("'" + property + "' was '" + (b[property] ? j$.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? j$.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j$.isArray_(a) && j$.isArray_(b) && a.length != b.length) {
|
|
||||||
mismatchValues.push("arrays were not the same length");
|
|
||||||
}
|
|
||||||
|
|
||||||
delete a.__Jasmine_been_here_before__;
|
|
||||||
delete b.__Jasmine_been_here_before__;
|
|
||||||
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
|
|
||||||
mismatchKeys = mismatchKeys || [];
|
|
||||||
mismatchValues = mismatchValues || [];
|
|
||||||
|
|
||||||
for (var i = 0; i < this.equalityTesters_.length; i++) {
|
|
||||||
var equalityTester = this.equalityTesters_[i];
|
|
||||||
var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
|
|
||||||
if (!j$.util.isUndefined(result)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a === b) return true;
|
|
||||||
|
|
||||||
if (j$.util.isUndefined(a) || a === null || j$.util.isUndefined(b) || b === null) {
|
|
||||||
return (j$.util.isUndefined(a) && j$.util.isUndefined(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j$.isDomNode(a) && j$.isDomNode(b)) {
|
|
||||||
return a === b;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a instanceof Date && b instanceof Date) {
|
|
||||||
return a.getTime() == b.getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.jasmineMatches) {
|
|
||||||
return a.jasmineMatches(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b.jasmineMatches) {
|
|
||||||
return b.jasmineMatches(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a instanceof j$.Matchers.ObjectContaining) {
|
|
||||||
return a.matches(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b instanceof j$.Matchers.ObjectContaining) {
|
|
||||||
return b.matches(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j$.isString_(a) && j$.isString_(b)) {
|
|
||||||
return (a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j$.isNumber_(a) && j$.isNumber_(b)) {
|
|
||||||
return (a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a instanceof RegExp && b instanceof RegExp) {
|
|
||||||
return this.compareRegExps_(a, b, mismatchKeys, mismatchValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof a === "object" && typeof b === "object") {
|
|
||||||
return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Straight check
|
|
||||||
return (a === b);
|
|
||||||
};
|
|
||||||
|
|
||||||
Env.prototype.contains_ = function(haystack, needle) {
|
|
||||||
if (j$.isArray_(haystack)) {
|
|
||||||
for (var i = 0; i < haystack.length; i++) {
|
|
||||||
if (this.equals_(haystack[i], needle)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return haystack.indexOf(needle) >= 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
Env.prototype.addEqualityTester = function(equalityTester) {
|
|
||||||
this.equalityTesters_.push(equalityTester);
|
|
||||||
};
|
|
||||||
|
|
||||||
return Env;
|
return Env;
|
||||||
};
|
};
|
||||||
|
|||||||
94
src/core/Expectation.js
Normal file
94
src/core/Expectation.js
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
getJasmineRequireObj().Expectation = function() {
|
||||||
|
|
||||||
|
var matchers = {};
|
||||||
|
|
||||||
|
function Expectation(options) {
|
||||||
|
this.util = options.util || { buildFailureMessage: function() {} };
|
||||||
|
this.customEqualityTesters = options.customEqualityTesters || [];
|
||||||
|
this.actual = options.actual;
|
||||||
|
this.addExpectationResult = options.addExpectationResult || function(){};
|
||||||
|
this.isNot = options.isNot;
|
||||||
|
|
||||||
|
for (var matcherName in matchers) {
|
||||||
|
this[matcherName] = matchers[matcherName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Expectation.prototype.wrapCompare = function(name, matcherFactory) {
|
||||||
|
return function() {
|
||||||
|
var args = Array.prototype.slice.call(arguments, 0),
|
||||||
|
expected = args.slice(0),
|
||||||
|
message = "";
|
||||||
|
|
||||||
|
args.unshift(this.actual);
|
||||||
|
|
||||||
|
var result = matcherFactory(this.util, this.customEqualityTesters).compare.apply(null, args);
|
||||||
|
|
||||||
|
if (this.isNot) {
|
||||||
|
result.pass = !result.pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.pass) {
|
||||||
|
if (!result.message) {
|
||||||
|
args.unshift(this.isNot);
|
||||||
|
args.unshift(name);
|
||||||
|
message = this.util.buildFailureMessage.apply(null, args);
|
||||||
|
} else {
|
||||||
|
message = result.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expected.length == 1) {
|
||||||
|
expected = expected[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: how many of these params are needed?
|
||||||
|
this.addExpectationResult(
|
||||||
|
result.pass,
|
||||||
|
{
|
||||||
|
matcherName: name,
|
||||||
|
passed: result.pass,
|
||||||
|
message: message,
|
||||||
|
actual: this.actual,
|
||||||
|
expected: expected // TODO: this may need to be arrayified/sliced
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Expectation.addCoreMatchers = function(matchers) {
|
||||||
|
var prototype = Expectation.prototype;
|
||||||
|
for (var matcherName in matchers) {
|
||||||
|
var matcher = matchers[matcherName];
|
||||||
|
prototype[matcherName] = prototype.wrapCompare(matcherName, matcher);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Expectation.addMatchers = function(matchersToAdd) {
|
||||||
|
for (var name in matchersToAdd) {
|
||||||
|
var matcher = matchersToAdd[name];
|
||||||
|
matchers[name] = Expectation.prototype.wrapCompare(name, matcher);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Expectation.resetMatchers = function() {
|
||||||
|
for (var name in matchers) {
|
||||||
|
delete matchers[name];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Expectation.Factory = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
var expect = new Expectation(options);
|
||||||
|
|
||||||
|
// TODO: this would be nice as its own Object - NegativeExpectation
|
||||||
|
// TODO: copy instead of mutate options
|
||||||
|
options.isNot = true;
|
||||||
|
expect.not = new Expectation(options);
|
||||||
|
|
||||||
|
return expect;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Expectation;
|
||||||
|
};
|
||||||
@@ -1,303 +0,0 @@
|
|||||||
getJasmineRequireObj().Matchers = function(j$) {
|
|
||||||
function Matchers(env, actual, spec, opt_isNot) {
|
|
||||||
//TODO: true dependency: equals, contains
|
|
||||||
this.env = env;
|
|
||||||
this.actual = actual;
|
|
||||||
this.spec = spec;
|
|
||||||
this.isNot = opt_isNot || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matchers.wrapInto_ = function(prototype, matchersClass) {
|
|
||||||
for (var methodName in prototype) {
|
|
||||||
var orig = prototype[methodName];
|
|
||||||
matchersClass.prototype[methodName] = Matchers.matcherFn_(methodName, orig);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.matcherFn_ = function(matcherName, matcherFunction) {
|
|
||||||
return function() {
|
|
||||||
var matcherArgs = j$.util.argsToArray(arguments);
|
|
||||||
var result = matcherFunction.apply(this, arguments);
|
|
||||||
|
|
||||||
if (this.isNot) {
|
|
||||||
result = !result;
|
|
||||||
}
|
|
||||||
|
|
||||||
var message;
|
|
||||||
if (!result) {
|
|
||||||
if (this.message) {
|
|
||||||
message = this.message.apply(this, arguments);
|
|
||||||
if (j$.isArray_(message)) {
|
|
||||||
message = message[this.isNot ? 1 : 0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
|
|
||||||
message = "Expected " + j$.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
|
|
||||||
if (matcherArgs.length > 0) {
|
|
||||||
for (var i = 0; i < matcherArgs.length; i++) {
|
|
||||||
if (i > 0) message += ",";
|
|
||||||
message += " " + j$.pp(matcherArgs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
message += ".";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.spec.addExpectationResult(result, {
|
|
||||||
matcherName: matcherName,
|
|
||||||
passed: result,
|
|
||||||
expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
|
|
||||||
actual: this.actual,
|
|
||||||
message: message
|
|
||||||
});
|
|
||||||
return void 0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toBe = function(expected) {
|
|
||||||
return this.actual === expected;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toNotBe = function(expected) {
|
|
||||||
return this.actual !== expected;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toEqual = function(expected) {
|
|
||||||
return this.env.equals_(this.actual, expected);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toNotEqual = function(expected) {
|
|
||||||
return !this.env.equals_(this.actual, expected);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toMatch = function(expected) {
|
|
||||||
return new RegExp(expected).test(this.actual);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toNotMatch = function(expected) {
|
|
||||||
return !(new RegExp(expected).test(this.actual));
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toBeDefined = function() {
|
|
||||||
return !j$.util.isUndefined(this.actual);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toBeUndefined = function() {
|
|
||||||
return j$.util.isUndefined(this.actual);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toBeNull = function() {
|
|
||||||
return (this.actual === null);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toBeNaN = function() {
|
|
||||||
this.message = function() {
|
|
||||||
return [ "Expected " + j$.pp(this.actual) + " to be NaN." ];
|
|
||||||
};
|
|
||||||
|
|
||||||
return (this.actual !== this.actual);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toBeTruthy = function() {
|
|
||||||
return !!this.actual;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toBeFalsy = function() {
|
|
||||||
return !this.actual;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toHaveBeenCalled = function() {
|
|
||||||
if (arguments.length > 0) {
|
|
||||||
throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!j$.isSpy(this.actual)) {
|
|
||||||
throw new Error('Expected a spy, but got ' + j$.pp(this.actual) + '.');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.message = function() {
|
|
||||||
return [
|
|
||||||
"Expected spy " + this.actual.identity + " to have been called.",
|
|
||||||
"Expected spy " + this.actual.identity + " not to have been called."
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.actual.wasCalled;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: kill this for 2.0
|
|
||||||
Matchers.prototype.wasCalled = Matchers.prototype.toHaveBeenCalled;
|
|
||||||
|
|
||||||
Matchers.prototype.wasNotCalled = function() {
|
|
||||||
if (arguments.length > 0) {
|
|
||||||
throw new Error('wasNotCalled does not take arguments');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!j$.isSpy(this.actual)) {
|
|
||||||
throw new Error('Expected a spy, but got ' + j$.pp(this.actual) + '.');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.message = function() {
|
|
||||||
return [
|
|
||||||
"Expected spy " + this.actual.identity + " to not have been called.",
|
|
||||||
"Expected spy " + this.actual.identity + " to have been called."
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
return !this.actual.wasCalled;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toHaveBeenCalledWith = function() {
|
|
||||||
var expectedArgs = j$.util.argsToArray(arguments);
|
|
||||||
if (!j$.isSpy(this.actual)) {
|
|
||||||
throw new Error('Expected a spy, but got ' + j$.pp(this.actual) + '.');
|
|
||||||
}
|
|
||||||
this.message = function() {
|
|
||||||
var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + j$.pp(expectedArgs) + " but it was.";
|
|
||||||
var positiveMessage = "";
|
|
||||||
if (this.actual.callCount === 0) {
|
|
||||||
positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + j$.pp(expectedArgs) + " but it was never called.";
|
|
||||||
} else {
|
|
||||||
positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + j$.pp(expectedArgs) + " but actual calls were " + j$.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '');
|
|
||||||
}
|
|
||||||
return [positiveMessage, invertedMessage];
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.env.contains_(this.actual.argsForCall, expectedArgs);
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: kill for 2.0
|
|
||||||
Matchers.prototype.wasCalledWith = Matchers.prototype.toHaveBeenCalledWith;
|
|
||||||
|
|
||||||
// TODO: kill for 2.0
|
|
||||||
Matchers.prototype.wasNotCalledWith = function() {
|
|
||||||
var expectedArgs = j$.util.argsToArray(arguments);
|
|
||||||
if (!j$.isSpy(this.actual)) {
|
|
||||||
throw new Error('Expected a spy, but got ' + j$.pp(this.actual) + '.');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.message = function() {
|
|
||||||
return [
|
|
||||||
"Expected spy not to have been called with " + j$.pp(expectedArgs) + " but it was",
|
|
||||||
"Expected spy to have been called with " + j$.pp(expectedArgs) + " but it was"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
return !this.env.contains_(this.actual.argsForCall, expectedArgs);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toContain = function(expected) {
|
|
||||||
return this.env.contains_(this.actual, expected);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toNotContain = function(expected) {
|
|
||||||
return !this.env.contains_(this.actual, expected);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toBeLessThan = function(expected) {
|
|
||||||
return this.actual < expected;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toBeGreaterThan = function(expected) {
|
|
||||||
return this.actual > expected;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toBeCloseTo = function(expected, precision) {
|
|
||||||
if (precision !== 0) {
|
|
||||||
precision = precision || 2;
|
|
||||||
}
|
|
||||||
return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.prototype.toThrow = function(expected) {
|
|
||||||
var result = false;
|
|
||||||
var exception, exceptionMessage;
|
|
||||||
if (typeof this.actual != 'function') {
|
|
||||||
throw new Error('Actual is not a function');
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
this.actual();
|
|
||||||
} catch (e) {
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exception) {
|
|
||||||
exceptionMessage = exception.message || exception;
|
|
||||||
result = (j$.util.isUndefined(expected) || this.env.equals_(exceptionMessage, expected.message || expected) || (j$.isA_("RegExp", expected) && expected.test(exceptionMessage)));
|
|
||||||
}
|
|
||||||
|
|
||||||
var not = this.isNot ? "not " : "";
|
|
||||||
var regexMatch = j$.isA_("RegExp", expected) ? " an exception matching" : "";
|
|
||||||
|
|
||||||
this.message = function() {
|
|
||||||
if (exception) {
|
|
||||||
return ["Expected function " + not + "to throw" + regexMatch, expected ? expected.message || expected : "an exception", ", but it threw", exceptionMessage].join(' ');
|
|
||||||
} else {
|
|
||||||
return "Expected function to throw an exception.";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.Any = function(expectedClass) {
|
|
||||||
this.expectedClass = expectedClass;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.Any.prototype.jasmineMatches = function(other) {
|
|
||||||
if (this.expectedClass == String) {
|
|
||||||
return typeof other == 'string' || other instanceof String;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.expectedClass == Number) {
|
|
||||||
return typeof other == 'number' || other instanceof Number;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.expectedClass == Function) {
|
|
||||||
return typeof other == 'function' || other instanceof Function;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.expectedClass == Object) {
|
|
||||||
return typeof other == 'object';
|
|
||||||
}
|
|
||||||
|
|
||||||
return other instanceof this.expectedClass;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.Any.prototype.jasmineToString = function() {
|
|
||||||
return '<jasmine.any(' + this.expectedClass + ')>';
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.ObjectContaining = function(sample) {
|
|
||||||
this.sample = sample;
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
|
|
||||||
mismatchKeys = mismatchKeys || [];
|
|
||||||
mismatchValues = mismatchValues || [];
|
|
||||||
|
|
||||||
var env = j$.getEnv();
|
|
||||||
|
|
||||||
var hasKey = function(obj, keyName) {
|
|
||||||
return obj !== null && !j$.util.isUndefined(obj[keyName]);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var property in this.sample) {
|
|
||||||
if (!hasKey(other, property) && hasKey(this.sample, property)) {
|
|
||||||
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
|
|
||||||
}
|
|
||||||
else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
|
|
||||||
mismatchValues.push("'" + property + "' was '" + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
Matchers.ObjectContaining.prototype.jasmineToString = function() {
|
|
||||||
return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>";
|
|
||||||
};
|
|
||||||
|
|
||||||
return Matchers;
|
|
||||||
|
|
||||||
};
|
|
||||||
32
src/core/ObjectContaining.js
Normal file
32
src/core/ObjectContaining.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
getJasmineRequireObj().ObjectContaining = function(j$) {
|
||||||
|
|
||||||
|
function ObjectContaining(sample) {
|
||||||
|
this.sample = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
|
||||||
|
mismatchKeys = mismatchKeys || [];
|
||||||
|
mismatchValues = mismatchValues || [];
|
||||||
|
|
||||||
|
var hasKey = function(obj, keyName) {
|
||||||
|
return obj !== null && !j$.util.isUndefined(obj[keyName]);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var property in this.sample) {
|
||||||
|
if (!hasKey(other, property) && hasKey(this.sample, property)) {
|
||||||
|
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
|
||||||
|
}
|
||||||
|
else if (!j$.matchersUtil.equals(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
|
||||||
|
mismatchValues.push("'" + property + "' was '" + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
ObjectContaining.prototype.jasmineToString = function() {
|
||||||
|
return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>";
|
||||||
|
};
|
||||||
|
|
||||||
|
return ObjectContaining;
|
||||||
|
};
|
||||||
268
src/core/matchers.js
Normal file
268
src/core/matchers.js
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
getJasmineRequireObj().matchers = function() {
|
||||||
|
matchers = {};
|
||||||
|
|
||||||
|
matchers.toBe = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual, expected) {
|
||||||
|
return {
|
||||||
|
pass: actual === expected
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toBeCloseTo = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual, expected, precision) {
|
||||||
|
if (precision !== 0) {
|
||||||
|
precision = precision || 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toBeDefined = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual) {
|
||||||
|
return {
|
||||||
|
pass: (void 0 !== actual)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toBeFalsy = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual) {
|
||||||
|
return {
|
||||||
|
pass: !!!actual
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toBeGreaterThan = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual, expected) {
|
||||||
|
return {
|
||||||
|
pass: actual > expected
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toBeLessThan = function() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
compare: function(actual, expected) {
|
||||||
|
return {
|
||||||
|
pass: actual < expected
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toBeNaN = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual) {
|
||||||
|
var result = {
|
||||||
|
pass: (actual !== actual)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (result.pass) {
|
||||||
|
result.message = "Expected actual not to be NaN.";
|
||||||
|
} else {
|
||||||
|
result.message = "Expected " + j$.pp(actual) + " to be NaN.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toBeNull = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual) {
|
||||||
|
return {
|
||||||
|
pass: actual === null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toBeTruthy = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual) {
|
||||||
|
return {
|
||||||
|
pass: !!actual
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toBeUndefined = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual) {
|
||||||
|
return {
|
||||||
|
pass: void 0 === actual
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toEqual = function(util, customEqualityTesters) {
|
||||||
|
customEqualityTesters = customEqualityTesters || [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
compare: function(actual, expected) {
|
||||||
|
var result = {
|
||||||
|
pass: false
|
||||||
|
};
|
||||||
|
|
||||||
|
result.pass = util.equals(actual, expected, customEqualityTesters);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toHaveBeenCalled = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual) {
|
||||||
|
var result = {};
|
||||||
|
|
||||||
|
if (!j$.isSpy(actual)) {
|
||||||
|
throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments.length > 1) {
|
||||||
|
throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
|
||||||
|
}
|
||||||
|
|
||||||
|
result.pass = actual.wasCalled;
|
||||||
|
|
||||||
|
result.message = result.pass ?
|
||||||
|
"Expected spy " + actual.identity + " not to have been called." :
|
||||||
|
"Expected spy " + actual.identity + " to have been called.";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toHaveBeenCalledWith = function(util) {
|
||||||
|
return {
|
||||||
|
compare: function() {
|
||||||
|
var args = Array.prototype.slice.call(arguments, 0),
|
||||||
|
actual = args[0],
|
||||||
|
expectedArgs = args.slice(1);
|
||||||
|
|
||||||
|
if (!j$.isSpy(actual)) {
|
||||||
|
throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
pass: util.contains(actual.argsForCall, expectedArgs)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
message: function(actual) {
|
||||||
|
return {
|
||||||
|
affirmative: "Expected spy " + actual.identity + " to have been called.",
|
||||||
|
negative: "Expected spy " + actual.identity + " not to have been called."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toMatch = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual, expected) {
|
||||||
|
var regexp = new RegExp(expected);
|
||||||
|
|
||||||
|
return {
|
||||||
|
pass: regexp.test(actual)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toThrow = function() {
|
||||||
|
return {
|
||||||
|
compare: function(actual, expected) {
|
||||||
|
var result = { pass: false },
|
||||||
|
exception;
|
||||||
|
|
||||||
|
if (typeof actual != "function") {
|
||||||
|
throw new Error("Actual is not a Function");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectedCannotBeTreatedAsException()) {
|
||||||
|
throw new Error("Expected cannot be treated as an exception.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
actual();
|
||||||
|
} catch (e) {
|
||||||
|
exception = new Error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exception) {
|
||||||
|
result.message = "Expected function to throw an exception.";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (void 0 == expected) {
|
||||||
|
result.pass = true;
|
||||||
|
result.message = "Expected function not to throw an exception.";
|
||||||
|
} else if (exception.message == expected) {
|
||||||
|
result.pass = true;
|
||||||
|
result.message = "Expected function not to throw an exception \"" + expected + "\".";
|
||||||
|
} else if (exception.message == expected.message) {
|
||||||
|
result.pass = true;
|
||||||
|
result.message = "Expected function not to throw an exception \"" + expected.message + "\".";
|
||||||
|
} else if (expected instanceof RegExp) {
|
||||||
|
if (expected.test(exception.message)) {
|
||||||
|
result.pass = true;
|
||||||
|
result.message = "Expected function not to throw an exception matching " + expected + ".";
|
||||||
|
} else {
|
||||||
|
result.pass = false;
|
||||||
|
result.message = "Expected function to throw an exception matching " + expected + ".";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.pass = false;
|
||||||
|
result.message = "Expected function to throw an exception \"" + (expected.message || expected) + "\".";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
function expectedCannotBeTreatedAsException() {
|
||||||
|
return !(
|
||||||
|
(void 0 == expected) ||
|
||||||
|
(expected instanceof Error) ||
|
||||||
|
(typeof expected == "string") ||
|
||||||
|
(expected instanceof RegExp)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matchers.toContain = function(util, customEqualityTesters) {
|
||||||
|
customEqualityTesters = customEqualityTesters || [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
compare: function(actual, expected) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
pass: util.contains(actual, expected, customEqualityTesters)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return matchers;
|
||||||
|
};
|
||||||
177
src/core/matchersUtil.js
Normal file
177
src/core/matchersUtil.js
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
getJasmineRequireObj().matchersUtil = function(j$) {
|
||||||
|
// TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
|
||||||
|
|
||||||
|
return {
|
||||||
|
equals: function(a, b, customTesters) {
|
||||||
|
customTesters = customTesters || [];
|
||||||
|
|
||||||
|
return eq(a, b, [], [], customTesters);
|
||||||
|
},
|
||||||
|
|
||||||
|
contains: function(haystack, needle, customTesters) {
|
||||||
|
customTesters = customTesters || [];
|
||||||
|
|
||||||
|
if (Object.prototype.toString.apply(haystack) === "[object Array]") {
|
||||||
|
for (var i = 0; i < haystack.length; i++) {
|
||||||
|
if (eq(haystack[i], needle, [], [], customTesters)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return haystack.indexOf(needle) >= 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
buildFailureMessage: function() {
|
||||||
|
var args = Array.prototype.slice.call(arguments, 0),
|
||||||
|
matcherName = args[0],
|
||||||
|
isNot = args[1],
|
||||||
|
actual = args[2],
|
||||||
|
expected = args.slice(3),
|
||||||
|
englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
|
||||||
|
|
||||||
|
var message = "Expected " +
|
||||||
|
j$.pp(actual) +
|
||||||
|
(isNot ? " not " : " ") +
|
||||||
|
englishyPredicate;
|
||||||
|
|
||||||
|
if (expected.length > 0) {
|
||||||
|
for (var i = 0; i < expected.length; i++) {
|
||||||
|
if (i > 0) message += ",";
|
||||||
|
message += " " + j$.pp(expected[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return message + ".";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Equality function lovingly adapted from isEqual in
|
||||||
|
// [Underscore](http://underscorejs.org)
|
||||||
|
function eq(a, b, aStack, bStack, customTesters) {
|
||||||
|
var result = true;
|
||||||
|
|
||||||
|
for (var i = 0; i < customTesters.length; i++) {
|
||||||
|
result = customTesters[i](a, b);
|
||||||
|
if (result) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a instanceof j$.Any) {
|
||||||
|
result = a.jasmineMatches(b);
|
||||||
|
if (result) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b instanceof j$.Any) {
|
||||||
|
result = b.jasmineMatches(a);
|
||||||
|
if (result) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b instanceof j$.ObjectContaining) {
|
||||||
|
result = b.jasmineMatches(a);
|
||||||
|
if (result) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
||||||
|
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
||||||
|
if (a === b) return a !== 0 || 1 / a == 1 / b;
|
||||||
|
// A strict comparison is necessary because `null == undefined`.
|
||||||
|
if (a === null || b === null) return a === b;
|
||||||
|
var className = Object.prototype.toString.call(a);
|
||||||
|
if (className != Object.prototype.toString.call(b)) return false;
|
||||||
|
switch (className) {
|
||||||
|
// Strings, numbers, dates, and booleans are compared by value.
|
||||||
|
case '[object String]':
|
||||||
|
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
||||||
|
// equivalent to `new String("5")`.
|
||||||
|
return a == String(b);
|
||||||
|
case '[object Number]':
|
||||||
|
// `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
|
||||||
|
// other numeric values.
|
||||||
|
return a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
|
||||||
|
case '[object Date]':
|
||||||
|
case '[object Boolean]':
|
||||||
|
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
||||||
|
// millisecond representations. Note that invalid dates with millisecond representations
|
||||||
|
// of `NaN` are not equivalent.
|
||||||
|
return +a == +b;
|
||||||
|
// RegExps are compared by their source patterns and flags.
|
||||||
|
case '[object RegExp]':
|
||||||
|
return a.source == b.source &&
|
||||||
|
a.global == b.global &&
|
||||||
|
a.multiline == b.multiline &&
|
||||||
|
a.ignoreCase == b.ignoreCase;
|
||||||
|
}
|
||||||
|
if (typeof a != 'object' || typeof b != 'object') return false;
|
||||||
|
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
||||||
|
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
||||||
|
var length = aStack.length;
|
||||||
|
while (length--) {
|
||||||
|
// Linear search. Performance is inversely proportional to the number of
|
||||||
|
// unique nested structures.
|
||||||
|
if (aStack[length] == a) return bStack[length] == b;
|
||||||
|
}
|
||||||
|
// Add the first object to the stack of traversed objects.
|
||||||
|
aStack.push(a);
|
||||||
|
bStack.push(b);
|
||||||
|
var size = 0;
|
||||||
|
// Recursively compare objects and arrays.
|
||||||
|
if (className == '[object Array]') {
|
||||||
|
// Compare array lengths to determine if a deep comparison is necessary.
|
||||||
|
size = a.length;
|
||||||
|
result = size == b.length;
|
||||||
|
if (result) {
|
||||||
|
// Deep compare the contents, ignoring non-numeric properties.
|
||||||
|
while (size--) {
|
||||||
|
if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Objects with different constructors are not equivalent, but `Object`s
|
||||||
|
// from different frames are.
|
||||||
|
var aCtor = a.constructor, bCtor = b.constructor;
|
||||||
|
if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) &&
|
||||||
|
isFunction(bCtor) && (bCtor instanceof bCtor))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Deep compare objects.
|
||||||
|
for (var key in a) {
|
||||||
|
if (has(a, key)) {
|
||||||
|
// Count the expected number of properties.
|
||||||
|
size++;
|
||||||
|
// Deep compare each member.
|
||||||
|
if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ensure that both objects contain the same number of properties.
|
||||||
|
if (result) {
|
||||||
|
for (key in b) {
|
||||||
|
if (has(b, key) && !(size--)) break;
|
||||||
|
}
|
||||||
|
result = !size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove the first object from the stack of traversed objects.
|
||||||
|
aStack.pop();
|
||||||
|
bStack.pop();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
function has(obj, key) {
|
||||||
|
return obj.hasOwnProperty(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFunction(obj) {
|
||||||
|
return typeof obj === 'function';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -12,13 +12,17 @@ getJasmineRequireObj().core = function(jRequire) {
|
|||||||
|
|
||||||
jRequire.base(j$);
|
jRequire.base(j$);
|
||||||
j$.util = jRequire.util();
|
j$.util = jRequire.util();
|
||||||
|
j$.Any = jRequire.Any();
|
||||||
j$.Clock = jRequire.Clock();
|
j$.Clock = jRequire.Clock();
|
||||||
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
|
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
|
||||||
j$.Env = jRequire.Env(j$);
|
j$.Env = jRequire.Env(j$);
|
||||||
j$.ExceptionFormatter = jRequire.ExceptionFormatter();
|
j$.ExceptionFormatter = jRequire.ExceptionFormatter();
|
||||||
|
j$.Expectation = jRequire.Expectation();
|
||||||
j$.buildExpectationResult = jRequire.buildExpectationResult();
|
j$.buildExpectationResult = jRequire.buildExpectationResult();
|
||||||
j$.JsApiReporter = jRequire.JsApiReporter();
|
j$.JsApiReporter = jRequire.JsApiReporter();
|
||||||
j$.Matchers = jRequire.Matchers(j$);
|
j$.matchers = jRequire.matchers(j$);
|
||||||
|
j$.matchersUtil = jRequire.matchersUtil(j$);
|
||||||
|
j$.ObjectContaining = jRequire.ObjectContaining(j$);
|
||||||
j$.StringPrettyPrinter = jRequire.StringPrettyPrinter(j$);
|
j$.StringPrettyPrinter = jRequire.StringPrettyPrinter(j$);
|
||||||
j$.QueueRunner = jRequire.QueueRunner();
|
j$.QueueRunner = jRequire.QueueRunner();
|
||||||
j$.ReportDispatcher = jRequire.ReportDispatcher();
|
j$.ReportDispatcher = jRequire.ReportDispatcher();
|
||||||
|
|||||||
Reference in New Issue
Block a user