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

Integration Testing using createRemixStub: useLoaderData must be used within a data router #10379

Open
Stephnn0 opened this issue Jan 1, 2025 · 0 comments

Comments

@Stephnn0
Copy link

Stephnn0 commented Jan 1, 2025

Reproduction

We have a shopify remix app where we are implementing integration tests to mock behavior from backend to frontend.

I'm using createRemixStub to mock the loader/actions in my routes and I'm also using using Vitest for testing.

We are getting this error when running the test:

Error: useLoaderData must be used within a data router. See https://reactrouter.com/routers/picking-a-router.

As an alternative we are using createMemoryRouter and RouterProvider to have access to useLoaderData, etc.

import { expect, test, vi } from 'vitest';
import Occasions, { loader } from '~/routes/app.occasions._index/route';
import { render, screen } from '../utils/config/testing.libary.polaris';

import { RouterProvider, createMemoryRouter } from 'react-router-dom';

vi.mock('@shopify/app-bridge-react', async () => {
  const actual = await import('@shopify/app-bridge-react');
  return {
    ...actual,
    Modal: vi.fn(),
    TitleBar: vi.fn(),
    useAppBridge: vi.fn(() => ({})),
  };
});

vi.mock('@shopify/shopify-app-remix/server', async () => {
  const actual = await import('@shopify/shopify-app-remix/server');
  const SHOPIFY_API_KEY = 'test-api-key';
  const SHOPIFY_API_SECRET = 'test-api-secret';
  const SHOPIFY_APP_URL = 'https://test-app-url.com';

  return {
    ...actual,
    shopifyApp: vi.fn(() => ({
      config: {
        shopifyApiKey: SHOPIFY_API_KEY,
        apiKey: SHOPIFY_API_KEY,
        apiSecretKey: SHOPIFY_API_SECRET,
        appUrl: SHOPIFY_APP_URL,
        sessionStorage: {
          storeSession: vi.fn(),
          loadSession: vi.fn(),
          deleteSession: vi.fn(),
        },
      },
        })),
      },
    })),
  };
});


test('Can load Index Route', async () => {
  const App = createRemixStub([
    {
      path: '/app/occassions',
      Component: Occasions,
      loader: loader,
    },
  ]);

  render(<App initialEntries={['/app/occassions']} />);

  const occasionText = await screen.findByText('Generic Rubber Sausages');

  expect(occasionText).not.toBeNull();

  screen.debug();
});


System Info

"@remix-run/dev": "2.11.2",
    "@remix-run/node": "2.11.2",
    "@remix-run/react": "2.11.2",
    "@remix-run/serve": "2.11.2",
    "@remix-run/eslint-config": "2.11.2",
    "@remix-run/testing": "^2.11.2",

Used Package Manager

npm

Expected Behavior

createRemixStub should mock the loader/actions, allow us to access useLoaderData, useActionData data and run the test without any errors. Again we are able to accomplish this with createMemoryRouter but we would like to use createRemixStub

Actual Behavior

Ignored nodes: comments, script, style
<body>
  <div>
    <h2>
      Unexpected Application Error!
    </h2>
    <h3
      style="font-style: italic;"
    >
      useLoaderData must be used within a data router.  See https://reactrouter.com/routers/picking-a-router.
    </h3>
    <pre
      style="padding: 0.5rem; background-color: rgba(200, 200, 200, 0.5);"
    >
      Error: useLoaderData must be used within a data router.  See https://reactrouter.com/routers/picking-a-router.
    at Object.invariant [as UNSAFE_invariant] (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/@remix-run/router/history.ts:494:11)
    at useDataRouterState (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-router/lib/hooks.tsx:876:3)
    at Object.useLoaderData (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-router/lib/hooks.tsx:947:15)
    at Proxy.useLoaderData (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/@remix-run/react/dist/components.js:760:25)
    at Occasions (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/app/routes/app.occasions._index/route.tsx:26:57)
    at renderWithHooks (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-dom/cjs/react-dom.development.js:15486:18)
    at mountIndeterminateComponent (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-dom/cjs/react-dom.development.js:20103:13)
    at beginWork (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-dom/cjs/react-dom.development.js:21626:16)
    at beginWork$1 (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-dom/cjs/react-dom.development.js:27465:14)
    at performUnitOfWork (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-dom/cjs/react-dom.development.js:26599:12)
    </pre>
    <p>
      💿 Hey developer 👋
    </p>
    <p>
      You can provide a way better UX than this when your app throws errors by providing your own 
      <code
        style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
      >
        ErrorBoundary
      </code>
       or
       
      <code
        style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
      >
        errorElement
      </code>
       prop on your route.
    </p>
    <div
      id="PolarisPortalsContainer"
    />
  </div>
</body>

Ignored nodes: comments, script, style
<body>
  <div>
    <h2>
      Unexpected Application Error!
    </h2>
    <h3
      style="font-style: italic;"
    >
      useLoaderData must be used within a data router.  See https://reactrouter.com/routers/picking-a-router.
    </h3>
    <pre
      style="padding: 0.5rem; background-color: rgba(200, 200, 200, 0.5);"
    >
      Error: useLoaderData must be used within a data router.  See https://reactrouter.com/routers/picking-a-router.
    at Object.invariant [as UNSAFE_invariant] (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/@remix-run/router/history.ts:494:11)
    at useDataRouterState (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-router/lib/hooks.tsx:876:3)
    at Object.useLoaderData (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-router/lib/hooks.tsx:947:15)
    at Proxy.useLoaderData (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/@remix-run/react/dist/components.js:760:25)
    at Occasions (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/app/routes/app.occasions._index/route.tsx:26:57)
    at renderWithHooks (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-dom/cjs/react-dom.development.js:15486:18)
    at mountIndeterminateComponent (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-dom/cjs/react-dom.development.js:20103:13)
    at beginWork (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-dom/cjs/react-dom.development.js:21626:16)
    at beginWork$1 (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-dom/cjs/react-dom.development.js:27465:14)
    at performUnitOfWork (/home/system-1/Documents/work/testing/testing-branch-dec31/nuflorist-official/node_modules/react-dom/cjs/react-dom.development.js:26599:12)
    </pre>
    <p>
      💿 Hey developer 👋
    </p>
    <p>
      You can provide a way better UX than this when your app throws errors by providing your own 
      <code
        style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
      >
        ErrorBoundary
      </code>
       or
       
      <code
        style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
      >
        errorElement
      </code>
       prop on your route.
    </p>
    <div
      id="PolarisPortalsContainer"
    />
  </div>
</body>
 ❯ Object.invariant [as UNSAFE_invariant] node_modules/@remix-run/router/history.ts:494:11
 ❯ useDataRouterState node_modules/react-router/lib/hooks.tsx:876:3
 ❯ Object.useLoaderData node_modules/react-router/lib/hooks.tsx:947:15
 ❯ Proxy.useLoaderData node_modules/@remix-run/react/dist/components.js:760:25
 ❯ Occasions app/routes/app.occasions._index/route.tsx:26:57
     24| export default function Occasions() {
     25|   console.log('-------------------------Occasions UI-------------------------');
     26|   const { payload: loaderData, errors: loaderErrors } = useLoaderData<typeof loader>();
       |                                                         ^
     27|   console.log(loaderData, 'loaderData');
     28|   const { errors: actionErrors, payload: actionPayload, code: actionCode } = useActionData<typeof action>() || {};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant