Search code examples
node.jstypescriptmocha.jschaichai-as-promised

chai-as-promised not failing typescript tests


I'm trying to use chai-as-promised in my Mocha test for some typescript code. I can't quite get the syntax right. So I setup a minimal reproducer:

index.ts

// Sample promise that resolves on red, fails on other values
export const getRedColor = async (color: string): Promise<string> =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      if (color === 'red') {
        resolve(color);
      } else {
        reject(new Error(`You picked ${color}, should be red`));
      }
    }, 1000);
  });

index.spec.ts

First I used async/await to write a test as control, the first 2 pass, the second two are designed to fail.

import * as chai from 'chai';
import { expect } from 'chai';
import 'mocha';
import chaiAsPromised from 'chai-as-promised';
import { getRedColor, isRedColor } from '../src/index';
import { describe } from 'mocha';

describe('Testing failing promises with async/await', () => {
  it('should pass on red', async () => {
    let result = await getRedColor('red');
    expect(result).to.equal('red');
  });

  it('should throw on blue', async () => {
    try {
      let result = await getRedColor('blue');
      expect.fail('SHould not succeed');
    } catch (e: any) {
      expect(e.message).to.equal('You picked blue, should be red');
    }
  });

  // Deliberately failing
  it('should fail on blue', async () => {
    let result = await getRedColor('blue');
    expect(result).to.equal('blue');
  });

  // Deliberately failing
  it('should throw on red', async () => {
    try {
      let result = await getRedColor('red');
      expect.fail('Should not succeed');
    } catch (e: any) {
      expect(e.message).to.equal('You picked red, should be red');
    }
  });
});

then (in the same file) the same (2 pass/2fail) in chai syntax

index.spec.ts (continued)

describe('Testing failing promises chai-as-promised', () => {
  it('should pass on red', () => {
    let result = getRedColor('red');
    expect(result).to.eventually.equal('red');
  });

  it('should throw on blue', () => {
    let result = getRedColor('blue');
    expect(result).to.eventually.rejectedWith('You picked blue, should be red');
  });

  // Deliberately failing
  it('should fail expecting rejection on red', () => {
    let result = getRedColor('red');
    expect(result).to.eventually.rejected;
  });

  // Deliberately failing
  it('should fail resulting in blue', () => {
    let result = getRedColor('blue');
    expect(result).to.eventually.eql('blue');
  });
});

All test pass - so I must do something wrong. I also checked the documentation which suggests to alter the test to

  // Deliberately failing
  it('should fail resulting in blue', () => {
    let result = getRedColor('blue');
    return result.to.eventually.eql('blue');
  });

but that leads to an Error

TypeError: Cannot read properties of undefined (reading 'eventually')

What do I miss?


Solution

  • I was close. Missing was either a return statement or a call to notify. These is the working code in return and notify() flavor:

    describe('Testing failing promises chai-as-promised', () => {
      it('should pass on red', () => {
        let result = getRedColor('red');
        return expect(result).to.eventually.equal('red');
      });
    
      it('should throw on blue', () => {
        let result = getRedColor('blue');
        return expect(result).to.eventually.rejectedWith('You picked blue, should be red');
      });
    
    describe('Testing failing promises chai-as-promised', () => {
      it('should pass on red', (done) => {
        let result = getRedColor('red');
        expect(result).to.eventually.equal('red').notify(done);
      });
    
      it('should throw on blue', (done) => {
        let result = getRedColor('blue');
        expect(result).to.eventually.rejectedWith('You picked blue, should be red').notify(done);
      });
    });
    

    Hope that helps someone struggling with the same details