solidjs / solid-router

A universal router for Solid inspired by Ember and React Router
MIT License
1.11k stars 138 forks source link

Wrapping Router aware components in test #366

Closed uhon closed 5 months ago

uhon commented 5 months ago

Describe the bug

Solidjs components can not be tested when they rely on Router.

Wrapping a Component with any kind of <Router> from solidjs-router, does not work during test.

This example Fails with the following Error: Make sure your app is wrapped in a <Router />:

render(() => <Counter />, {
      wrapper: (props) => (
        <Router>
          <RouteAwareWrapper>{props.children}</RouteAwareWrapper>
        </Router>
      ),
    });

This works without erros, but the resulting baseElement is empty (nothing is rendered):

render(() => <Counter />, {
      wrapper: (props) => (
        <Router
          root={(props) => (
            <RouteAwareWrapper>{props.children}</RouteAwareWrapper>
          )}
        >
          <Route>{props.children}</Route>
        </Router>
      ),
    });

I also tested MemoryRouter and StaticRouter but neither of them worked. Test suite can be found below.

Steps to Reproduce the Bug or Issue

Reproducible here: https://stackblitz.com/edit/node-dbbmnk?file=test%2Fsuite.test.tsx

Expected behavior

At least one version of the now failing tests should work

Platform

ryansolid commented 5 months ago

The children of <Router> can only be <Route> components.. Children of <Route> components can only be <Route> components. So most of the examples aren't right.

const { queryByRole } = render(() => <Counter />, {
      wrapper: (props) => {
        return (
          <Router
            root={(props) => (
              <RouteAwareWrapper>{props.children}</RouteAwareWrapper>
            )}
          >
            <Route path="/" component={() => <>{props.children}</>} />
          </Router>
        );
      },
    });

I believe is the closest to being correct. I'm gathering props.children is a getter that executes the component so it should be inside a page component.

You could also do this I suppose:

const { queryByRole } = render(() => <Counter />, {
      wrapper: (props) => {
        return (
          <Router>
            <Route path="/" component={() => <RouteAwareWrapper>{props.children}</RouteAwareWrapper>} />
          </Router>
        );
      },
    });