0

I have a test case which looks like this:

it("should throw when the template file does not exist", async (): Promise<void> => {
    await expect(new UpdateReadmeCommandlet().invoke()).to.be.rejectedWith(Error);
});

And the corresponding invoke method is the following:

public async invoke(): Promise<void> {
    fs.readFile(this.templatePath, (outerError: NodeJS.ErrnoException, data: Buffer): void => {
        if (outerError !== null) {
            throw new Error(`FileNotFoundException: Cannot find file \`${this.templatePath}'.`);
        }
    });
}

This test is setup so that this error is thrown. When running mocha I am getting some really awkward error messages and everything is all over place which is most likely due to the async calls. The error message I get is AssertionError: expected promise to be rejected with 'Error' but it was fulfilled with undefined.

My test is written based on this answer. Surprisingly enough, when I copy the fails method it works as described in the post. Exchanging the throw directive with my call to invoke causes the issues. So I assume I my invoke method has to work differently.

I still cannot figure out what is actually wrong and how I can rewrite my test s.t. doesn't interfere with other tests and that checks my assertion correctly.

Christian Ivicevic
  • 10,071
  • 7
  • 39
  • 74

1 Answers1

1

A throw in the callback passed to fs.readFile will not reject the promise returned by public async invoke(): Promise<void> {

Fix

Wrap fs.readFile to be async aware and use that the cascade the promise rejection.

public async invoke(): Promise<void> {
    return new Promise<void>((res, rej) => {
    fs.readFile(this.templatePath, (outerError: NodeJS.ErrnoException, data: Buffer): void => {
        if (outerError !== null) {
            rej(new Error(`FileNotFoundException: Cannot find file \`${this.templatePath}'.`));
        }
    });

    })
}
basarat
  • 261,912
  • 58
  • 460
  • 511
  • Even better would be `require('util').promisify(fs.readFile)` so that you don't even have to write it using the callback-style API. – Patrick Roberts May 21 '18 at 01:11
  • @PatrickRoberts Would you mind quickly showing a snippet what your alternative would look like? – Christian Ivicevic May 21 '18 at 01:20
  • @ChristianIvicevic I'm not sure how it would look in TypeScript, but in JavaScript (Node.js) you'd do something like ``const readFile = require('util').promisify(fs.readFile); ... async invoke () { return readFile(this.templatePath).then(data => data, outerError => { throw new Error(`FileNotFoundException: cannot find file \`${this.templatePath}'.`); }); }`` – Patrick Roberts May 21 '18 at 02:05