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

nextjs/TypeScript with Jest: "SyntaxError: Cannot use import statement outside a module" for some packages #58707

Open
1 task done
erikmuttersbach opened this issue Nov 20, 2023 · 7 comments
Labels
examples Issue was opened via the examples template.

Comments

@erikmuttersbach
Copy link

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.1.0: Mon Oct  9 21:28:12 PDT 2023; root:xnu-10002.41.9~6/RELEASE_ARM64_T8103
Binaries:
  Node: 21.1.0
  npm: 10.2.0
  Yarn: 1.22.19
  pnpm: N/A
Relevant Packages:
  next: 14.0.4-canary.5
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.2.2
Next.js Config:
  output: N/A


### Which example does this report relate to?

https://github.com/vercel/next.js/tree/canary/examples/with-jest

### What browser are you using? (if relevant)

_No response_

### How are you deploying your application? (if relevant)

_No response_

### Describe the Bug

I am using next.js with TypeScript and try to use jest for running tests. When importing some packages, such as `chalk` or `ora` I get the following error when running jest.

```bash
npx jest
(node:27468) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
 PASS  __tests__/index.test.tsx
 PASS  app/component.test.tsx
 PASS  app/rsc/page.test.tsx
 PASS  app/blog/[slug]/page.test.tsx
 PASS  __tests__/snapshot.tsx
 FAIL  app/client/page.test.tsx
  ● Test suite failed to run

    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:

    /Users/erikmuttersbach/Projects/home-assistant-openai-nextjs/with-jest-app/node_modules/chalk/source/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import ansiStyles from '#ansi-styles';
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

       8 | it('App Router: Works with Client Components', () => {
       9 |   console.log(chalk.blue('Client Component Test'))
    > 10 |   render(<ClientComponent />)
         |                                                       ^
      11 |   expect(screen.getByRole('heading')).toHaveTextContent('Client Component')
      12 | })
      13 |

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1505:14)
      at Object.<anonymous> (app/client/page.test.tsx:10:55)

Test Suites: 1 failed, 5 passed, 6 total
Tests:       5 passed, 5 total
Snapshots:   1 passed, 1 total
Time:        0.842 s, estimated 1 s
Ran all test suites.

Expected Behavior

Using the same packages for running the application works. I was expecting jest to behave the same

To Reproduce

Start with a clean setup:

nvm use 21.1 
npx create-next-app --example with-jest with-jest-app
cd with-jest-app/
npm install next@canary
npx jest # still works!

Introduce breaking changes:

npm install chalk 

Edit app/client/page.test.tsx (or any other test file) and use chalk:

/**
 * @jest-environment jsdom
 */
import { render, screen } from '@testing-library/react'
import ClientComponent from './page'
import chalk from 'chalk'

it('App Router: Works with Client Components', () => {
  console.log(chalk.blue('Client Component Test'))
  render(<ClientComponent />)
  expect(screen.getByRole('heading')).toHaveTextContent('Client Component')
})

Now npx jest fails:

npx jest
(node:27468) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
 PASS  __tests__/index.test.tsx
 PASS  app/component.test.tsx
 PASS  app/rsc/page.test.tsx
 PASS  app/blog/[slug]/page.test.tsx
 PASS  __tests__/snapshot.tsx
 FAIL  app/client/page.test.tsx
  ● Test suite failed to run

    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:

    /Users/erikmuttersbach/Projects/home-assistant-openai-nextjs/with-jest-app/node_modules/chalk/source/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import ansiStyles from '#ansi-styles';
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

       8 | it('App Router: Works with Client Components', () => {
       9 |   console.log(chalk.blue('Client Component Test'))
    > 10 |   render(<ClientComponent />)
         |                                                       ^
      11 |   expect(screen.getByRole('heading')).toHaveTextContent('Client Component')
      12 | })
      13 |

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1505:14)
      at Object.<anonymous> (app/client/page.test.tsx:10:55)

Test Suites: 1 failed, 5 passed, 6 total
Tests:       5 passed, 5 total
Snapshots:   1 passed, 1 total
Time:        0.842 s, estimated 1 s
Ran all test suites.
@erikmuttersbach erikmuttersbach added the examples Issue was opened via the examples template. label Nov 20, 2023
@anthones
Copy link

You are probably using babel-jest for transforming TS and TSX files. Take a look at your jest config file and in the "transform" option try switching to ts-jest for these two file types.

  preset: 'ts-jest',
  transform: {
    '^.+\\.(ts|tsx)?$': 'ts-jest',
    '^.+\\.(js|jsx)$': 'babel-jest',
  },

@thesonpb
Copy link

Same here for me:

node_modules/antd/es/message/index.js:3
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:77:18)
    at wrapSafe (node:internal/modules/cjs/loader:1288:20)
    at Module._compile (node:internal/modules/cjs/loader:1340:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at Module.require (node:internal/modules/cjs/loader:1235:19)
    at mod.require (/home/ubuntu/jenkins/workspace/ONE-DX/CICD_SERVER_68/ONEDX_FE_CORE_CUSTOMERS_PIPELINE/node_modules/next/dist/server/require-hook.js:64:28)
    at require (node:internal/modules/helpers:176:18)
    at 9573 (/home/ubuntu/jenkins/workspace/ONE-DX/CICD_SERVER_68/ONEDX_FE_CORE_CUSTOMERS_PIPELINE/build-workplace/server/pages/_app.js:1:1302) {
  type: 'SyntaxError'
}

Although the code has no changes, the build is completely difference

Update:

When I use nextjs 14.0.2, the error disappear. The cause could be the version 14.0.3

@victorandree
Copy link

I'm seeing the same issue as @thesonpb with next@14.0.3 and antd@4.24.15. It seems like next@14.0.3 includes this change which changes how antd is modularized: #57968. I'm pretty sure it's what breaks this for us.

Note: My issue is not when running jest, but when doing npm run build. My build fails during the "Collecting page data" step (output below).

Not sure how to fix this, or if it should be reported as a separate issue. For now, I'm pinning 14.0.2.

 ✓ Creating an optimized production build
 ✓ Compiled successfully
   Collecting page data  ../app/node_modules/antd/es/spin/index.js:1
import _extends from "@babel/runtime/helpers/esm/extends";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1153:20)
    at Module._compile (node:internal/modules/cjs/loader:1197:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1287:10)
    at Module.load (node:internal/modules/cjs/loader:1091:32)
    at Module._load (node:internal/modules/cjs/loader:938:12)
    at Module.require (node:internal/modules/cjs/loader:1115:19)
    at mod.require (/app/node_modules/next/dist/server/require-hook.js:64:28)
    at require (node:internal/modules/helpers:130:18)
    at 2600 (/app/.next/server/pages/admin.js:1:2698)

> Build error occurred
Error: Failed to collect page data for /admin
    at /app/node_modules/next/dist/build/utils.js:1217:15
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  type: 'Error'
}

@erikmuttersbach
Copy link
Author

erikmuttersbach commented Nov 22, 2023

@victorandree, @thesonpb I cannot confirm that this is connected to the issue I am posting. Changing to the nextjs version you mentioned does not help for me.

What ultimately ended up working for me is to add the problematic packages into transformIgnorePatterns:

jest.config.ts

const tsconfig = require("./tsconfig.json");
const moduleNameMapper = require("tsconfig-paths-jest")(tsconfig)

module.exports = {
  preset: 'ts-jest',
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  moduleNameMapper,
  testEnvironment: 'jest-environment-jsdom',
  "transform": {
    "^.+\\.(ts|tsx)$": "ts-jest",
    '^.+\\.(js|jsx)$': 'babel-jest'
 },
 "transformIgnorePatterns": [
  "node_modules/(?!(ora|chalk|cli-cursor))",
],
}

@victorandree
Copy link

@erikmuttersbach Seems likely. I've reported my issue as a new one: #58817.

@huypham1411
Copy link

I also got this issue, I am pretty new to setting up Jest so I hope someone can help me
here is my jest.config.js

const nextJest = require('next/jest');

const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: './',
});

// Add any custom config to be passed to Jest
const customJestConfig = {
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  testEnvironment: 'jest-environment-jsdom',
  preset: 'ts-jest',
  transformIgnorePatterns: [
    'node_modules/(?!@azure/msal-react)',
    'node_modules/(?!antd)/',
  ],
  transform: {
    '^.+\\.jsx?$': 'babel-jest',
    '^.+\\.(js|jsx|ts|tsx)$': 'ts-jest',
  },
  moduleNameMapper: {
    '@azure/msal-react': '<rootDir>/mocked/module.js',
  },
};

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);

this code I follow the jest example in Nextjs source code, I got this issue when running jest to test component render

\node_modules\antd\es\button\index.js:3
    import Button from './button';
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

@zzh8829
Copy link

zzh8829 commented Nov 26, 2024

transpilePackages option fixed this issue for me #58817 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
examples Issue was opened via the examples template.
Projects
None yet
Development

No branches or pull requests

6 participants