Added support for custom object formatters
Custom object formatters allow users to customize how an object is
stringified in matcher failure messages. This can already be done by
adding a `jasmineToString` method to the objects in question. But
it's not always desirable or possible to do that, particularly when
objects of a given "type" do not inherit from a specific prototype.
For instance, suppose a web service returns a list of foos that are
deserialized from JSON, e.g.:
{ fooId: 42, /* more properties */ }
The only way to define `jasmineToString` on those is by writing code to
add it to each instance at runtime. But a custom object formatter can
recognize that the object it's looking at is a foo and format it
accordingly:
jasmine.addCustomObjectFormatter(function(obj) {
if (typeof obj.fooId !== 'number') {
return undefined;
}
return '[Foo with ID ' + obj.fooId + ']';
});
Unlike `jasmineToString`, custom object formatters are scoped to a
particular spec or suite and don't require any changes to the code
under test.
This commit is contained in:
committed by
Steve Gravrock
parent
1f23f1e4d2
commit
25816a6e77
@@ -1217,6 +1217,18 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.addCustomObjectFormatter = function(formatter) {
|
||||||
|
if (!currentRunnable()) {
|
||||||
|
throw new Error(
|
||||||
|
'Custom object formatters must be added in a before function or a spec'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
runnableResources[currentRunnable().id].customObjectFormatters.push(
|
||||||
|
formatter
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
j$.Expectation.addCoreMatchers(j$.matchers);
|
j$.Expectation.addCoreMatchers(j$.matchers);
|
||||||
j$.Expectation.addAsyncCoreMatchers(j$.asyncMatchers);
|
j$.Expectation.addAsyncCoreMatchers(j$.asyncMatchers);
|
||||||
|
|
||||||
@@ -1231,7 +1243,9 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var makePrettyPrinter = function() {
|
var makePrettyPrinter = function() {
|
||||||
return j$.makePrettyPrinter();
|
var customObjectFormatters =
|
||||||
|
runnableResources[currentRunnable().id].customObjectFormatters;
|
||||||
|
return j$.makePrettyPrinter(customObjectFormatters);
|
||||||
};
|
};
|
||||||
|
|
||||||
var makeMatchersUtil = function() {
|
var makeMatchersUtil = function() {
|
||||||
@@ -1281,7 +1295,8 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
customMatchers: {},
|
customMatchers: {},
|
||||||
customAsyncMatchers: {},
|
customAsyncMatchers: {},
|
||||||
customSpyStrategies: {},
|
customSpyStrategies: {},
|
||||||
defaultStrategyFn: undefined
|
defaultStrategyFn: undefined,
|
||||||
|
customObjectFormatters: []
|
||||||
};
|
};
|
||||||
|
|
||||||
if (runnableResources[parentRunnableId]) {
|
if (runnableResources[parentRunnableId]) {
|
||||||
@@ -2318,8 +2333,8 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
ArrayContaining.prototype.jasmineToString = function () {
|
ArrayContaining.prototype.jasmineToString = function (pp) {
|
||||||
return '<jasmine.arrayContaining(' + j$.pp(this.sample) +')>';
|
return '<jasmine.arrayContaining(' + pp(this.sample) +')>';
|
||||||
};
|
};
|
||||||
|
|
||||||
return ArrayContaining;
|
return ArrayContaining;
|
||||||
@@ -2350,8 +2365,8 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
ArrayWithExactContents.prototype.jasmineToString = function() {
|
ArrayWithExactContents.prototype.jasmineToString = function(pp) {
|
||||||
return '<jasmine.arrayWithExactContents ' + j$.pp(this.sample) + '>';
|
return '<jasmine.arrayWithExactContents(' + pp(this.sample) + ')>';
|
||||||
};
|
};
|
||||||
|
|
||||||
return ArrayWithExactContents;
|
return ArrayWithExactContents;
|
||||||
@@ -2433,8 +2448,8 @@ getJasmineRequireObj().MapContaining = function(j$) {
|
|||||||
return hasAllMatches;
|
return hasAllMatches;
|
||||||
};
|
};
|
||||||
|
|
||||||
MapContaining.prototype.jasmineToString = function() {
|
MapContaining.prototype.jasmineToString = function(pp) {
|
||||||
return '<jasmine.mapContaining(' + j$.pp(this.sample) + ')>';
|
return '<jasmine.mapContaining(' + pp(this.sample) + ')>';
|
||||||
};
|
};
|
||||||
|
|
||||||
return MapContaining;
|
return MapContaining;
|
||||||
@@ -2510,8 +2525,8 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
ObjectContaining.prototype.jasmineToString = function() {
|
ObjectContaining.prototype.jasmineToString = function(pp) {
|
||||||
return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
|
return '<jasmine.objectContaining(' + pp(this.sample) + ')>';
|
||||||
};
|
};
|
||||||
|
|
||||||
return ObjectContaining;
|
return ObjectContaining;
|
||||||
@@ -2550,8 +2565,8 @@ getJasmineRequireObj().SetContaining = function(j$) {
|
|||||||
return hasAllMatches;
|
return hasAllMatches;
|
||||||
};
|
};
|
||||||
|
|
||||||
SetContaining.prototype.jasmineToString = function() {
|
SetContaining.prototype.jasmineToString = function(pp) {
|
||||||
return '<jasmine.setContaining(' + j$.pp(this.sample) + ')>';
|
return '<jasmine.setContaining(' + pp(this.sample) + ')>';
|
||||||
};
|
};
|
||||||
|
|
||||||
return SetContaining;
|
return SetContaining;
|
||||||
@@ -4173,14 +4188,15 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().DiffBuilder = function(j$) {
|
getJasmineRequireObj().DiffBuilder = function(j$) {
|
||||||
return function DiffBuilder() {
|
return function DiffBuilder(config) {
|
||||||
var path = new j$.ObjectPath(),
|
var path = new j$.ObjectPath(),
|
||||||
mismatches = [];
|
mismatches = [],
|
||||||
|
prettyPrinter = (config || {}).prettyPrinter || j$.makePrettyPrinter();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
record: function (actual, expected, formatter) {
|
record: function (actual, expected, formatter) {
|
||||||
formatter = formatter || defaultFormatter;
|
formatter = formatter || defaultFormatter;
|
||||||
mismatches.push(formatter(actual, expected, path));
|
mismatches.push(formatter(actual, expected, path, prettyPrinter));
|
||||||
},
|
},
|
||||||
|
|
||||||
getMessage: function () {
|
getMessage: function () {
|
||||||
@@ -4195,12 +4211,12 @@ getJasmineRequireObj().DiffBuilder = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function defaultFormatter (actual, expected, path) {
|
function defaultFormatter (actual, expected, path, prettyPrinter) {
|
||||||
return 'Expected ' +
|
return 'Expected ' +
|
||||||
path + (path.depth() ? ' = ' : '') +
|
path + (path.depth() ? ' = ' : '') +
|
||||||
j$.pp(actual) +
|
prettyPrinter(actual) +
|
||||||
' to equal ' +
|
' to equal ' +
|
||||||
j$.pp(expected) +
|
prettyPrinter(expected) +
|
||||||
'.';
|
'.';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -4253,7 +4269,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
message += ',';
|
message += ',';
|
||||||
}
|
}
|
||||||
message += ' ' + j$.pp(expected[i]);
|
message += ' ' + self.pp(expected[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5289,7 +5305,7 @@ getJasmineRequireObj().toEqual = function(j$) {
|
|||||||
var result = {
|
var result = {
|
||||||
pass: false
|
pass: false
|
||||||
},
|
},
|
||||||
diffBuilder = j$.DiffBuilder();
|
diffBuilder = j$.DiffBuilder({prettyPrinter: util.pp});
|
||||||
|
|
||||||
result.pass = util.equals(actual, expected, diffBuilder);
|
result.pass = util.equals(actual, expected, diffBuilder);
|
||||||
|
|
||||||
@@ -5990,11 +6006,13 @@ getJasmineRequireObj().MockDate = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
||||||
function SinglePrettyPrintRun() {
|
function SinglePrettyPrintRun(customObjectFormatters, pp) {
|
||||||
|
this.customObjectFormatters_ = customObjectFormatters;
|
||||||
this.ppNestLevel_ = 0;
|
this.ppNestLevel_ = 0;
|
||||||
this.seen = [];
|
this.seen = [];
|
||||||
this.length = 0;
|
this.length = 0;
|
||||||
this.stringParts = [];
|
this.stringParts = [];
|
||||||
|
this.pp_ = pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasCustomToString(value) {
|
function hasCustomToString(value) {
|
||||||
@@ -6015,7 +6033,11 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
|||||||
SinglePrettyPrintRun.prototype.format = function(value) {
|
SinglePrettyPrintRun.prototype.format = function(value) {
|
||||||
this.ppNestLevel_++;
|
this.ppNestLevel_++;
|
||||||
try {
|
try {
|
||||||
if (j$.util.isUndefined(value)) {
|
var customFormatResult = this.applyCustomFormatters_(value);
|
||||||
|
|
||||||
|
if (customFormatResult) {
|
||||||
|
this.emitScalar(customFormatResult);
|
||||||
|
} else if (j$.util.isUndefined(value)) {
|
||||||
this.emitScalar('undefined');
|
this.emitScalar('undefined');
|
||||||
} else if (value === null) {
|
} else if (value === null) {
|
||||||
this.emitScalar('null');
|
this.emitScalar('null');
|
||||||
@@ -6024,7 +6046,7 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
|||||||
} else if (value === j$.getGlobal()) {
|
} else if (value === j$.getGlobal()) {
|
||||||
this.emitScalar('<global>');
|
this.emitScalar('<global>');
|
||||||
} else if (value.jasmineToString) {
|
} else if (value.jasmineToString) {
|
||||||
this.emitScalar(value.jasmineToString());
|
this.emitScalar(value.jasmineToString(this.pp_));
|
||||||
} else if (typeof value === 'string') {
|
} else if (typeof value === 'string') {
|
||||||
this.emitString(value);
|
this.emitString(value);
|
||||||
} else if (j$.isSpy(value)) {
|
} else if (j$.isSpy(value)) {
|
||||||
@@ -6086,6 +6108,18 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) {
|
||||||
|
var i, result;
|
||||||
|
|
||||||
|
for (i = 0; i < this.customObjectFormatters_.length; i++) {
|
||||||
|
result = this.customObjectFormatters_[i](value);
|
||||||
|
|
||||||
|
if (result !== undefined) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) {
|
SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) {
|
||||||
var objKeys = keys(obj, j$.isArray_(obj));
|
var objKeys = keys(obj, j$.isArray_(obj));
|
||||||
var isGetter = function isGetter(prop) {};
|
var isGetter = function isGetter(prop) {};
|
||||||
@@ -6356,12 +6390,17 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
|||||||
return extraKeys;
|
return extraKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
return function() {
|
return function(customObjectFormatters) {
|
||||||
return function(value) {
|
var pp = function(value) {
|
||||||
var prettyPrinter = new SinglePrettyPrintRun();
|
var prettyPrinter = new SinglePrettyPrintRun(
|
||||||
|
customObjectFormatters || [],
|
||||||
|
pp
|
||||||
|
);
|
||||||
prettyPrinter.format(value);
|
prettyPrinter.format(value);
|
||||||
return prettyPrinter.stringParts.join('');
|
return prettyPrinter.stringParts.join('');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return pp;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -6972,6 +7011,20 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
|||||||
return env.addAsyncMatchers(matchers);
|
return env.addAsyncMatchers(matchers);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a custom object formatter for the current scope of specs.
|
||||||
|
*
|
||||||
|
* _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
|
||||||
|
* @name jasmine.addCustomObjectFormatter
|
||||||
|
* @since 3.6.0
|
||||||
|
* @function
|
||||||
|
* @param {Function} formatter - A function which takes a value to format and returns a string if it knows how to format it, and `undefined` otherwise.
|
||||||
|
* @see custom_object_formatter
|
||||||
|
*/
|
||||||
|
jasmine.addCustomObjectFormatter = function(formatter) {
|
||||||
|
return env.addCustomObjectFormatter(formatter);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the currently booted mock {Clock} for this Jasmine environment.
|
* Get the currently booted mock {Clock} for this Jasmine environment.
|
||||||
* @name jasmine.clock
|
* @name jasmine.clock
|
||||||
|
|||||||
@@ -305,8 +305,9 @@ describe('Env', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates an expectationFactory that uses the current custom equality testers', function(done) {
|
it('creates an expectationFactory that uses the current custom equality testers and object formatters', function(done) {
|
||||||
function customEqualityTester() {}
|
function customEqualityTester() {}
|
||||||
|
function customObjectFormatter() {}
|
||||||
function prettyPrinter() {}
|
function prettyPrinter() {}
|
||||||
var RealSpec = jasmineUnderTest.Spec,
|
var RealSpec = jasmineUnderTest.Spec,
|
||||||
specInstance,
|
specInstance,
|
||||||
@@ -321,11 +322,15 @@ describe('Env', function() {
|
|||||||
|
|
||||||
env.it('spec', function() {
|
env.it('spec', function() {
|
||||||
env.addCustomEqualityTester(customEqualityTester);
|
env.addCustomEqualityTester(customEqualityTester);
|
||||||
|
env.addCustomObjectFormatter(customObjectFormatter);
|
||||||
expectationFactory('actual', specInstance);
|
expectationFactory('actual', specInstance);
|
||||||
});
|
});
|
||||||
|
|
||||||
env.addReporter({
|
env.addReporter({
|
||||||
jasmineDone: function() {
|
jasmineDone: function() {
|
||||||
|
expect(jasmineUnderTest.makePrettyPrinter).toHaveBeenCalledWith([
|
||||||
|
customObjectFormatter
|
||||||
|
]);
|
||||||
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({
|
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({
|
||||||
customTesters: [customEqualityTester],
|
customTesters: [customEqualityTester],
|
||||||
pp: prettyPrinter
|
pp: prettyPrinter
|
||||||
@@ -337,8 +342,9 @@ describe('Env', function() {
|
|||||||
env.execute();
|
env.execute();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates an asyncExpectationFactory that uses the current custom equality testers', function(done) {
|
it('creates an asyncExpectationFactory that uses the current custom equality testers and object formatters', function(done) {
|
||||||
function customEqualityTester() {}
|
function customEqualityTester() {}
|
||||||
|
function customObjectFormatter() {}
|
||||||
function prettyPrinter() {}
|
function prettyPrinter() {}
|
||||||
var RealSpec = jasmineUnderTest.Spec,
|
var RealSpec = jasmineUnderTest.Spec,
|
||||||
specInstance,
|
specInstance,
|
||||||
@@ -353,11 +359,15 @@ describe('Env', function() {
|
|||||||
|
|
||||||
env.it('spec', function() {
|
env.it('spec', function() {
|
||||||
env.addCustomEqualityTester(customEqualityTester);
|
env.addCustomEqualityTester(customEqualityTester);
|
||||||
|
env.addCustomObjectFormatter(customObjectFormatter);
|
||||||
asyncExpectationFactory('actual', specInstance);
|
asyncExpectationFactory('actual', specInstance);
|
||||||
});
|
});
|
||||||
|
|
||||||
env.addReporter({
|
env.addReporter({
|
||||||
jasmineDone: function() {
|
jasmineDone: function() {
|
||||||
|
expect(jasmineUnderTest.makePrettyPrinter).toHaveBeenCalledWith([
|
||||||
|
customObjectFormatter
|
||||||
|
]);
|
||||||
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({
|
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({
|
||||||
customTesters: [customEqualityTester],
|
customTesters: [customEqualityTester],
|
||||||
pp: prettyPrinter
|
pp: prettyPrinter
|
||||||
|
|||||||
@@ -388,6 +388,16 @@ describe('PrettyPrinter', function() {
|
|||||||
expect(pp(obj)).toEqual('strung');
|
expect(pp(obj)).toEqual('strung');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should pass itself to jasmineToString', function() {
|
||||||
|
var pp = jasmineUnderTest.makePrettyPrinter([]);
|
||||||
|
var obj = {
|
||||||
|
jasmineToString: jasmine.createSpy('jasmineToString').and.returnValue('')
|
||||||
|
};
|
||||||
|
|
||||||
|
pp(obj);
|
||||||
|
expect(obj.jasmineToString).toHaveBeenCalledWith(pp);
|
||||||
|
});
|
||||||
|
|
||||||
it('should stringify objects that implement custom toString', function() {
|
it('should stringify objects that implement custom toString', function() {
|
||||||
var pp = jasmineUnderTest.makePrettyPrinter();
|
var pp = jasmineUnderTest.makePrettyPrinter();
|
||||||
var obj = {
|
var obj = {
|
||||||
@@ -478,4 +488,36 @@ describe('PrettyPrinter', function() {
|
|||||||
'Object({ foo: [object Number], bar: [object Object], baz: 3, qux: Error: bar, baddy: has-invalid-toString-method })'
|
'Object({ foo: [object Number], bar: [object Object], baz: 3, qux: Error: bar, baddy: has-invalid-toString-method })'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Custom object formatters', function() {
|
||||||
|
it('should use the first custom object formatter that does not return undefined', function() {
|
||||||
|
var customObjectFormatters = [
|
||||||
|
function(obj) {
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
function(obj) {
|
||||||
|
return '2nd: ' + obj.foo;
|
||||||
|
},
|
||||||
|
function(obj) {
|
||||||
|
return '3rd: ' + obj.foo;
|
||||||
|
}
|
||||||
|
],
|
||||||
|
pp = jasmineUnderTest.makePrettyPrinter(customObjectFormatters),
|
||||||
|
obj = { foo: 'bar' };
|
||||||
|
|
||||||
|
expect(pp(obj, customObjectFormatters)).toEqual('2nd: bar');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fall back to built in logic if all custom object formatters return undefined', function() {
|
||||||
|
var customObjectFormatters = [
|
||||||
|
function(obj) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
],
|
||||||
|
pp = jasmineUnderTest.makePrettyPrinter(customObjectFormatters),
|
||||||
|
obj = { foo: 'bar' };
|
||||||
|
|
||||||
|
expect(pp(obj, customObjectFormatters)).toEqual("Object({ foo: 'bar' })");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -42,9 +42,14 @@ describe("ArrayContaining", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("jasmineToStrings itself", function() {
|
it("jasmineToStrings itself", function() {
|
||||||
var containing = new jasmineUnderTest.ArrayContaining([]);
|
var sample = [],
|
||||||
|
matcher = new jasmineUnderTest.ArrayContaining(sample),
|
||||||
|
pp = jasmine.createSpy('pp').and.returnValue('sample');
|
||||||
|
|
||||||
expect(containing.jasmineToString()).toMatch("<jasmine.arrayContaining");
|
expect(matcher.jasmineToString(pp)).toEqual(
|
||||||
|
'<jasmine.arrayContaining(sample)>'
|
||||||
|
);
|
||||||
|
expect(pp).toHaveBeenCalledWith(sample);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses custom equality testers", function() {
|
it("uses custom equality testers", function() {
|
||||||
|
|||||||
@@ -30,9 +30,14 @@ describe("ArrayWithExactContents", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("jasmineToStrings itself", function() {
|
it("jasmineToStrings itself", function() {
|
||||||
var matcher = new jasmineUnderTest.ArrayWithExactContents([]);
|
var sample = [],
|
||||||
|
matcher = new jasmineUnderTest.ArrayWithExactContents(sample),
|
||||||
|
pp = jasmine.createSpy('pp').and.returnValue('sample');
|
||||||
|
|
||||||
expect(matcher.jasmineToString()).toMatch("<jasmine.arrayWithExactContents");
|
expect(matcher.jasmineToString(pp)).toEqual(
|
||||||
|
'<jasmine.arrayWithExactContents(sample)>'
|
||||||
|
);
|
||||||
|
expect(pp).toHaveBeenCalledWith(sample);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses custom equality testers", function() {
|
it("uses custom equality testers", function() {
|
||||||
|
|||||||
@@ -184,8 +184,13 @@ describe('MapContaining', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('defines a `jasmineToString` method', function() {
|
it('defines a `jasmineToString` method', function() {
|
||||||
var containing = new jasmineUnderTest.MapContaining(new Map());
|
var sample = new Map(),
|
||||||
|
containing = new jasmineUnderTest.MapContaining(sample),
|
||||||
|
pp = jasmine.createSpy('pp').and.returnValue('sample');
|
||||||
|
|
||||||
expect(containing.jasmineToString()).toMatch(/^<jasmine\.mapContaining/);
|
expect(containing.jasmineToString(pp)).toEqual(
|
||||||
|
'<jasmine.mapContaining(sample)>'
|
||||||
|
);
|
||||||
|
expect(pp).toHaveBeenCalledWith(sample);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -37,9 +37,15 @@ describe("ObjectContaining", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("jasmineToString's itself", function() {
|
it("jasmineToString's itself", function() {
|
||||||
var containing = new jasmineUnderTest.ObjectContaining({});
|
var sample = {},
|
||||||
|
matcher = new jasmineUnderTest.ObjectContaining(sample),
|
||||||
|
pp = jasmine.createSpy('pp').and.returnValue('sample');
|
||||||
|
|
||||||
|
expect(matcher.jasmineToString(pp)).toEqual(
|
||||||
|
'<jasmine.objectContaining(sample)>'
|
||||||
|
);
|
||||||
|
expect(pp).toHaveBeenCalledWith(sample);
|
||||||
|
|
||||||
expect(containing.jasmineToString()).toMatch("<jasmine.objectContaining");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("matches recursively", function() {
|
it("matches recursively", function() {
|
||||||
|
|||||||
@@ -117,8 +117,13 @@ describe('SetContaining', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('defines a `jasmineToString` method', function() {
|
it('defines a `jasmineToString` method', function() {
|
||||||
var containing = new jasmineUnderTest.SetContaining(new Set());
|
var sample = new Set(),
|
||||||
|
containing = new jasmineUnderTest.SetContaining(sample),
|
||||||
|
pp = jasmine.createSpy('pp').and.returnValue('sample');
|
||||||
|
|
||||||
expect(containing.jasmineToString()).toMatch(/^<jasmine\.setContaining/);
|
expect(containing.jasmineToString(pp)).toEqual(
|
||||||
|
'<jasmine.setContaining(sample)>'
|
||||||
|
);
|
||||||
|
expect(pp).toHaveBeenCalledWith(sample);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
67
spec/core/integration/CustomObjectFormatterSpec.js
Normal file
67
spec/core/integration/CustomObjectFormatterSpec.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
describe("Custom object formatters", function() {
|
||||||
|
var env;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
env = new jasmineUnderTest.Env();
|
||||||
|
env.configure({random: false});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("scopes custom object formatters to a spec", function(done) {
|
||||||
|
env.it('a spec with custom pretty-printer', function() {
|
||||||
|
env.addCustomObjectFormatter(function(obj) { return 'custom(' + obj + ')'; });
|
||||||
|
env.expect(42).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it('a spec without custom pretty-printer', function() {
|
||||||
|
env.expect(42).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
var specResults = [];
|
||||||
|
var specDone = function(result) {
|
||||||
|
specResults.push(result);
|
||||||
|
};
|
||||||
|
var expectations = function() {
|
||||||
|
expect(specResults[0].failedExpectations[0].message).toEqual("Expected custom(42) to be undefined.");
|
||||||
|
expect(specResults[1].failedExpectations[0].message).toEqual("Expected 42 to be undefined.");
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
env.addReporter({ specDone:specDone, jasmineDone: expectations});
|
||||||
|
|
||||||
|
env.execute();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("scopes custom object formatters to a suite", function(done) {
|
||||||
|
env.it('a spec without custom pretty-printer', function() {
|
||||||
|
env.expect(42).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
env.describe('with custom pretty-printer', function() {
|
||||||
|
env.beforeEach(function() {
|
||||||
|
env.addCustomObjectFormatter(function(obj) { return 'custom(' + obj + ')'; });
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it('a spec', function() {
|
||||||
|
env.expect(42).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var specResults = [];
|
||||||
|
var specDone = function(result) {
|
||||||
|
specResults.push(result);
|
||||||
|
};
|
||||||
|
var expectations = function() {
|
||||||
|
expect(specResults[0].failedExpectations[0].message).toEqual("Expected 42 to be undefined.");
|
||||||
|
expect(specResults[1].failedExpectations[0].message).toEqual("Expected custom(42) to be undefined.");
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
env.addReporter({ specDone:specDone, jasmineDone: expectations});
|
||||||
|
|
||||||
|
env.execute();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws an exception if you try to add a custom object formatter outside a runable", function() {
|
||||||
|
expect(function() {
|
||||||
|
env.addCustomObjectFormatter(function() {});
|
||||||
|
}).toThrowError('Custom object formatters must be added in a before function or a spec')
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -48,6 +48,28 @@ describe('Matchers (Integration)', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function verifyFailsWithCustomObjectFormatters(config) {
|
||||||
|
it('uses custom object formatters', function(done) {
|
||||||
|
var env = new jasmineUnderTest.Env();
|
||||||
|
env.it('a spec', function () {
|
||||||
|
env.addCustomObjectFormatter(config.formatter);
|
||||||
|
config.expectations(env);
|
||||||
|
});
|
||||||
|
|
||||||
|
var specExpectations = function (result) {
|
||||||
|
expect(result.status).toEqual('failed');
|
||||||
|
expect(result.failedExpectations.length)
|
||||||
|
.withContext('Number of failed expectations')
|
||||||
|
.toEqual(1);
|
||||||
|
expect(result.failedExpectations[0].message)
|
||||||
|
.toEqual(config.expectedMessage);
|
||||||
|
};
|
||||||
|
|
||||||
|
env.addReporter({specDone: specExpectations, jasmineDone: done});
|
||||||
|
env.execute();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function verifyPassesAsync(expectations) {
|
function verifyPassesAsync(expectations) {
|
||||||
it('passes', function(done) {
|
it('passes', function(done) {
|
||||||
jasmine.getEnv().requirePromises();
|
jasmine.getEnv().requirePromises();
|
||||||
@@ -101,6 +123,30 @@ describe('Matchers (Integration)', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function verifyFailsWithCustomObjectFormattersAsync(config) {
|
||||||
|
it('uses custom object formatters', function(done) {
|
||||||
|
var env = new jasmineUnderTest.Env();
|
||||||
|
jasmine.getEnv().requirePromises();
|
||||||
|
env.it('a spec', function () {
|
||||||
|
env.addCustomObjectFormatter(config.formatter);
|
||||||
|
return config.expectations(env);
|
||||||
|
});
|
||||||
|
|
||||||
|
var specExpectations = function (result) {
|
||||||
|
expect(result.status).toEqual('failed');
|
||||||
|
expect(result.failedExpectations.length)
|
||||||
|
.withContext('Number of failed expectations')
|
||||||
|
.toEqual(1);
|
||||||
|
expect(result.failedExpectations[0].message)
|
||||||
|
.toEqual(config.expectedMessage);
|
||||||
|
};
|
||||||
|
|
||||||
|
env.addReporter({specDone: specExpectations, jasmineDone: done});
|
||||||
|
env.execute();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
describe('nothing', function() {
|
describe('nothing', function() {
|
||||||
verifyPasses(function(env) {
|
verifyPasses(function(env) {
|
||||||
env.expect().nothing();
|
env.expect().nothing();
|
||||||
@@ -217,6 +263,16 @@ describe('Matchers (Integration)', function() {
|
|||||||
verifyFails(function(env) {
|
verifyFails(function(env) {
|
||||||
env.expect(2).toBeNaN();
|
env.expect(2).toBeNaN();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormatters({
|
||||||
|
formatter: function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
env.expect(1).toBeNaN();
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected |1| to be NaN.'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toBeNegativeInfinity', function() {
|
describe('toBeNegativeInfinity', function() {
|
||||||
@@ -227,6 +283,16 @@ describe('Matchers (Integration)', function() {
|
|||||||
verifyFails(function(env) {
|
verifyFails(function(env) {
|
||||||
env.expect(2).toBeNegativeInfinity();
|
env.expect(2).toBeNegativeInfinity();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormatters({
|
||||||
|
formatter: function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
env.expect(1).toBeNegativeInfinity();
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected |1| to be -Infinity.'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toBeNull', function() {
|
describe('toBeNull', function() {
|
||||||
@@ -247,6 +313,16 @@ describe('Matchers (Integration)', function() {
|
|||||||
verifyFails(function(env) {
|
verifyFails(function(env) {
|
||||||
env.expect(2).toBePositiveInfinity();
|
env.expect(2).toBePositiveInfinity();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormatters({
|
||||||
|
formatter: function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
env.expect(1).toBePositiveInfinity();
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected |1| to be Infinity.'
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toBeResolved', function() {
|
describe('toBeResolved', function() {
|
||||||
@@ -270,6 +346,17 @@ describe('Matchers (Integration)', function() {
|
|||||||
verifyFailsAsync(function(env) {
|
verifyFailsAsync(function(env) {
|
||||||
return env.expectAsync(Promise.resolve('foo')).toBeResolvedTo('bar');
|
return env.expectAsync(Promise.resolve('foo')).toBeResolvedTo('bar');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormattersAsync({
|
||||||
|
formatter: function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
return env.expectAsync(Promise.resolve('x')).toBeResolvedTo('y');
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected a promise to be resolved to |y| ' +
|
||||||
|
'but it was resolved to |x|.'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toBeRejected', function() {
|
describe('toBeRejected', function() {
|
||||||
@@ -293,6 +380,17 @@ describe('Matchers (Integration)', function() {
|
|||||||
verifyFailsAsync(function(env) {
|
verifyFailsAsync(function(env) {
|
||||||
return env.expectAsync(Promise.resolve()).toBeRejectedWith('nope');
|
return env.expectAsync(Promise.resolve()).toBeRejectedWith('nope');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormattersAsync({
|
||||||
|
formatter: function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
return env.expectAsync(Promise.reject('x')).toBeRejectedWith('y');
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected a promise to be rejected with |y| ' +
|
||||||
|
'but it was rejected with |x|.'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toBeRejectedWithError', function() {
|
describe('toBeRejectedWithError', function() {
|
||||||
@@ -303,6 +401,17 @@ describe('Matchers (Integration)', function() {
|
|||||||
verifyFailsAsync(function(env) {
|
verifyFailsAsync(function(env) {
|
||||||
return env.expectAsync(Promise.resolve()).toBeRejectedWithError(Error);
|
return env.expectAsync(Promise.resolve()).toBeRejectedWithError(Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormattersAsync({
|
||||||
|
formatter: function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
return env.expectAsync(Promise.reject('foo')).toBeRejectedWithError('foo');
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected a promise to be rejected with Error: |foo| ' +
|
||||||
|
'but it was rejected with |foo|.'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toBeTrue', function() {
|
describe('toBeTrue', function() {
|
||||||
@@ -359,6 +468,20 @@ describe('Matchers (Integration)', function() {
|
|||||||
verifyFails(function(env) {
|
verifyFails(function(env) {
|
||||||
env.expect('a').toEqual('b');
|
env.expect('a').toEqual('b');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormatters({
|
||||||
|
formatter: function(val) {
|
||||||
|
if (val === 5) {
|
||||||
|
return "five"
|
||||||
|
} else if (val === 4) {
|
||||||
|
return "four"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
env.expect([{foo: 4}]).toEqual([{foo: 5}]);
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected $[0].foo = four to equal five.'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toHaveBeenCalled', function() {
|
describe('toHaveBeenCalled', function() {
|
||||||
@@ -417,6 +540,19 @@ describe('Matchers (Integration)', function() {
|
|||||||
var spy = env.createSpy();
|
var spy = env.createSpy();
|
||||||
env.expect(spy).toHaveBeenCalledWith('foo');
|
env.expect(spy).toHaveBeenCalledWith('foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormatters({
|
||||||
|
formatter: function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
var spy = env.createSpy('foo');
|
||||||
|
env.expect(spy).toHaveBeenCalledWith('x');
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected spy foo to have been called with:\n' +
|
||||||
|
' |x|\n' +
|
||||||
|
'but it was never called.'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toHaveClass', function() {
|
describe('toHaveClass', function() {
|
||||||
@@ -458,6 +594,19 @@ describe('Matchers (Integration)', function() {
|
|||||||
verifyFails(function(env) {
|
verifyFails(function(env) {
|
||||||
env.expect(function() {}).toThrow();
|
env.expect(function() {}).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormatters({
|
||||||
|
formatter: function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
var spy = env.createSpy('foo');
|
||||||
|
env.expect(function() {
|
||||||
|
throw 'x'
|
||||||
|
}).not.toThrow();
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected function not to throw, but it threw |x|.'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toThrowError', function() {
|
describe('toThrowError', function() {
|
||||||
@@ -468,6 +617,19 @@ describe('Matchers (Integration)', function() {
|
|||||||
verifyFails(function(env) {
|
verifyFails(function(env) {
|
||||||
env.expect(function() { }).toThrowError();
|
env.expect(function() { }).toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormatters({
|
||||||
|
formatter: function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
var spy = env.createSpy('foo');
|
||||||
|
env.expect(function() {
|
||||||
|
throw 'x'
|
||||||
|
}).toThrowError();
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected function to throw an Error, but it threw |x|.'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toThrowMatching', function() {
|
describe('toThrowMatching', function() {
|
||||||
@@ -482,5 +644,21 @@ describe('Matchers (Integration)', function() {
|
|||||||
verifyFails(function(env) {
|
verifyFails(function(env) {
|
||||||
env.expect(throws).toThrowMatching(function() { return false; });
|
env.expect(throws).toThrowMatching(function() { return false; });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
verifyFailsWithCustomObjectFormatters({
|
||||||
|
formatter: function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
expectations: function(env) {
|
||||||
|
var spy = env.createSpy('foo');
|
||||||
|
env.expect(function() {
|
||||||
|
throw new Error('nope')
|
||||||
|
}).toThrowMatching(function() {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
expectedMessage: 'Expected function to throw an exception matching ' +
|
||||||
|
'a predicate, but it threw Error with message |nope|.'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -44,4 +44,30 @@ describe("DiffBuilder", function() {
|
|||||||
|
|
||||||
expect(diffBuilder.getMessage()).toEqual("I find your lack of foo disturbing. (was bar, at $.x)");
|
expect(diffBuilder.getMessage()).toEqual("I find your lack of foo disturbing. (was bar, at $.x)");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses the injected pretty-printer", function() {
|
||||||
|
var prettyPrinter = function(val) {
|
||||||
|
return '|' + val + '|';
|
||||||
|
},
|
||||||
|
diffBuilder = jasmineUnderTest.DiffBuilder({prettyPrinter: prettyPrinter});
|
||||||
|
|
||||||
|
diffBuilder.withPath('foo', function() {
|
||||||
|
diffBuilder.record('actual', 'expected');
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(diffBuilder.getMessage()).toEqual("Expected $.foo = |actual| to equal |expected|.");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("passes the injected pretty-printer to the diff formatter", function() {
|
||||||
|
var diffFormatter = jasmine.createSpy('diffFormatter'),
|
||||||
|
prettyPrinter = function() {},
|
||||||
|
diffBuilder = jasmineUnderTest.DiffBuilder({prettyPrinter: prettyPrinter});
|
||||||
|
|
||||||
|
diffBuilder.withPath('x', function() {
|
||||||
|
diffBuilder.record('bar', 'foo', diffFormatter);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(diffFormatter).toHaveBeenCalledWith('bar', 'foo', jasmine.anything(), prettyPrinter);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -840,7 +840,7 @@ describe("matchersUtil", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("buildMessage", function() {
|
describe("buildFailureMessage", function() {
|
||||||
|
|
||||||
it("builds an English sentence for a failure case", function() {
|
it("builds an English sentence for a failure case", function() {
|
||||||
var actual = "foo",
|
var actual = "foo",
|
||||||
@@ -873,15 +873,17 @@ describe("matchersUtil", function() {
|
|||||||
expect(message).toEqual("Expected 'foo' to bar 'quux', 'corge'.");
|
expect(message).toEqual("Expected 'foo' to bar 'quux', 'corge'.");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses the injected pretty-printer to format the expected", function() {
|
it("uses the injected pretty-printer to format the expecteds and actual", function() {
|
||||||
var actual = "foo",
|
var actual = "foo",
|
||||||
|
expected1 = "qux",
|
||||||
|
expected2 = "grault",
|
||||||
name = "toBar",
|
name = "toBar",
|
||||||
isNot = false,
|
isNot = false,
|
||||||
pp = function(value) { return '<' + value + '>'; },
|
pp = function(value) { return '<' + value + '>'; },
|
||||||
matchersUtil = new jasmineUnderTest.MatchersUtil({pp: pp}),
|
matchersUtil = new jasmineUnderTest.MatchersUtil({pp: pp}),
|
||||||
message = message = matchersUtil.buildFailureMessage(name, isNot, actual);
|
message = message = matchersUtil.buildFailureMessage(name, isNot, actual, expected1, expected2);
|
||||||
|
|
||||||
expect(message).toEqual("Expected <foo> to bar.");
|
expect(message).toEqual("Expected <foo> to bar <qux>, <grault>.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -59,4 +59,16 @@ describe("toBe", function() {
|
|||||||
expect(result.pass).toBe(false);
|
expect(result.pass).toBe(false);
|
||||||
expect(result.message).toBe("Expected Object({ foo: 'bar' }) to be Object({ foo: 'bar' }). Tip: To check for deep equality, use .toEqual() instead of .toBe().")
|
expect(result.message).toBe("Expected Object({ foo: 'bar' }) to be Object({ foo: 'bar' }). Tip: To check for deep equality, use .toEqual() instead of .toBe().")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("works with custom object formatters when expected is an object", function() {
|
||||||
|
var formatter = function(x) { return '<' + x.foo + '>'; },
|
||||||
|
prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]),
|
||||||
|
util = new jasmineUnderTest.MatchersUtil({pp: prettyPrinter}),
|
||||||
|
matcher = jasmineUnderTest.matchers.toBe(util),
|
||||||
|
result;
|
||||||
|
|
||||||
|
result = matcher.compare({foo: "bar"}, {foo: "bar"});
|
||||||
|
expect(result.pass).toBe(false);
|
||||||
|
expect(result.message).toBe("Expected <bar> to be <bar>. Tip: To check for deep equality, use .toEqual() instead of .toBe().")
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -97,14 +97,34 @@ describe("toEqual", function() {
|
|||||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("reports extra and missing properties together", function() {
|
it("uses custom object formatters to pretty-print properties", function() {
|
||||||
|
function formatter(x) { return '|' + x + '|'; }
|
||||||
|
|
||||||
var actual = {x: {y: 1, z: 2, f: 4}},
|
var actual = {x: {y: 1, z: 2, f: 4}},
|
||||||
expected = {x: {y: 1, z: 2, g: 3}},
|
expected = {x: {y: 1, z: 2, g: 3}},
|
||||||
|
pp = jasmineUnderTest.makePrettyPrinter([formatter]),
|
||||||
|
util = new jasmineUnderTest.MatchersUtil({pp: pp}),
|
||||||
|
matcher = jasmineUnderTest.matchers.toEqual(util),
|
||||||
message =
|
message =
|
||||||
"Expected $.x to have properties\n" +
|
"Expected $.x to have properties\n" +
|
||||||
" g: 3\n" +
|
" g: |3|\n" +
|
||||||
"Expected $.x not to have properties\n" +
|
"Expected $.x not to have properties\n" +
|
||||||
" f: 4";
|
" f: |4|";
|
||||||
|
|
||||||
|
expect(matcher.compare(actual, expected).message).toEqual(message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses custom object formatters to build diffs", function() {
|
||||||
|
function formatter(x) { return '|' + x + '|'; }
|
||||||
|
|
||||||
|
var actual = [{foo: 4}],
|
||||||
|
expected = [{foo: 5}],
|
||||||
|
prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]),
|
||||||
|
util = new jasmineUnderTest.MatchersUtil({pp: prettyPrinter}),
|
||||||
|
matcher = jasmineUnderTest.matchers.toEqual(util),
|
||||||
|
message = "Expected $[0].foo = |4| to equal |5|.";
|
||||||
|
|
||||||
|
expect(matcher.compare(actual, expected).message).toEqual(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("reports extra and missing properties of the root-level object", function() {
|
it("reports extra and missing properties of the root-level object", function() {
|
||||||
@@ -277,12 +297,27 @@ describe("toEqual", function() {
|
|||||||
function Bar() {}
|
function Bar() {}
|
||||||
|
|
||||||
var actual = {x: new Foo()},
|
var actual = {x: new Foo()},
|
||||||
expected = {x: new Bar()},
|
expected = {x: new Bar()},
|
||||||
message = "Expected $.x to be a kind of Bar, but was Foo({ }).";
|
message = "Expected $.x to be a kind of Bar, but was Foo({ }).";
|
||||||
|
|
||||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses custom object formatters to report objects with different constructors", function () {
|
||||||
|
function Foo() {}
|
||||||
|
function Bar() {}
|
||||||
|
function formatter(x) { return '|' + x + '|'; }
|
||||||
|
|
||||||
|
var actual = {x: new Foo()},
|
||||||
|
expected = {x: new Bar()},
|
||||||
|
message = "Expected $.x to be a kind of Bar, but was |[object Object]|.",
|
||||||
|
pp = jasmineUnderTest.makePrettyPrinter([formatter]),
|
||||||
|
util = new jasmineUnderTest.MatchersUtil({pp: pp}),
|
||||||
|
matcher = jasmineUnderTest.matchers.toEqual(util);
|
||||||
|
|
||||||
|
expect(matcher.compare(actual, expected).message).toEqual(message);
|
||||||
|
});
|
||||||
|
|
||||||
it("reports type mismatches at the root level", function () {
|
it("reports type mismatches at the root level", function () {
|
||||||
function Foo() {}
|
function Foo() {}
|
||||||
function Bar() {}
|
function Bar() {}
|
||||||
@@ -803,6 +838,20 @@ describe("toEqual", function() {
|
|||||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses custom object formatters when the actual array is longer", function() {
|
||||||
|
function formatter(x) { return '|' + x + '|'; }
|
||||||
|
|
||||||
|
var actual = [1, 1, 2, 3, 5],
|
||||||
|
expected = [1, 1, 2, 3],
|
||||||
|
pp = jasmineUnderTest.makePrettyPrinter([formatter]),
|
||||||
|
util = new jasmineUnderTest.MatchersUtil({pp: pp}),
|
||||||
|
matcher = jasmineUnderTest.matchers.toEqual(util),
|
||||||
|
message = 'Expected $.length = |5| to equal |4|.\n' +
|
||||||
|
'Unexpected $[4] = |5| in array.';
|
||||||
|
|
||||||
|
expect(matcher.compare(actual, expected).message).toEqual(message);
|
||||||
|
});
|
||||||
|
|
||||||
it("expected array is longer", function() {
|
it("expected array is longer", function() {
|
||||||
var actual = [1, 1, 2, 3],
|
var actual = [1, 1, 2, 3],
|
||||||
expected = [1, 1, 2, 3, 5],
|
expected = [1, 1, 2, 3, 5],
|
||||||
|
|||||||
@@ -296,6 +296,18 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.addCustomObjectFormatter = function(formatter) {
|
||||||
|
if (!currentRunnable()) {
|
||||||
|
throw new Error(
|
||||||
|
'Custom object formatters must be added in a before function or a spec'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
runnableResources[currentRunnable().id].customObjectFormatters.push(
|
||||||
|
formatter
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
j$.Expectation.addCoreMatchers(j$.matchers);
|
j$.Expectation.addCoreMatchers(j$.matchers);
|
||||||
j$.Expectation.addAsyncCoreMatchers(j$.asyncMatchers);
|
j$.Expectation.addAsyncCoreMatchers(j$.asyncMatchers);
|
||||||
|
|
||||||
@@ -310,7 +322,9 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var makePrettyPrinter = function() {
|
var makePrettyPrinter = function() {
|
||||||
return j$.makePrettyPrinter();
|
var customObjectFormatters =
|
||||||
|
runnableResources[currentRunnable().id].customObjectFormatters;
|
||||||
|
return j$.makePrettyPrinter(customObjectFormatters);
|
||||||
};
|
};
|
||||||
|
|
||||||
var makeMatchersUtil = function() {
|
var makeMatchersUtil = function() {
|
||||||
@@ -360,7 +374,8 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
customMatchers: {},
|
customMatchers: {},
|
||||||
customAsyncMatchers: {},
|
customAsyncMatchers: {},
|
||||||
customSpyStrategies: {},
|
customSpyStrategies: {},
|
||||||
defaultStrategyFn: undefined
|
defaultStrategyFn: undefined,
|
||||||
|
customObjectFormatters: []
|
||||||
};
|
};
|
||||||
|
|
||||||
if (runnableResources[parentRunnableId]) {
|
if (runnableResources[parentRunnableId]) {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
||||||
function SinglePrettyPrintRun() {
|
function SinglePrettyPrintRun(customObjectFormatters, pp) {
|
||||||
|
this.customObjectFormatters_ = customObjectFormatters;
|
||||||
this.ppNestLevel_ = 0;
|
this.ppNestLevel_ = 0;
|
||||||
this.seen = [];
|
this.seen = [];
|
||||||
this.length = 0;
|
this.length = 0;
|
||||||
this.stringParts = [];
|
this.stringParts = [];
|
||||||
|
this.pp_ = pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasCustomToString(value) {
|
function hasCustomToString(value) {
|
||||||
@@ -24,7 +26,11 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
|||||||
SinglePrettyPrintRun.prototype.format = function(value) {
|
SinglePrettyPrintRun.prototype.format = function(value) {
|
||||||
this.ppNestLevel_++;
|
this.ppNestLevel_++;
|
||||||
try {
|
try {
|
||||||
if (j$.util.isUndefined(value)) {
|
var customFormatResult = this.applyCustomFormatters_(value);
|
||||||
|
|
||||||
|
if (customFormatResult) {
|
||||||
|
this.emitScalar(customFormatResult);
|
||||||
|
} else if (j$.util.isUndefined(value)) {
|
||||||
this.emitScalar('undefined');
|
this.emitScalar('undefined');
|
||||||
} else if (value === null) {
|
} else if (value === null) {
|
||||||
this.emitScalar('null');
|
this.emitScalar('null');
|
||||||
@@ -33,7 +39,7 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
|||||||
} else if (value === j$.getGlobal()) {
|
} else if (value === j$.getGlobal()) {
|
||||||
this.emitScalar('<global>');
|
this.emitScalar('<global>');
|
||||||
} else if (value.jasmineToString) {
|
} else if (value.jasmineToString) {
|
||||||
this.emitScalar(value.jasmineToString());
|
this.emitScalar(value.jasmineToString(this.pp_));
|
||||||
} else if (typeof value === 'string') {
|
} else if (typeof value === 'string') {
|
||||||
this.emitString(value);
|
this.emitString(value);
|
||||||
} else if (j$.isSpy(value)) {
|
} else if (j$.isSpy(value)) {
|
||||||
@@ -95,6 +101,18 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) {
|
||||||
|
var i, result;
|
||||||
|
|
||||||
|
for (i = 0; i < this.customObjectFormatters_.length; i++) {
|
||||||
|
result = this.customObjectFormatters_[i](value);
|
||||||
|
|
||||||
|
if (result !== undefined) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) {
|
SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) {
|
||||||
var objKeys = keys(obj, j$.isArray_(obj));
|
var objKeys = keys(obj, j$.isArray_(obj));
|
||||||
var isGetter = function isGetter(prop) {};
|
var isGetter = function isGetter(prop) {};
|
||||||
@@ -365,11 +383,16 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
|||||||
return extraKeys;
|
return extraKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
return function() {
|
return function(customObjectFormatters) {
|
||||||
return function(value) {
|
var pp = function(value) {
|
||||||
var prettyPrinter = new SinglePrettyPrintRun();
|
var prettyPrinter = new SinglePrettyPrintRun(
|
||||||
|
customObjectFormatters || [],
|
||||||
|
pp
|
||||||
|
);
|
||||||
prettyPrinter.format(value);
|
prettyPrinter.format(value);
|
||||||
return prettyPrinter.stringParts.join('');
|
return prettyPrinter.stringParts.join('');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return pp;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
ArrayContaining.prototype.jasmineToString = function () {
|
ArrayContaining.prototype.jasmineToString = function (pp) {
|
||||||
return '<jasmine.arrayContaining(' + j$.pp(this.sample) +')>';
|
return '<jasmine.arrayContaining(' + pp(this.sample) +')>';
|
||||||
};
|
};
|
||||||
|
|
||||||
return ArrayContaining;
|
return ArrayContaining;
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
ArrayWithExactContents.prototype.jasmineToString = function() {
|
ArrayWithExactContents.prototype.jasmineToString = function(pp) {
|
||||||
return '<jasmine.arrayWithExactContents ' + j$.pp(this.sample) + '>';
|
return '<jasmine.arrayWithExactContents(' + pp(this.sample) + ')>';
|
||||||
};
|
};
|
||||||
|
|
||||||
return ArrayWithExactContents;
|
return ArrayWithExactContents;
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ getJasmineRequireObj().MapContaining = function(j$) {
|
|||||||
return hasAllMatches;
|
return hasAllMatches;
|
||||||
};
|
};
|
||||||
|
|
||||||
MapContaining.prototype.jasmineToString = function() {
|
MapContaining.prototype.jasmineToString = function(pp) {
|
||||||
return '<jasmine.mapContaining(' + j$.pp(this.sample) + ')>';
|
return '<jasmine.mapContaining(' + pp(this.sample) + ')>';
|
||||||
};
|
};
|
||||||
|
|
||||||
return MapContaining;
|
return MapContaining;
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
ObjectContaining.prototype.jasmineToString = function() {
|
ObjectContaining.prototype.jasmineToString = function(pp) {
|
||||||
return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
|
return '<jasmine.objectContaining(' + pp(this.sample) + ')>';
|
||||||
};
|
};
|
||||||
|
|
||||||
return ObjectContaining;
|
return ObjectContaining;
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ getJasmineRequireObj().SetContaining = function(j$) {
|
|||||||
return hasAllMatches;
|
return hasAllMatches;
|
||||||
};
|
};
|
||||||
|
|
||||||
SetContaining.prototype.jasmineToString = function() {
|
SetContaining.prototype.jasmineToString = function(pp) {
|
||||||
return '<jasmine.setContaining(' + j$.pp(this.sample) + ')>';
|
return '<jasmine.setContaining(' + pp(this.sample) + ')>';
|
||||||
};
|
};
|
||||||
|
|
||||||
return SetContaining;
|
return SetContaining;
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
getJasmineRequireObj().DiffBuilder = function(j$) {
|
getJasmineRequireObj().DiffBuilder = function(j$) {
|
||||||
return function DiffBuilder() {
|
return function DiffBuilder(config) {
|
||||||
var path = new j$.ObjectPath(),
|
var path = new j$.ObjectPath(),
|
||||||
mismatches = [];
|
mismatches = [],
|
||||||
|
prettyPrinter = (config || {}).prettyPrinter || j$.makePrettyPrinter();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
record: function (actual, expected, formatter) {
|
record: function (actual, expected, formatter) {
|
||||||
formatter = formatter || defaultFormatter;
|
formatter = formatter || defaultFormatter;
|
||||||
mismatches.push(formatter(actual, expected, path));
|
mismatches.push(formatter(actual, expected, path, prettyPrinter));
|
||||||
},
|
},
|
||||||
|
|
||||||
getMessage: function () {
|
getMessage: function () {
|
||||||
@@ -21,12 +22,12 @@ getJasmineRequireObj().DiffBuilder = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function defaultFormatter (actual, expected, path) {
|
function defaultFormatter (actual, expected, path, prettyPrinter) {
|
||||||
return 'Expected ' +
|
return 'Expected ' +
|
||||||
path + (path.depth() ? ' = ' : '') +
|
path + (path.depth() ? ' = ' : '') +
|
||||||
j$.pp(actual) +
|
prettyPrinter(actual) +
|
||||||
' to equal ' +
|
' to equal ' +
|
||||||
j$.pp(expected) +
|
prettyPrinter(expected) +
|
||||||
'.';
|
'.';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
message += ',';
|
message += ',';
|
||||||
}
|
}
|
||||||
message += ' ' + j$.pp(expected[i]);
|
message += ' ' + self.pp(expected[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ getJasmineRequireObj().toEqual = function(j$) {
|
|||||||
var result = {
|
var result = {
|
||||||
pass: false
|
pass: false
|
||||||
},
|
},
|
||||||
diffBuilder = j$.DiffBuilder();
|
diffBuilder = j$.DiffBuilder({prettyPrinter: util.pp});
|
||||||
|
|
||||||
result.pass = util.equals(actual, expected, diffBuilder);
|
result.pass = util.equals(actual, expected, diffBuilder);
|
||||||
|
|
||||||
|
|||||||
@@ -316,6 +316,20 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
|||||||
return env.addAsyncMatchers(matchers);
|
return env.addAsyncMatchers(matchers);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a custom object formatter for the current scope of specs.
|
||||||
|
*
|
||||||
|
* _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
|
||||||
|
* @name jasmine.addCustomObjectFormatter
|
||||||
|
* @since 3.6.0
|
||||||
|
* @function
|
||||||
|
* @param {Function} formatter - A function which takes a value to format and returns a string if it knows how to format it, and `undefined` otherwise.
|
||||||
|
* @see custom_object_formatter
|
||||||
|
*/
|
||||||
|
jasmine.addCustomObjectFormatter = function(formatter) {
|
||||||
|
return env.addCustomObjectFormatter(formatter);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the currently booted mock {Clock} for this Jasmine environment.
|
* Get the currently booted mock {Clock} for this Jasmine environment.
|
||||||
* @name jasmine.clock
|
* @name jasmine.clock
|
||||||
|
|||||||
Reference in New Issue
Block a user