oedotme / generouted

Generated file-based routes for Vite
https://stackblitz.com/github.com/oedotme/generouted/tree/main/explorer
MIT License
1.02k stars 47 forks source link

Issues importing @generouted/react-router/client in jest #145

Closed alexander7161 closed 3 months ago

alexander7161 commented 7 months ago

Describe the Bug

Everything is working fine with generouted. However when I try to run jest tests that import a file that imports generouted client hooks I get the following error: Cannot find module '@generouted/react-router/client' from 'src/router.ts'

Seems to be related to https://stackoverflow.com/questions/53466859/jest-cannot-find-module-from-node-modules/75595580#75595580 Perhaps exporting a cjs version of client would fix it? See https://github.com/oedotme/generouted/blob/8939c9dc0012c73b08b0b4a0ff2c334e6c0859c9/packages/react-router/package.json#L46

Generouted Version

1.18.2

Your Example Website or App or Reproduction

N/A

Steps to Reproduce the Bug or Issue

  1. Create a vite project using jest for testing
  2. import generouted router.ts in a file that has tests
  3. The import fails with error Cannot find module '@generouted/react-router/client' from 'src/router.ts'

Expected Behavior

Generouted client should import correctly in commonJS environment

Screenshots or Videos

No response

Platform

Additional context

No response

oedotme commented 7 months ago

Hey @alexander7161, could you provide a Stack blitz example?

I'm also wondering why do you need to import generouted at Jest test? As this file only contains type related exports, and some type-safe react-router-dom exports.

alexander7161 commented 7 months ago

Thanks for the response!

Here's a minimal reproduction: https://stackblitz.com/edit/vitejs-vite-qsba6t?file=src%2Fmain.test.tsx

If you run jest in the console you will see an error importing generouted:

image

I'm not importing generouted directly, I'm testing a file that imports src/router which imports generouted

oedotme commented 7 months ago

Hey @alexander7161, I tried with vitest but it fails as well. I've encountered errors related to import.meta.glob resolving which is a Vite browser API that's used to scan the modules. I don't expect it to work out well tbh.

Could you try playwright instead of jest|vitest to test out the rendering? as it provides a real browser environment. After installing and setting up playwright using yarn create playwright, that would be an equivalent test:

// tests/rendering.test.ts

import { expect, test } from '@playwright/test'

test('rendering', async ({ page }) => {
  await page.goto('/')
  await expect(page.getByRole('heading', { name: 'Home' })).toBeVisible()
})
alexander7161 commented 7 months ago

But src/router only imports @generouted/react-router/client, which looking at the source code doesn't use import.meta.glob at all and only imports methods from react-router-dom

The original use case I had was a jest unit test on a ProtectedRoute component (e.g https://www.robinwieruch.de/react-router-private-routes/) that imports Navigate from src/router. Ideally I'd be able to test this with jest only and not need playwright

alexander7161 commented 7 months ago

I did some more debugging and added a "require": "./dist/client/index.js" to the @generouted/react-router ./client export in my node_modules, here: https://github.com/oedotme/generouted/blob/8939c9dc0012c73b08b0b4a0ff2c334e6c0859c9/packages/react-router/package.json#L48C8-L48C14

Now I get a different error:

Jest encountered an unexpected token

    Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

    Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

    By default "node_modules" folder is ignored by transformers.

    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
     • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/configuration
    For information about custom transformations, see:
    https://jestjs.io/docs/code-transformation

    Details:

    /frontend/node_modules/@generouted/react-router/dist/client/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import {
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

I believe if generouted had a cjs export for react-router/client then it would work correctly.

See https://stackoverflow.com/questions/53466859/jest-cannot-find-module-from-node-modules

oedotme commented 7 months ago

@alexander7161 If you need to test the rendering as the example you provided — then you'd need to import the Routes component which is imported from @generouted/react-router which uses import.meta.glob to scan the routes.

When I tried to add the cjs format to @generouted/react-router, I got an error related to the import.meta.glob which is expected. Here's a related comment on this issue.

If you actually need to use imports from the src/router.ts generated file — you can skip src/router.ts and @generouted/react-router/client all together and import the components/hooks/utils directly from react-router-dom to test out what you need, as src/router.ts only adds some type narrowing to react-router-dom exports.

Hope that helps, please let me know if you have more questions.

alexander7161 commented 7 months ago

The thing is I want to use src/router.ts so I can benefit from the type safety of generouted in my components. I want to keep using jest for testing them. It's a shame that generouted doesn't export a cjs version as that would solve this issue.

I found a workaround if anyone is running into the same issue.

Add these to your jest.config.js:

{
  "transformIgnorePatterns": [
    "node_modules/(?!@@generouted)"
  ],
  "moduleNameMapper": {
    "@generouted/react-router/client": "<rootDir>/node_modules/@generouted/react-router/dist/client"
  }
}

This tells jest not to transform generouted (since it's already ESM) and maps @generouted/react-router/client to the ESM client dist folder

oedotme commented 3 months ago

Glad you had it working with this config. Thanks for sharing the workaround.