Travis CI build procs, TypeScript catching error before Mocha

This isn’t a TypeScript (tsx) compiler issue so much as it it Travis’s problem.

In my package I have a function completeRound which takes a number as its first argument, then 3 optional arguments, and because I’ve written it in TypeScript I tell it that it needs to have a number passed in as the first argument:

function completeRound( number: number, rounding = 1, direction = 'closest', offset = 0 ): number {
  let n: number = +number,
      r: number = Math.abs(+rounding),
      d: string = direction,
      o: number = +offset;

  if (typeof n !== 'number') {
    throw new TypeError('You need to round a number!');
  }

  // Rest of the code goes here
}

It all works fine, the only trouble is when it comes to testing, which is obviously the whole point of Travis:

import completeRound from '../src/completeRound';
import { expect } from 'chai';
import 'mocha';

const expectedResults = [
  {
    testVal : {
      number    : 3.5,
      rounding  : 1,
      direction : 'down'
    },
    eR      : 3
  },
  // 40-something different tests, all passing fine
];

expectedResults.map(t => describe(`completeRound(${t.testVal.number}, ${t.testVal.rounding}, '${t.testVal.direction}', ${t.testVal.offset})`,() => {
  it(`should return ${t.eR}`, () => {
    const result = completeRound(t.testVal.number,t.testVal.rounding,t.testVal.direction,t.testVal.offset);
    expect(result).to.equal(t.eR);
  });
})); // For testing results where it shouldn't throw an error, or throw a TypeError

/* This one is the problem line */
expect(() => completeRound([5])).to.throw(TypeError, /a number/);
/* ---------------------------- */

expect(() => completeRound(5,1,'arriba')).to.throw(Error, /valid rounding direction/);

So I’m passing it an array instead of a number, where I want JavaScript to throw the TypeError. Obviously I want people using this either in JavaScript or in TypeScript to be equally covered. Plus I’m after that sweet 100% figure in my coverage report. BUT , from the below report in Travis, we can see that the TypeScript compiler is getting there first and throwing a compilation error.

TSError: ⨯ Unable to compile TypeScript:

dev/test/completeRound.spec.ts:414:28 - error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'number'.

414 expect(() => completeRound([5])).to.throw(TypeError, /a number/);

I don’t see a way that I can test the compiled code because that means, well, compiling it, I’m using webpack to compile thought about using Babel but no point, it which straightaway put it in my ./dist folder, browserifies it and everything else, so I can’t see how to import from that, and I don’t really want a 2-step process where I compile it then bundle it.

I guess the short version is, I want to test JavaScript error throwing for an error where TypeScript would catch it automatically, but JavaScript wouldn’t.

Any help appreciated, I’ve seen a gist on this as well, no help.

I see two problems reading your TypeScript code right off the bat,

Firstly, at function completeRound(), you are using unary plus (n = +number), which means n always has type number (AFAIK). You need check “number” (the first function parameter) first. Or you can use isNaN() to check, if you still want to check it later. Example (simplified version):

function completeRound(number: number): number|TypeError {
  // Check the type of the first argument.
  if (typeof number !== 'number') {
    throw new TypeError('You need to round a number!');
  }
  // Before assign it.
  const n: number = +number;
  // For example if first parameter is function, n still has type number, but NaN.
  if (Number.isNaN(n)) {
    throw new TypeError('You need to round a number!');
  }
  // Rest of the code goes here
  return n;
}

You can define unknown and then run a type assertion, for example:

// Use unknown testVar.
const testVar:unknown = [5];
// Do type assertion on testVar.
expect(() => completeRound(testVar as number)).to.throw(TypeError, /a number/);
// Try again with function.
const testVarAgain: unknown = () => false;
expect(() => completeRound(testVarAgain as number)).to.throw(TypeError, /a number/);

This should work, let me know I’ll gladly continue to help.

1 Like

thanks @montana, it was type assertion, re ran build with my build.sh worked fine