vadimdemedes/ink-testing-library

`act` equivalent or flush effects on render

Open

#3 opened on Mar 17, 2019

View on GitHub
 (13 comments) (8 reactions) (0 assignees)TypeScript (152 stars) (22 forks)user submission
enhancementhelp wanted

Description

Testing a component with hooks is a bit of an issue currently. I have this as an example component that renders & ends the application:

export const Cancelled = () => {
  const { exit } = useContext(AppContext);

  useEffect(() => {
    exit();
  }, [exit]);

  return <Box>Cancelled!</Box>;
};

And I'm testing it like this:

it('should render and exit', () => {
    const exit = sinon.spy();
    const { lastFrame, unmount } = render(
        <AppContext.Provider value={{ exit }}>
          <Cancelled />
        </AppContext.Provider>
    );

    expect(lastFrame()).to.matchSnapshot();
    expect(exit.calledOnce).to.equal(true);

    unmount();
});

The problem is the effect doesn't run by the time the render completes. I have to wrap the check around exit.calledOnce in a setTimeout. An act equivalent would allow use to write something like this:

it('should render and exit', () => {
    let lastFrame, unmount;
    const exit = sinon.spy();
    act(() => {
        ({ lastFrame, unmount } = render(
            <AppContext.Provider value={{ exit }}>
              <Cancelled />
            </AppContext.Provider>
        ));
    });

    expect(lastFrame()).to.matchSnapshot();
    expect(exit.calledOnce).to.equal(true);

    unmount();
});

and we'd know the effects would have been flushed by the time we check exit.calledOnce.

Alternatively, this version of render could flush effects immediately, rather than using the scheduler, which uses setTimeout.

Contributor guide