Mythos
Mythos

Reputation: 1482

Jest - log parameters passed into a function called inside the test when test failed

I have a Jest test described as:

it('Full name must be >= 3 letters', () => {
    ['', 'a', 'ab', 'a ', 'a    ', '     a'].forEach((fullName) => {
      expect(() => userBuilder.build({ fullName })).toThrowError();
    });
  });

When any iteration fails, the test fails and points me to the expect line:

user › Full name must be >= 3 letters

    expect(received).toThrowError()

    Received function did not throw

      15 |     ['', 'a', 'ab', 'a ', 'a    ', '     a', 'asdf'].forEach((fullName) => {
      16 |       console.debug('testing', fullName);
    > 17 |       expect(() => userBuilder.build({ fullName })).toThrowError();
         |                                                     ^
      18 |     });
      19 |   });
      20 |

      at src/api/user/user.test.ts:17:53
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (src/api/user/user.test.ts:15:54)

which isn't very helpful since its in a loop. I need to know what parameters were passed as fullName in the iteration when expect failed.

From this SO question, I know I can use something like
test.each([...])('Full name must be >= 3 letters, testing: %s'){...
But here each iteration is considered a separate test, and I have hundreds of such iterations in tens of different tests (Full name must be <= 50 chars, Full name must contain alpha and spaces only, etc). This unnecessarily bloats my test suite printing the repetitive Full name must be >= 3 letters, testing: text over and over.

I know I can console.debug('testing', fullName) for each iteration, but it logs output for every iteration, with some added verbose around each output, and it doesn't print out with the failed message, so with multiple tests, its hard to figure out which iteration failed for which test. I don't know how to log output only when an expectation fails.

It seems like such a simple thing for a test runner to have that I'm sure I must be missing something here.

Not sure if its important but I'm using ts-jest for typescript.

Upvotes: 2

Views: 756

Answers (1)

hoangdv
hoangdv

Reputation: 16147

Use describe to group the validation rules, then use test.each or forEach to make the test.

describe('Full name must be >= 3 letters', () => {
  ['', 'a', 'ab', 'a ', 'a    ', '     a'].forEach((fullName) => {
    it(`should throw error when full name is "${fullName}"`, () => {
      expect(() => userBuilder.build({ fullName })).toThrowError();
    });
  });
});

Then, the fail message will look like this:

  Full name must be >= 3 letters
    ✓ should throw error when full name is "" (9 ms)
    ✓ should throw error when full name is "a" (1 ms)
    ✕ should throw error when full name is "ab" (1 ms)
    ✓ should throw error when full name is "a " (1 ms)
    ✓ should throw error when full name is "a    "
    ✓ should throw error when full name is "     a"

  ● Full name must be >= 3 letters › should throw error when full name is "ab"

    expect(received).toThrowError()

    Received function did not throw

      10 |   ['', 'a', 'ab', 'a ', 'a    ', '     a'].forEach((fullName) => {
      11 |     it(`should throw error when full name is "${fullName}"`, () => {
    > 12 |       expect(() => userBuilder.build({ fullName })).toThrowError();
         |                                                     ^
      13 |     });
      14 |   });
      15 | });

Upvotes: 2

Related Questions