Skip to content
Permalink
Browse files

Show the type signature of the subject and arguments when failing wit…

…h "assertion not found".

As suggested by @sunesimonsen on #339
  • Loading branch information...
papandreou committed Jan 22, 2017
1 parent bcd0263 commit 96f5f7c4e175daf9449e2a36aac550de4a008918
@@ -847,6 +847,7 @@ function calculateLimits(items) {

Unexpected.prototype.throwAssertionNotFoundError = function (subject, testDescriptionString, args) {
var candidateHandlers = this.assertions[testDescriptionString];
var that = this;
if (candidateHandlers) {
this.fail({
message: function (output) {
@@ -858,21 +859,30 @@ Unexpected.prototype.throwAssertionNotFoundError = function (subject, testDescri
};
output.append(createStandardErrorMessage(output.clone(), subjectOutput, testDescriptionString, argsOutput)).nl()
.indentLines();
output.i().error('No matching assertion, did you mean:').nl();
output.i().error('The assertion does not have a matching signature for:').nl()
.indentLines().i().text('<').text(that.findTypeOf(subject).name).text('>').sp().text(testDescriptionString);

args.forEach(function (arg, i) {
output.sp().text('<').text(that.findTypeOf(arg).name).text('>');
});

output
.outdentLines()
.nl()
.i().text('did you mean:').nl();
var assertionDeclarations = Object.keys(candidateHandlers.reduce(function (result, handler) {
result[handler.declaration] = true;
return result;
}, {})).sort();
assertionDeclarations.forEach(function (declaration, i) {
output.nl(i > 0 ? 1 : 0).i().text(declaration);
output.nl(i > 0 ? 1 : 0).i().i().text(declaration);
});
}
});
}

var assertionsWithScore = [];
var assertionStrings = Object.keys(this.assertions);
var that = this;

function compareAssertions(a, b) {
var aAssertion = that.lookupAssertionRule(subject, a, args);
@@ -43,9 +43,12 @@ describe('clone', function () {
expect(function () {
clonedExpect('foobarquux', 'to foobarquux');
}, 'to throw',
"expected 'foobarquux' to foobarquux\n" +
" No matching assertion, did you mean:\n" +
" <array> to foobarquux");
"expected 'foobarquux' to foobarquux\n" +
" The assertion does not have a matching signature for:\n" +
" <string> to foobarquux\n" +
" did you mean:\n" +
" <array> to foobarquux"
);
});

it('prefers to suggest a similarly named assertion defined for the correct type over an exact match defined for other types', function () {
@@ -57,20 +60,26 @@ describe('clone', function () {
expect(function () {
clonedExpect(['fooo'], 'to fooo');
}, 'to throw',
"expected [ 'fooo' ] to fooo\n" +
" No matching assertion, did you mean:\n" +
" <string> to fooo");
"expected [ 'fooo' ] to fooo\n" +
" The assertion does not have a matching signature for:\n" +
" <array> to fooo\n" +
" did you mean:\n" +
" <string> to fooo"
);

clonedExpect.addAssertion('<null> to fooo', function (expect, subject) {
expect(subject.message, 'to equal', 'fooo');
});
expect(function () {
clonedExpect(['fooo'], 'to fooo');
}, 'to throw',
"expected [ 'fooo' ] to fooo\n" +
" No matching assertion, did you mean:\n" +
" <null> to fooo\n" +
" <string> to fooo");
"expected [ 'fooo' ] to fooo\n" +
" The assertion does not have a matching signature for:\n" +
" <array> to fooo\n" +
" did you mean:\n" +
" <null> to fooo\n" +
" <string> to fooo"
);
});

it('prefers to suggest a similarly named assertion for a more specific type', function () {
@@ -119,10 +119,12 @@ describe('expect.shift', function () {
expect(function () {
clonedExpect('foo', 'when prepended with foo', function () {});
}, 'to throw',
"expected 'foo' when prepended with foo function () {}\n" +
" No matching assertion, did you mean:\n" +
" <string> when prepended with foo <assertion>"
);
"expected 'foo' when prepended with foo function () {}\n" +
" The assertion does not have a matching signature for:\n" +
" <string> when prepended with foo <function>\n" +
" did you mean:\n" +
" <string> when prepended with foo <assertion>"
);
});

describe('with an async assertion', function () {
@@ -75,44 +75,56 @@ describe('to be a/an assertion', function () {
expect(function () {
expect('foo', 'to be an', undefined);
}, 'to throw',
"expected 'foo' to be an undefined\n" +
" No matching assertion, did you mean:\n" +
" <any> [not] to be (a|an) <function>\n" +
" <any> [not] to be (a|an) <string>\n" +
" <any> [not] to be (a|an) <type>");
"expected 'foo' to be an undefined\n" +
" The assertion does not have a matching signature for:\n" +
" <string> to be an <undefined>\n" +
" did you mean:\n" +
" <any> [not] to be (a|an) <function>\n" +
" <any> [not] to be (a|an) <string>\n" +
" <any> [not] to be (a|an) <type>"
);
});

it('should throw when the type is specified as null', function () {
expect(function () {
expect('foo', 'to be a', null);
}, 'to throw',
"expected 'foo' to be a null\n" +
" No matching assertion, did you mean:\n" +
" <any> [not] to be (a|an) <function>\n" +
" <any> [not] to be (a|an) <string>\n" +
" <any> [not] to be (a|an) <type>");
"expected 'foo' to be a null\n" +
" The assertion does not have a matching signature for:\n" +
" <string> to be a <null>\n" +
" did you mean:\n" +
" <any> [not] to be (a|an) <function>\n" +
" <any> [not] to be (a|an) <string>\n" +
" <any> [not] to be (a|an) <type>"
);
});

it('should not consider a string a to be an instance of an object without a name property', function () {
expect(function () {
expect('foo', 'to be a', {});
}, 'to throw',
"expected 'foo' to be a {}\n" +
" No matching assertion, did you mean:\n" +
" <any> [not] to be (a|an) <function>\n" +
" <any> [not] to be (a|an) <string>\n" +
" <any> [not] to be (a|an) <type>");
"expected 'foo' to be a {}\n" +
" The assertion does not have a matching signature for:\n" +
" <string> to be a <object>\n" +
" did you mean:\n" +
" <any> [not] to be (a|an) <function>\n" +
" <any> [not] to be (a|an) <string>\n" +
" <any> [not] to be (a|an) <type>"
);
});

it('should throw when the type is specified as an object without an identify function', function () {
expect(function () {
expect('foo', 'to be a', { name: 'bar' });
}, 'to throw',
"expected 'foo' to be a { name: 'bar' }\n" +
" No matching assertion, did you mean:\n" +
" <any> [not] to be (a|an) <function>\n" +
" <any> [not] to be (a|an) <string>\n" +
" <any> [not] to be (a|an) <type>");
"expected 'foo' to be a { name: 'bar' }\n" +
" The assertion does not have a matching signature for:\n" +
" <string> to be a <object>\n" +
" did you mean:\n" +
" <any> [not] to be (a|an) <function>\n" +
" <any> [not] to be (a|an) <string>\n" +
" <any> [not] to be (a|an) <type>"
);
});

it('should throw when the type is specified as an object with an identify function, but without a name property', function () {
@@ -123,10 +135,12 @@ describe('to be a/an assertion', function () {
// http://v8project.blogspot.dk/2016/04/v8-release-51.html
expect(err.getErrorMessage('text').toString().replace('function identify', 'function '), 'to satisfy',
"expected 'foo' to be a { identify: function () { return true; } }\n" +
" No matching assertion, did you mean:\n" +
" <any> [not] to be (a|an) <function>\n" +
" <any> [not] to be (a|an) <string>\n" +
" <any> [not] to be (a|an) <type>"
" The assertion does not have a matching signature for:\n" +
" <string> to be a <object>\n" +
" did you mean:\n" +
" <any> [not] to be (a|an) <function>\n" +
" <any> [not] to be (a|an) <string>\n" +
" <any> [not] to be (a|an) <type>"
);
});
});
@@ -25,10 +25,13 @@ describe('empty assertion', function () {
expect(function () {
expect(null, 'to be empty');
}, 'to throw exception',
"expected null to be empty\n" +
" No matching assertion, did you mean:\n" +
" <object> [not] to be empty\n" +
" <string|array-like> [not] to be empty");
"expected null to be empty\n" +
" The assertion does not have a matching signature for:\n" +
" <null> to be empty\n" +
" did you mean:\n" +
" <object> [not] to be empty\n" +
" <string|array-like> [not] to be empty"
);

expect(function () {
expect({ a: 'b' }, 'to be empty');
@@ -11,9 +11,12 @@ describe('to be finite assertion', function () {
expect(function () {
expect(NaN, 'not to be finite');
}, 'to throw',
"expected NaN not to be finite\n" +
" No matching assertion, did you mean:\n" +
" <number> [not] to be finite");
"expected NaN not to be finite\n" +
" The assertion does not have a matching signature for:\n" +
" <NaN> not to be finite\n" +
" did you mean:\n" +
" <number> [not] to be finite"
);
});

it('throws when the assertion fails', function () {
@@ -16,9 +16,12 @@ describe('greater than assertion', function () {
expect(function () {
expect(NaN, 'not to be greater than', 1);
}, 'to throw',
"expected NaN not to be greater than 1\n" +
" No matching assertion, did you mean:\n" +
" <number> [not] to be (greater than|above) <number>\n" +
" <string> [not] to be (greater than|above) <string>");
"expected NaN not to be greater than 1\n" +
" The assertion does not have a matching signature for:\n" +
" <NaN> not to be greater than <number>\n" +
" did you mean:\n" +
" <number> [not] to be (greater than|above) <number>\n" +
" <string> [not] to be (greater than|above) <string>"
);
});
});
@@ -11,9 +11,12 @@ describe('to be infinite assertion', function () {
expect(function () {
expect(NaN, 'not to be infinite');
}, 'to throw',
"expected NaN not to be infinite\n" +
" No matching assertion, did you mean:\n" +
" <number> [not] to be infinite");
"expected NaN not to be infinite\n" +
" The assertion does not have a matching signature for:\n" +
" <NaN> not to be infinite\n" +
" did you mean:\n" +
" <number> [not] to be infinite"
);
});

it('throws when the assertion fails', function () {
@@ -17,10 +17,13 @@ describe('within assertion', function () {
expect(function () {
expect(null, 'not to be within', 0, 4);
}, 'to throw exception',
"expected null not to be within 0, 4\n" +
" No matching assertion, did you mean:\n" +
" <number> [not] to be within <number> <number>\n" +
" <string> [not] to be within <string> <string>");
"expected null not to be within 0, 4\n" +
" The assertion does not have a matching signature for:\n" +
" <null> not to be within <number> <number>\n" +
" did you mean:\n" +
" <number> [not] to be within <number> <number>\n" +
" <string> [not] to be within <string> <string>"
);
});

it('throws with the correct error message when the end points are strings', function () {
@@ -241,9 +241,9 @@ describe('to call the callback assertion', function () {
setTimeout(cb, 0);
}, 'to call the callback with error', new Error('bla'));
}, 'to error',
"expected function (cb) { setTimeout(cb, 0); }\n" +
"to call the callback with error Error('bla')"
);
"expected function (cb) { setTimeout(cb, 0); }\n" +
"to call the callback with error Error('bla')"
);
});
});

