Jasmine testing matcher for throw someObject - javascript

I have a function which throws some object in certain cases. I wrote a jasmine expect matcher with toThrow but its not working. Not sure why its failing. Any help will be appreciated.
fit("The 'toThrow' matcher is for some object", function() {
function baz(x) { // this is the function to test
if(x === 1) {
return 1;
} else {
throw {status: 515};
}
};
expect(baz(1)).toBe(1); // matched perfect.
expect(baz(2)).toThrow({status: 515}); // failing with message Error: "[object Object] thrown"
});
How to write matcher for function call baz(2)??

According to the documentation, you have to give the reference to the function to expect, not the return value of the function.
see https://jasmine.github.io/api/3.5/matchers.html#toThrow
Example
function error() {
throw 'ERROR';
}
expect(error).toThrow('ERROR')
For your case, you can wrap your function call into another function. You can directly inline the declaration of that function inside the expect argument:
expect(() => baz(2)).toThrow({status: 515});
// equivalent with
expect(function(){ baz(2) }).toThrow({status: 515});
Another way is to use .bind to attach parameters to the function without calling it.
expect(baz.bind(null, 2)).toThrow({status: 515});
// ^^^^ ^
// context first parameter

Related

Passing A Function As Argument To A Function

function say(something) {
console.log(something);
}
function exec(func, arg) {
return func(arg);
}
exec(say, "Hi, there.");
Why does this code work? I feel like it shouldn't since what is in the second function should return
say(something) (arg) {
console.log(something) ;
}
It works as it does because when you write return func(arg);, the func(arg) bit executes the function. What is returned is then the result of executing func(arg).
However, you're right that say() doesn't actually return a value, it just logs to the console within that function. The output you're seeing is the result of that log command. If you logged the returned value instead you'd see undefined as the result.
But if you'd passed a different function to exec which did return a value, then you'd need the return in exec() for it to work properly.
P.S. I'm not sure if this is part of what you're asking, but the difference between that and when you wrote exec(say, "hi there"); is that in that code, say is a reference to the "say" function. At that moment it's treated like any other variable, just the same as if you passed in a number or a string, for example.
The difference is the (), which causes the function to be executed, rather than passed as a reference.
In the question you seem to imply that you'd expect the source code of the say() function to be displayed, but this is not what it does, and also is not possible anyway.
Function say returns undefined (default value if no return keyword is used), and therefore function exec also returns undefined.
Proof:
function say(something) {
console.log(something);
}
function exec(func, arg) {
var result = func(arg);
console.log(result);
return result;
}
var result2 = exec(say, "Hi, there.");
console.log(result2);
Maybe you are looking for a closure, where exec returns a function for getting arg for the first handed over function func.
function say(something) {
console.log(something);
}
function exec(func) {
return function (arg) {
return func(arg);
};
}
exec(say)("Hi, there.");

node: using chai's expect.to.throw on a function that takes arguments

I need to call expect().to.throw() on a function that takes arguments. For example, say I have the following:
var func = function(x) {
if (x > 1) {
throw new Error()
} else {
console.log('hello')
}
}
expect(func).to.throw()
This fails, because it calls func without an argument, meaning it will never throw an error. But if I call expect(func(2)).to.throw(), I get AssertionError: expected undefined to be a function. The function gets called and the return value is passed to expect.
How can I use expect().to.throw() and give the included function arguments. Is the only way to do it with an anonymous function, like expect(() => {func(2)}).to.throw()?
This is from the chai docs:
If you need to assert that your function fn throws when passed certain arguments, then wrap a call to fn inside of another function.
expect(function () { fn(42); }).to.throw(); // Function expression
expect(() => fn(42)).to.throw(); // ES6 arrow function

Why does it matter to Mocha's `before()` whether the function passed takes parameters or not?

