Search code examples
javascriptangulartypescriptjestjsts-jest

Incorrect types for Jest test.each


So I'm using Jest#test.each to run some unit tests.

Here's the actual code:

const invalidTestCases = [
  [null, TypeError],
  [undefined, TypeError],
  [false, TypeError],
  [true, TypeError],
];

describe('normalizeNames', () => {
  describe('invalid', () => {
    test.each(invalidTestCases)('some description for (%p, %p)', (actual, expected) => {
      expect(() => normalizeNames(actual as any)).toThrowError(expected);
    });
  });

  describe('valid', () => {
    // ...
  });
});

The problem is that I'm unable to run this due to typescript errors:

Argument of type '(actual: boolean | TypeErrorConstructor | null | undefined, expected: boolean | TypeErrorConstructor | null | undefined) => void' is not assignable to parameter of type '(...args: (TypeErrorConstructor | null)[] | (TypeErrorConstructor | undefined)[] | (boolean | TypeErrorConstructor)[]) => any'.
      Types of parameters 'actual' and 'args' are incompatible.
        Type '(TypeErrorConstructor | null)[] | (TypeErrorConstructor | undefined)[] | (boolean | TypeErrorConstructor)[]' is not assignable to type '[boolean | TypeErrorConstructor | null | undefined, boolean | TypeErrorConstructor | null | undefined]'.
          Type '(TypeErrorConstructor | null)[]' is missing the following properties from type '[boolean | TypeErrorConstructor | null | undefined, boolean | TypeErrorConstructor | null | undefined]': 0, 1
           test.each(invalidTestCases)('some description for (%p, %p)', (actual, expected) => {
                                                       ~~~~~~~~~~~~~~~~~~~~~~~

I also tried to use an array of objects instead of 2d array, like this:

const invalidTestCases = [
  { actual: null, expected: TypeError },
  { actual: undefined, expected: TypeError },
  { actual: false, expected: TypeError },
  { actual: true, expected: TypeError },
];

describe('normalizeNames', () => {
  describe('invalid', () => {
    test.each(invalidTestCases)('some description for (%p, %p)', ({ actual, expected }) => {
      expect(() => normalizeNames(actual as any)).toThrowError(expected);
    });
  });

  describe('valid', () => {
    // ...
  });
});

...but doing this way, I can't get correct test description for object values.


Solution

  • I'm currently not somewhere I can test it, but adding type annotations usually fixes that error.

    So maybe try:

    type testCaseErrorTypes = null|undefined|boolean
    const invalidTestCases: [testCaseErrorTypes, typeof TypeError][] = [
      [null, TypeError],
      [undefined, TypeError],
      [false, TypeError],
      [true, TypeError],
    ];
    test.each(invalidTestCases)('some description for (%p, %p)', (actual, expected) => { … }
    

    This should transform invalidTestCases from a (testCaseErrorTypes|TypeError)[][] into the correct type [testCaseErrorTypes, TypeError][].