@@ -262,8 +262,8 @@ describe('to call the callback assertion', function () {
setTimeout(cb, 0);
}, 'to call the callback with error');
}, 'to error',
"expected function (cb) { setTimeout(cb, 0); } to call the callback with error"
);
"expected function (cb) { setTimeout(cb, 0); } to call the callback with error"
);
});
});
});
@@ -277,15 +277,18 @@ describe('to call the callback assertion', function () {
}, 0);
}, 'to call the callback without error', new Error('bla'));
}, 'to throw',
"expected\n" +
"function (cb) {\n" +
" setTimeout(function () {\n" +
" cb(new Error('bla'));\n" +
" }, 0);\n" +
"}\n" +
"to call the callback without error Error('bla')\n" +
" No matching assertion, did you mean:\n" +
" <function> to call the callback without error");
"expected\n" +
"function (cb) {\n" +
" setTimeout(function () {\n" +
" cb(new Error('bla'));\n" +
" }, 0);\n" +
"}\n" +
"to call the callback without error Error('bla')\n" +
" The assertion does not have a matching signature for:\n" +
" <function> to call the callback without error <Error>\n" +
" did you mean:\n" +
" <function> to call the callback without error"
);
});

it('should succeed', function () {
@@ -22,10 +22,13 @@ describe('to contain assertion', function () {
expect(function () {
expect(null, 'not to contain', 'world');
}, 'to throw',
"expected null not to contain 'world'\n" +
" No matching assertion, did you mean:\n" +
" <array-like> [not] to contain <any+>\n" +
" <string> [not] to contain <string+>");
"expected null not to contain 'world'\n" +
" The assertion does not have a matching signature for:\n" +
" <null> not to contain <string>\n" +
" did you mean:\n" +
" <array-like> [not] to contain <any+>\n" +
" <string> [not] to contain <string+>"
);

expect(function () {
expect('hello world', 'to contain', 'foo');
@@ -51,10 +54,13 @@ describe('to contain assertion', function () {
expect(function () {
expect(1, 'to contain', 1);
}, 'to throw exception',
"expected 1 to contain 1\n" +
" No matching assertion, did you mean:\n" +
" <array-like> [not] to contain <any+>\n" +
" <string> [not] to contain <string+>");
"expected 1 to contain 1\n" +
" The assertion does not have a matching signature for:\n" +
" <number> to contain <number>\n" +
" did you mean:\n" +
" <array-like> [not] to contain <any+>\n" +
" <string> [not] to contain <string+>"
);
});

it('produces a diff showing full and partial matches for each needle when the assertion fails', function () {

0 comments on commit 96f5f7c

Please sign in to comment.
You can’t perform that action at this time.