Mocha / Chai expect.to.throw not catching thrown errors

前端 未结 7 1842
傲寒
傲寒 2020-11-22 07:20

I\'m having issues getting Chai\'s expect.to.throw to work in a test for my node.js app. The test keeps failing on the thrown error, but If I wrap the test case

相关标签:
7条回答
  • 2020-11-22 08:02

    I have found a nice way around it:

    // The test, BDD style
    it ("unsupported site", () => {
        The.function(myFunc)
        .with.arguments({url:"https://www.ebay.com/"})
        .should.throw(/unsupported/);
    });
    
    
    // The function that does the magic: (lang:TypeScript)
    export const The = {
        'function': (func:Function) => ({
            'with': ({
                'arguments': function (...args:any) {
                    return () => func(...args);
                }
            })
        })
    };
    

    It's much more readable then my old version:

    it ("unsupported site", () => {
        const args = {url:"https://www.ebay.com/"}; //Arrange
        function check_unsupported_site() { myFunc(args) } //Act
        check_unsupported_site.should.throw(/unsupported/) //Assert
    });
    
    0 讨论(0)
  • 2020-11-22 08:06

    And if you are already using ES6/ES2015 then you can also use an arrow function. It is basically the same as using a normal anonymous function but shorter.

    expect(() => model.get('z')).to.throw('Property does not exist in model schema.');
    
    0 讨论(0)
  • 2020-11-22 08:09

    You have to pass a function to expect. Like this:

    expect(model.get.bind(model, 'z')).to.throw('Property does not exist in model schema.');
    expect(model.get.bind(model, 'z')).to.throw(new Error('Property does not exist in model schema.'));
    

    The way you are doing it, you are passing to expect the result of calling model.get('z'). But to test whether something is thrown, you have to pass a function to expect, which expect will call itself. The bind method used above creates a new function which when called will call model.get with this set to the value of model and the first argument set to 'z'.

    A good explanation of bind can be found here.

    0 讨论(0)
  • 2020-11-22 08:09

    One other possible implementation, more cumbersome than the .bind() solution, but one that helps to make the point that expect() requires a function that provides a this context to the covered function, you can use a call(), e.g.,

    expect(function() {model.get.call(model, 'z');}).to.throw('...');

    0 讨论(0)
  • 2020-11-22 08:11

    As this answer says, you can also just wrap your code in an anonymous function like this:

    expect(function(){
        model.get('z');
    }).to.throw('Property does not exist in model schema.');
    
    0 讨论(0)
  • 2020-11-22 08:18

    examples from doc... ;)

    because you rely on this context:

    • which is lost when the function is invoked by .throw
    • there’s no way for it to know what this is supposed to be

    you have to use one of these options:

    • wrap the method or function call inside of another function
    • bind the context

      // wrap the method or function call inside of another function
      expect(function () { cat.meow(); }).to.throw();  // Function expression
      expect(() => cat.meow()).to.throw();             // ES6 arrow function
      
      // bind the context
      expect(cat.meow.bind(cat)).to.throw();           // Bind
      
    0 讨论(0)
提交回复
热议问题