I have code like this in my describe: before(a).
When a looks like this:
function a() {
return chai.request(app)
...
.then(res => {
res.blah.should.blah;
return Promise.resolve();
});
}
...everything works great (it's a very quick call.)
However, when I make a take some input variables:
function a(dummy, my_var) {
return chai.request(app)
... // use my_var here
.then(res => {
res.blah.should.blah;
console.log("finished!");
return Promise.resolve();
});
}
The promise never resolves. Two observations:
finished! does get properly output (immediately)
dummy is populated.
It's populated with this:
function (err) {
if (err instanceof Error || toString.call(err) === '[object Error]') {
return done(err);
}
if (err) {
if (Object.prototype.toString.call(err) === '[object Object]') {
return done(new Error('done() invoked with non-Error: ' + JSON.stringify(err)));
}
return done(new Error('done() invoked with non-Error: ' + err));
}
if (result && utils.isPromise(result)) {
return done(new Error('Resolution method is overspecified. Specify a callback *or* return a Promise; not both.'));
}
done();
}
I don't know where that's from exactly, but I don't need it, that's why I just put it into a dummy variable.
Now I suspect that has something to do with it, but I wonder why my workaround doesn't do the trick here.
I still want to use before(a) for the default case, leaving my_var undefined. When I do actually want to pass that variable, I intended to:
before(() => {
return a('my_content');
})
That's because Mocha inspects the function you pass to before to check how many parameters are defined on it like this:
this.async = fn && fn.length;
If there's any parameter defined, then the function is deemed to be asynchronous. (Mocha also checks if it returns a promise but that's a different test.) If there's at least one parameter defined, then Mocha passes as 1st parameters a function that you are meant to call when your before callback is done doing its work. That callback (traditionally named done) is useful for code that does not use promises.
If you do not call it, then Mocha waits forever even if you return a promise.
Note that Mocha does the same with all other hooks: beforeEach, after, etc., and with the callback you pass to it.
Mocha before, after, it function accepts one parameter - callback. It should be defined and called when your test uses async functions:
db.connect is async function:
before(done => {
db.connect(done);
}
When db.connect returns a promise you shouldn't use callback and could return the promise:
before(() => {
return db.connect();
}
In your code, you call before with a function, which accepts two parameters. Mocha interprets the first parameter as callback, and tries to call it.
To prevent this issue, you need to call a function directly and pass params in it:
before(() => {
return a(dummy, my_var);
}

Jasmine - How to test errors?

THE SITUATION:
Hello guys. I am learning jasmine to test my angular app.
I have create a basic function that does multiply two numbers.
If the parameters given are not a number, the function throw an error.
I then made two very basic tests.
The first to check if the function properly multiply the numbers.
The second to check if the function properly throw an error if a string is given as parameter.
The first test pass, the second not. And i don't understand why.
THE CODE:
The function:
function Multiply( num1, num2 )
{
var result;
if (isNaN(num1) || isNaN(num2))
{
throw new Error("not a number");
}
else
{
result = num1 * num2;
return result;
}
}
The spec:
describe('The function', function ()
{
it('properly multiply two numbers', function ()
{
result = Multiply(10, 5);
expect(result).toEqual(50);
});
it('throw an error if a parameter is not a number', function ()
{
result = Multiply(10, 'aaaa');
expect(result).toThrow(new Error("not a number"));
});
});
THE OUTPUT:
2 specs, 1 failure
Spec List | Failures
The function throw an error if a parameter is not a number
Error: not a number
Error: not a number
at Multiply (http://localhost/jasmine_test/src/app.js:8:9)
If i understand properly Jasmine. Both test should pass, because in the second case the function throw the error as we expected.
THE QUESTION:
How can i test if a function properly throw an error?
EDIT:
I am trying this new code, but is still not working:
describe('The function', function ()
{
it('throw an error if a parameter is not a number', function ()
{
expect(function() { Multiply(10, 'aaaa') }).toThrowError(new Error("not a number"));
});
});
OUTPUT:
2 specs, 1 failure
Spec List | Failures
The function throw an error if a parameter is not a number
Error: Expected is not an Error, string, or RegExp.
If I understand correctly you need to pass a function into the expect(...) call.
The code you have here:
expect(result).toThrow(new Error("not a number"));
Is checking the result of Multiply, which when it works is fine, but like I said .toThrow() expects a function, I'd use an anonymous function instead, see below:
expect( function(){ Multiply(10, 'aaaa'); } ).toThrow(new Error("not a number"));
EDIT: Did a quick search and this blog post is a very detailed explanation of what I am trying to say.
You need to put the code you expect to throw an error into a function:
expect(function () {
Multiply(10, 'aaaa');
}).toThrow(Error, 'not a number');
Otherwise, when you run your assertions, the error has already been thrown outside the scope. You can see available syntax for error matching in jasmine docs
The above methods are exactly true for exceptions handled inside the methods.
When you've to test the services you can use mocking mechanism to do that.
Use the advantage of NgModule providers section to create the mocks.
In describe() block,
providers: [{ provide: APIService, useValue: { api: { filterTaskDetails: () => throwError('Error') }}}]
throwError to be imported from rxjs.
In expect() block test it as,
spyOn(component['toaster'], 'showError');
/** add respected it() blocks**/
expect(component['toaster'].showError).toHaveBeenCalledTimes(1);

Supplied parameters do not match any signature of call target in wrapper method - Typescript

Ok I'm guessing I'm missing something really simple on this one.
Lets say I have multiple methods that repeat a lot of the same things like this:
public getDepartments(id: number): ng.IPromise<IDepartmentViewModel[]> {
this.common.loadStart();
return this.unitOfWork.teamRepository.getDepartmentsForTeam(id).then((response: IDepartmentViewModel[]) => {
this.common.loadComplete();
return response;
}).catch((error) => {
this.common.loadReset();
return error;
});
}
Tons of boilerplate for a single call to this.unitOfWork.teamRepository.getDepartmentsForTeam(id)
so I wanted to make a generic wrapper for the boilerplate such as:
private internalCall<T>(method: () => ng.IPromise<T>): ng.IPromise<T> {
this.common.loadStart();
return method().then((response: T) => {
this.common.loadComplete();
return response;
}).catch((error) => {
this.common.loadReset();
return error;
});
}
Which I could then call like:
public getDepartments(id: number): ng.IPromise<IDepartmentViewModel[]> {
return this.internalCall<IDepartmentViewModel[]>(this.unitOfWork.teamRepository.getDepartmentsForTeam(id));
But I get the following error:
Supplied parameters do not match any signature of call target:
Type '() => ng.IPromise<IDepartmentViewModel[]>' requires a call signature, but type 'ng.IPromise<IDepartmentViewModel[]>' lacks one.
What is the right way to pass my method into the other to call it with supplied parameters?
This is a common mistake: you cannot pass a method function as a regular function since it requires the instance for the class as context. The solution is to use a closure:
function foo( func: () => any ) {
}
class A {
method() : any {
}
}
var instanceOfA = new A;
// Error: you need a closure to preserve the reference to instanceOfA
foo( instanceOfA.method );
// Correct: the closure preserves the binding to instanceOfA
foo( () => instanceOfA.method() );
For a more complete example you can also see my snippet published here: http://www.snip2code.com/Snippet/28601/Typescript--passing-a-class-member-funct
I needed to wrap the call so it was wrapped in a closure like so:
public getDepartments(id: number): ng.IPromise<IDepartmentViewModel[]> {
return this.internalCall<IDepartmentViewModel[]>(
() => { return this.unitOfWork.teamRepository.getDepartmentsForTeam(id); } // Wrapping here too
);
Only for documentation - I got this error when I accidentally called the wrong (existing) function with wrong parameters. Had to look into the errorous line in the packaged file .tmp/bla/bla/bla.ts to see the error.
Try replacing your fat arrow in to normal function. This will resolve the issue.
() => ng.IPromise
to
function(){ng.IPromise .....}
In my case a simpler trick allowed me to dodge the error. The call (or trigger) of a function is due to it parentheses, so :
class MyClass {
foo: any;
firstMethod() {
this.foo = this.secondMethod;
this.foo();
}
secondMethod() {
}
}
In a more generic answer, the error "Supplied parameters do not match any signature of call target in wrapper method - Typescript" points out that you are calling a function with the wrong parameters.
example() receives two parameters per definition, but you are passing only one:
example('param1') // wrong
example('param1','param2') // OK!

Categories

Resources