marsidev / react-turnstile

Cloudflare Turnstile integration for React.
https://www.npmjs.com/package/@marsidev/react-turnstile
MIT License
414 stars 25 forks source link

🐛 Bug: Failing in Jest #88

Closed smol-honk closed 2 months ago

smol-honk commented 2 months ago

Bug Report Checklist

Expected

Jest tests should be able to locate the react-turnstile library without failing.

Actual

I isolated it to this specific library. Our jest tests work inside a monorepo and we were originally using the other react-turnstile library fine but when I tried to switch to this one I get this error:

Cannot find module '@marsidev/react-turnstile' from '../my-repo/CaptchaWidget/CaptchaWidget.tsx'

It stack traces from at Resolver._throwModNotFoundError (../../node_modules/jest-resolve/build/resolver.js:427:11)

Package Version

"^1.0.1"

Browsers

Chrome, Firefox, Safari, Microsoft Edge, Other

Additional Info

I originally thought it was our jest implementation, but after a bit of troubleshooting and trying to do resolvers I noticed it only reacted with this library.

How to reproduce

  1. Have a monorepo with a components package (like packages/components)
  2. Import the react-turnstile component
  3. Render the turnstile component as the return return <Turnstile siteKey={...} />
  4. Import and use that component in another part of the monorepo, like, packages/app
  5. Have jest tests for components in packages/app that import the turnstile component from packages/components
  6. Jest will error out
Kireki commented 2 months ago

Similar issue after update (v1.0.1), but with ESLint

Resolve error: Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in...

What resolved this for me was adding a eslint-import-resolver-node and including its settings in my .eslintrc.

Adding "default" to the package.json of react-turnstile also seems like something that would work, but that's up to the maintainer of this package.

"exports": {
  ".": {
    "types": "./dist/index.d.ts",
    "import": "./dist/index.js",
    "default": "./dist/index.js"
  }
},
smol-honk commented 2 months ago

@marsidev thanks for the quick response! I wanted to add to this thread that it was still failing after I upgraded (which fixed the original error, so thank you for updating it!) with an esm import error. Traced it back to my nextjs app and I had to add this to the config:

async function jestConfig() {
  const nextJestConfig = await createJestConfig(config)();
  // THIS IS NEEDED BECAUSE NEXT JEST WONT TAKE THE TRANSFORM IGNORE PATTERNS
  nextJestConfig.transformIgnorePatterns[0] =
    '/node_modules/(?!@marsidev/react-turnstile)/';
  return nextJestConfig;
}

Related issue: https://github.com/vercel/next.js/issues/35634

marsidev commented 2 months ago

@smol-honk Thanks for sharing! I understand the problem occurs when we use Jest with jsdom environment and the tests have esm code.

Since the v1.0.0 we ship esm-only code, so that explains why it didn't happen before.

To summarize, some solutions are:

  1. Override config.transformIgnorePatterns as you suggested:
// jest.config.js
const nextJest = require("next/jest");

const createJestConfig = nextJest({ dir: "./" });

const customJestConfig = {
  testEnvironment: "jsdom",
};

async function jestConfig() {
  const nextJestConfig = await createJestConfig(customJestConfig)();
  nextJestConfig.transformIgnorePatterns[0] = "/node_modules/(?!@marsidev/react-turnstile)/";
  return nextJestConfig;
}

module.exports = jestConfig;
  1. Use ts-jest with the createDefaultEsmPreset() built-in helper:
// jest.config.ts
import type { Config } from "jest";
import nextJest from "next/jest";
import { createDefaultEsmPreset } from "ts-jest";

const createJestConfig = nextJest({ dir: "./" });
const defaultEsmPreset = createDefaultEsmPreset();

const config: Config = {
  ...defaultEsmPreset,
  testEnvironment: "jsdom",
};

export default createJestConfig(config);
  1. Migrate to vitest.