Tomasz Waszczyk
Tomasz Waszczyk

Reputation: 3159

!! in Jest test

I have those two following test:

it('should render w/o crashing', () => {
  const onExport = jest.fn();
  const ID = 123;

  const tree = renderer.create(
    <I18nextProvider i18n={i18n}>
      <ExportButton id={ID} onExport={onExport} />
    </I18nextProvider>,
  );
  expect(tree!!.toJSON()).toMatchSnapshot();
});

and second:

it('should handle click', () => {
  const onExport = jest.fn();
  const ID = 123;

  const tree = renderer.create(
    <I18nextProvider i18n={i18n}>
      <ExportButton id={ID} onExport={onExport} />
    </I18nextProvider>,
  );
  const buttonProps = tree.root.findByType('button').props as ButtonHTMLAttributes<
    HTMLButtonElement
  >;
  buttonProps.onClick!!({} as React.MouseEvent<HTMLButtonElement, MouseEvent>);
  expect(onExport).toBeCalledTimes(1);
  expect(onExport).toBeCalledWith(ID);
});

Do you know how to improve it in order to replace !! syntax (tree!! and onClick!!) ? I guess that it is not the best possible solution, the cause of those syntax is to be sure that in that place there will not be null value.

Upvotes: 0

Views: 84

Answers (1)

Estus Flask
Estus Flask

Reputation: 222935

!! double bang is a mistake, it doesn't result in error because multiple operators are allowed but it doesn't do any good, a single ! non-null assertion operator has to be used.

In production, this is supposed to be solved with type guards in order to not cause error at compilation and runtime:

if (tree)
  expect(tree.toJSON()).toMatchSnapshot();

But in test environment it's preferable to have an error at runtime because an assertion should fail if it doesn't conform to expectations, so it's a perfect use case for ! non-null assertion:

expect(tree!.toJSON()).toMatchSnapshot();

It's possible to modify types to make some properties non-optional:

type ButtonType = ButtonHTMLAttributes<HTMLButtonElement>;
type ButtonTypeWithOnClick = ButtonType & Required<Pick<ButtonType, 'onClick'>>;

const buttonProps = tree.root.findByType('button').props as ButtonTypeWithOnClick;
buttonProps.onClick({} as React.MouseEvent<HTMLButtonElement, MouseEvent>);

But the result is verbose, it's a perfect use case for ! for one-time assertion either, also makes the intention more clear.

Upvotes: 1

Related Questions