Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MemoryRouterProvider url property does not work properly #108

Open
SalahAdDin opened this issue Sep 27, 2023 · 3 comments
Open

MemoryRouterProvider url property does not work properly #108

SalahAdDin opened this issue Sep 27, 2023 · 3 comments

Comments

@SalahAdDin
Copy link

I'm trying to text links with this package and I am getting inconsistent behavior.

I defined a custom render as follows:

  const mockPath = "/streaming";

  const mockItem = {
    label: "Live",
    path: mockPath,
    //decorator: "streaming-status",
  };

const renderWithRouter = (ui: React.ReactElement, { route = "/" } = {}) => {
  const wrapper = ({ children }: { children: React.ReactNode }) => (
    <MemoryRouterProvider url={route}>{children}</MemoryRouterProvider>
  );
  return {
    user: userEvent.setup(),
    ...render(ui, { wrapper }),
  };
};

And I'm using it on my test like this:

  const setup = () => {
    const view = renderWithRouter(
      <Navbar>
        <HeaderItemBase {...mockItem} />
      </Navbar>,
      { route: mockItem.path }
    );

    return view;
  };


  it("should have blue text color when route is same with path", async () => {
    const view = setup();
    expect(view).toBeTruthy();

    const { user } = view;

    const link = screen.getByRole("link", { name: mockItem.label });

    await user.click(link);

    console.log("Current Path", mockRouter.asPath);
    expect(mockRouter.asPath).toStrictEqual(mockPath);

    /** TODO
     * `next/navigation` is not fully suported on the mocking library yet.
     * https://github.com/scottrippey/next-router-mock/issues/67
     * expect(link).toHaveClass("text-primary-400");
     *  */
  });

Logging the router path we get:

17:32:15 | header item base > should have white text color when route is different to path | stdout

This is the route /streaming
Current Path /

17:32:15 | header item base > should have blue text color when route is same with path | stdout

This is the route /streaming
Current Path /

17:32:16 | header item base > should have blue text color when route is same with path | stdout

Current Path after Click /

Yeah, it should be "Current Path /streaming".

Also, after clicking on the button, it should navigate easily, but it seems the route is always overwritten to be the given one and it does not change.

When using it without url property it works well, and navigates correctly.

It seems I got the property wrong, it should work as an initial route, right? Could you write an example of writing it as a provider with options using testing library?

@kotarella1110
Copy link

kotarella1110 commented Sep 29, 2023

I've encountered the same issue before as well.
Back then, I investigated the code, and it appears that this is probably not a bug but likely by design.
The reason for this specification is unclear, but as you can see in the following code, when you pass the url prop to MemoryRouterProvider, it's implemented to replace the singleton router with an isolate router.

if (typeof url !== "undefined") {
// If the `url` was specified, we'll use an "isolated router" instead of the singleton.
return new MemoryRouter(url, async);
}

To resolve this issue, you can create a wrapper for MemoryRouterProvider. Set the url passed in via props using setCurrentUrl as shown below and pass the remaining props other than url to MemoryRouterProvider:

import singletonRouter from 'next-router-mock';
import { MemoryRouterProvider } from 'next-router-mock/MemoryRouterProvider';
import type { MemoryRouterProviderProps } from 'next-router-mock/dist/MemoryRouterProvider/MemoryRouterProvider';

const SingletonRouterProvider = ({ url, ...rest }: MemoryRouterProviderProps) => {
  useEffect(() => {
    if (!url) {
      return;
    }
    singletonRouter.setCurrentUrl(url);
  }, [url]);

  return <MemoryRouterProvider {...rest} />;
};

const renderWithRouter = (ui: React.ReactElement, { route = "/" } = {}) => {
  const wrapper = ({ children }: { children: React.ReactNode }) => (
    <SingletonRouterProvider url={route}>{children}</SingletonRouterProvider>
  );
  return {
    user: userEvent.setup(),
    ...render(ui, { wrapper }),
  };
};

@kotarella1110
Copy link

kotarella1110 commented Sep 29, 2023

@scottrippey

The reason for this specification is unclear, but as you can see in the following code, when you pass the url prop to MemoryRouterProvider, it's implemented to replace the singleton router with an isolate router.

It appears that this implementation was added in the following PR, but could you please explain the reason behind it?

#66

@SalahAdDin
Copy link
Author

@scottrippey Are you here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants