Terrance
Terrance

Reputation: 11872

Chai expect to throw Exception not matching same exception using Typescript

Ello all, So I've been trying to write a unit test that expects a certain type of exception. I had a function that threw that exception but, I still got a failing test. To troubleshoot, I've gone as far as just trying to throw the same exception and still get a fail. I can make it pass with comparing the message but, that seems like a terrible idea.

How should I be handling testing for a matching custom exception?

Class code

export class EventEntity {

    comments : Array<string> = new Array<string>();

    constructor() {}

    public addComment(comment : string) {
        this.comments.push(comment);
    }

    public getCommentCount() : number {
        return this.comments.length;
    }

    public getCommentByOrder(commentNumber : number) : string {
        console.log(`getCommentByOrder with arg:${commentNumber}`);            

        let offset = 1;
        try {
            let result = this.comments[commentNumber - offset];
            return result;
        } catch (err){
                console.log(`getCommentByOrder:Error: ${err.toString()}`);
            console.log(`err: with arg:${commentNumber}`);
            if(err instanceof RangeError){
                throw new CommentNotFoundException();
            }
            throw err;
        }
    }
}

MyException

export class CommentNotFoundException extends Error {
    constructor(m?:string) 
    {
        let message : string  = m?m:"Comment number not found in event's comments.";        
        super(message);
        Object.setPrototypeOf(this, CommentNotFoundException.prototype);
    }
}

Failing Test

@test shouldThrowIfCommentNumberIsGreaterThanTotalNumberOfComments() {
    let testEvent = new EventEntity();
    let expectedException = new CommentNotFoundException();
    //expect(testEvent.getCommentByOrder(5)).to.throw(expectedException);
    expect(()=> {
        throw new CommentNotFoundException();
    }).to.throw(new CommentNotFoundException());
}

update

Okay, I revised. This works as expected. The exception wasn't being picked up in the form:

expect(testEvent.getCommentByOrder(5)).to.throw(CommentNotFoundException);

but this does:

expect(()=>{
        testEvent.getCommentByOrder(5);
}).to.throw(CommentNotFoundException);

Here is the listing with updated code:

method

public getCommentByOrder(commentNumber : number) : string {
    let offset = 1;
    let result = this.comments[commentNumber - offset];
    if (!result) {
        throw new CommentNotFoundException();
    } else {
        return result;
    }
}

test

@test shouldThrowIfCommentNumberIsGreaterThanTotalNumberOfComments() {
    let testEvent = new EventEntity();
    expect(()=>{
            testEvent.getCommentByOrder(5);
    }).to.throw(CommentNotFoundException);
}

That's a win, Thanks!

Upvotes: 2

Views: 2034

Answers (1)

Louis
Louis

Reputation: 151401

You are passing an error instance to the .throw(...) method. You need to pass a constructor instead. And what you pass to expect must be a function that expect will call. Your commented out line should be edited to:

expect(() => testEvent.getCommentByOrder(5)).to.throw(CommentNotFoundException);

You can pass an instance to the method but then the assertion will pass if and only if the instance raised by the function being tested and the instance you pass to .throw(...) satisfy a comparison with ===. In other words, the two values must be the exact same JS object. When testing real code (rather than trivial examples), it is almost never the case that you can get the error instance before the error is raised so passing an instance is something you normally cannot do.

Upvotes: 4

Related Questions