react-from-markup icon indicating copy to clipboard operation
react-from-markup copied to clipboard

Testing utilities

Open simon360 opened this issue 7 years ago • 3 comments

Add some testing utilities.

In particular, a version of MarkupContainer that can be used by developers who are using the library in their project, would be handy.

Need to delineate clearly between development tools, and tools that are appropriate to send to production.

simon360 avatar Sep 25 '18 21:09 simon360

Having written a fair few tests for rehydrators now, some way of exporting the rehydrateChildren or having some mock function available would help a lot in the case of, for example:

  it("Should pass props through correctly on rehydration", async () => {
    const component = (
      <Component prop="my Value">
        <span>children</span>
      </Component>
    );
    const documentElement = document.createElement("div");

    documentElement.innerHTML = ReactDOMServer.renderToStaticMarkup(component);

    const rehydrateChildren = jest.fn(() => <span>rehydrated children</span>);
    const reactElement = await rehydrator(
      documentElement.childNodes[0],
      rehydrateChildren
    );

    expect(reactElement).toMatchSnapshot();
  });

In this usecase we'd prefer something more sophisticated than the jest.fn() at rehydrateChildren

willtonkin avatar Dec 04 '18 15:12 willtonkin

Hm, interesting. That's definitely worth a look. I can't think of a reason not to, at least as a testing utility.

simon360 avatar Dec 10 '18 22:12 simon360

On a second look, rehydrateChildren is exported from react-from-markup. It's just not the rehydrateChildren you know (and love). It requires a couple of extra arguments, but they're easy to fill in.

The tl;dr: in your test above, you could...

import { rehydrateChildren } from "react-from-markup";

// ...

    const reactElement = await rehydrator(
      documentElement.childNodes[0],
      children => rehydrateChildren(children, [], {})
    );

and be on your merry way. You can provide some rehydrators or options if you wish, but in the vast majority of cases, I suspect this will do.

Why this works

When react-from-markup calls a rehydrator, it does this:

  return rehydrator(
    el,
    children => rehydrateChildren(children, rehydrators, options),
    options.extra
  );

That second argument takes a 3-argument version of rehydrateChildren, and binds it to the list of rehydrators and the options that are normally provided directly to rehydrate() when the page initializes. That way, your rehydrator gets a function that it can call with a single children argument, without escaping the system.

Under the hood, rehydrateChildren is where everything happens - rehydrate (the default export) just adds a markup container search into the mix.

The nice thing about the jest.fn() method you used, though, is that it avoids accidentally testing the internals of react-from-markup, when what you really want to do is test an independent rehydrator unit. There's definitely use cases where this is useful, but most of the time, it's best to treat children as something that will just work.

simon360 avatar Dec 10 '18 23:12 simon360