user3142695
user3142695

Reputation: 17332

jest mock call object is possibly undefined

This is a simple test using a mocked function. But I do get an ts error for the mock call Object is possibly 'undefined'.ts(2532). I don't see how to get rid of this error. This is the structure of the call object, so I think I handle it correctly... but obviously not as expected by ts.

import { render, fireEvent } from '@testing-library/react'

const mockSetCheckbox = jest.fn(() => Promise.resolve())

test('should select checkbox', () => {
  // ...
  userEvent.click(checkbox)
  expect(mockSetCheckbox.mock.calls[0][0].variables.input.checkbox).toBe(true)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   Object is possibly 'undefined'.ts(2532)
})

Upvotes: 2

Views: 5036

Answers (2)

Teneff
Teneff

Reputation: 32158

I'd suggest you to change your test to use .toHaveBeenCalled()

  test("should select checkbox", () => {
    userEvent.click(checkbox)

    expect(mockSetCheckbox).toHaveBeenCalledWith(
      expect.objectContaining({
        variables: expect.objectContaining({
          input: expect.objectContaining({
            checkbox: true,
          }),
        }),
      })
    );
  });

which would assert the same, but you'll get much more understandable error if the implementation changes in a way that the function isn't called.

When using .toHaveBeenCalled() will look like this:

    expect(jest.fn()).toHaveBeenCalledWith(...expected)

    Expected: ObjectContaining {"variables": ObjectContaining {"input": ObjectContaining {"checkbox": true}}}

    Number of calls: 0

working example

Upvotes: 2

oooyaya
oooyaya

Reputation: 1783

It's saying mockSetCheckbox.mock.calls[0][0] is possibly undefined, because you're potentially doing mockSetCheckbox.mock.undefined.variables and you cant reference undefined like that.

It's trying to help you because your type for whatever calls[0][0] is is undefined and/or something else.

Simplest fix is to just assure the checker that it's not going to be undefined by checking first. Shortcuts exist to do this more concisely if you don't want a buncha ifs.

if(mockSetCheckbox.mock.calls[0][0]) {
   expect(mockSetCheckbox.mock.calls[0][0].variables.input.checkbox).toBe(true)
}

You might also want to make sure that your test fails if it is undefined by throwing. The above will silently fail since no expects means 'pass'. I prefer to do both by catching the problem and assuming all's well after looking for problems.

Something like:

if(mockSetCheckbox.mock.calls[0][0] === undefined) {
    throw "oh no!";
}
expect(mockSetCheckbox.mock.calls[0][0].variables.input.checkbox).toBe(true)

Other options include:

expect(mockSetCheckbox.mock.!calls[0][0].variables.checkbox).toBe(true);

// or 

expect((mockSetCheckbox.mock.calls[0][0] as Something).variables.input.checkbox).toBe(true);

// or

let val:Something = mockSetCheckbox.mock.calls[0][0];
expect(val.variables.input.checkbox).toBe(true);

... where Something is whatever type that contains that variables object (or any).

Upvotes: 1

Related Questions