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

Mocking issue when using Jest with the Rust compiler (next/jest) #32539

Closed
HiDeoo opened this issue Dec 15, 2021 · 17 comments · Fixed by #33731
Closed

Mocking issue when using Jest with the Rust compiler (next/jest) #32539

HiDeoo opened this issue Dec 15, 2021 · 17 comments · Fixed by #33731
Labels
SWC Related to minification/transpilation in Next.js. Testing Related to testing with Next.js.

Comments

@HiDeoo
Copy link

HiDeoo commented Dec 15, 2021

What version of Next.js are you using?

12.0.7

What version of Node.js are you using?

17.2.0

What browser are you using?

Chrome

What operating system are you using?

macOS 12.0.1

How are you deploying your application?

Vercel

Describe the Bug

I'm trying to test my Next.js 12 API Routes using Jest with the Rust compiler thanks to next/jest (which is amazing).

It looks like I can't use any mocking feature, for example a basic jest.mock().

When trying to customize a mock in a test, I would get an error similar to:

TypeError: mockFn.mockReturnValue is not a function

When trying to use jest.mock() with an explicit factory as second parameter, the factory is not even called which may indicates nothing is actually mocked.

Even if @swc/jest is not used, I wonder if this configuration problem described in a comment could be the main issue I'm hitting here as it looks like the Next.js base SWC options do not include these settings which are used by getJestSWCOptions().

As a temporary workaround, I'm declaring my jest.mock() in another file that I have to import in my tests as suggested in the same issue which works but a bit of a pain to maintain.

Expected Behavior

Being able to use jest.mock() in a test file.

To Reproduce

Use jest.mock() in a test file with Jest and the Rust compiler thanks to next/jest and try to customize the mock using mockFn.mockReturnValue().

@HiDeoo HiDeoo added the bug Issue was opened via the bug report template. label Dec 15, 2021
@balazsorban44 balazsorban44 added SWC Related to minification/transpilation in Next.js. kind: bug and removed bug Issue was opened via the bug report template. labels Dec 16, 2021
@martinkr
Copy link

Hi,

I absolutely love the rust compiler and the hard work you are putting into this.

Today I figured that when using the rust compiler jest.mocks are not working with import, only with require. (as far as i understood from the the documentation "babel automatically hoists jest.mock" - without babel it's not working) I also realised, that mocks in general are behaving different: they are not replacing all dependencies of my modules under test, just the dependencies inside the current test file.

Switching back to babel, jest.mock replaces all calls with the mocked functions.

minimal example:

rust

// home.test.js
const  loadData = require("service/data");
jest.mock("service/data");

describe(`Page / Home`, () => {
 it(`call mocked`, async () => {
  loadData() // mocked
 })
})
// home.tsx
import { loadData } from "service/data";


const Users: NextPage = ({
  data,
}: InferGetServerSidePropsType<typeof getServerSideProps>) => {

  loadData() // original
  return (<div></div>)

export const getServerSideProps: GetServerSideProps = async (
  context: GetServerSidePropsContext<ParsedUrlQuery, PreviewData>
) => {
 loadData() // original
}

babel

// home.test.js
import { loadData } from "service/data";
jest.mock("service/data");

describe(`Page / Home`, () => {
 it(`call mocked`, async () => {
  loadData() // mocked
 })
})
// home.tsx
import { loadData } from "service/data";


const Users: NextPage = ({
  data,
}: InferGetServerSidePropsType<typeof getServerSideProps>) => {

  loadData() // mocked
  return (<div></div>)

export const getServerSideProps: GetServerSideProps = async (
  context: GetServerSidePropsContext<ParsedUrlQuery, PreviewData>
) => {
 loadData() // mocked
}

If necessary, I can try and set up an example repository from my code for this.

Happy to help - cheers,

Martin

@spence-novata
Copy link

I wonder if #32964 is related? I'm not using swc but they seem like the might be in the same ball park.

@AndrewSmir
Copy link

Hi, has someone been able to mock modules since Next 12?

@bastibuck
Copy link

Can confirm the issue.

Started a fresh NextJS the other day and used Jest with Rust as the docs say. Tried to use manual mocks in my tests yesterday but it doesn't pick up the mock-files.

Simple work-around for now: opt-out of rust and opt-in to the Babel version like the docs say. No changes in my tests and the mocks are picked up 🚀

@balazsorban44 balazsorban44 added the Testing Related to testing with Next.js. label Jan 20, 2022
@bybruno
Copy link

bybruno commented Jan 21, 2022

Hi, has someone been able to mock modules since Next 12?

The only way to mock working for now is to add the mock inside jest.setup.js.
For example:

// jest.config.js
const nextJest = require('next/jest');

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

const customJestConfig = {
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'], // adds this
  collectCoverageFrom: [
    '**/*.{js,jsx,ts,tsx}',
    '!**/*.d.ts',
    '!**/node_modules/**',
  ],
  moduleNameMapper: {
    // Handle image imports
    // https://jestjs.io/docs/webpack#handling-static-assets
    '^.+\\.(jpg|jpeg|png|gif|webp|avif|svg)$': `<rootDir>/tests/__mocks__/fileMock.js`,
    // Handle module aliases
    '^@/(.*)': '<rootDir>/src/$1',
  },
  testPathIgnorePatterns: [
    '<rootDir>/node_modules/',
    '<rootDir>/.next/',
  ],
  testEnvironment: 'jsdom',
  transformIgnorePatterns: [
    '/node_modules/',
    '^.+\\.module\\.(css|sass|scss)$',
  ],
};

module.exports = createJestConfig(customJestConfig);
// jest.setup.js
jest.mock('next/router', () => ({
  push: jest.fn(),
  back: jest.fn(),
  events: {
    on: jest.fn(),
    off: jest.fn(),
  },
  asPath: jest.fn().mockReturnThis(),
  beforePopState: jest.fn(() => null),
  useRouter: () => ({
    push: jest.fn(),
  }),
}));
// file.test.js
import Router from 'next/router';

it('Router.push is called with the correct url', () => {
    expect(Router.push).toHaveBeenCalledWith('/any-url');
});

@archived-m
Copy link

The only way to mock working for now is to add the mock inside jest.setup.js

This solved the problem for me for now, although I have yet to figure out how to mock something differently based on the test using this workaround.

@bybruno
Copy link

bybruno commented Jan 24, 2022

The only way to mock working for now is to add the mock inside jest.setup.js

This solved the problem for me for now, although I have yet to figure out how to mock something differently based on the test using this workaround.

It's just a "workaround", and unfortunately creating mocks of specific scenarios will not work properly. I recommend using babel-jest.

@olingern
Copy link
Contributor

olingern commented Jan 25, 2022

Also seeing this problem. I can see in the console that the printed out function is not mocked. I've reproduced this on 12.0.8 and the latest canary.

Switching to babel-jest as @bybruno seems to be the best way to move forward. Copying and pasting the jest.config.js from the instructions worked for me.

IMO, the SWC compiler shouldn't be the recommended default until the rough edges are worked out. I spent way too much time thinking I was mocking incorrectly.


Debug code

import { render } from '@testing-library/react';
import Header from '../../components/header';
import { useSession } from 'next-auth/react';

jest.mock('next-auth/react');

test('should mock', () => {
  console.log(useSession.toString());
  render(<Header />);
  expect(true).toBeTruthy();
});

@bruceharrison1984
Copy link

Just went through the same thing as @olingern. Falling back to using a .babelrc file and opt-ing out of SWC was my only path forward.

@blaketastic2
Copy link

I may have gotten things working by adding some dependencies in package.json

"devDependencies": {
    "@swc/core": "^1.2.124",
    "@swc/jest": "^0.2.15",
    ....
}

and then use the swc/jest transformer in jest.config.js

  transform: {
    '^.+\\.tsx?$': ['@swc/jest'],
  },

Lastly, removed the .babelrc

@timneutkens
Copy link
Member

Had a look at this and it seems that the main problem is what @martinkr mentioned, babel-jest has some Babel plugins that are added automatically: https://github.com/facebook/jest/blob/main/packages/babel-preset-jest/index.js. In order to make this work we'll have to port babel-plugin-jest-hoist to SWC.

@timneutkens
Copy link
Member

According to @kdy1 this is already implemented: https://github.com/swc-project/swc/blob/0359deb4841be743d73db4536d4a22ac797d7f65/crates/swc_ecma_ext_transforms/src/jest.rs so we just have to enable it in next/jest 💯

timneutkens added a commit to timneutkens/next.js that referenced this issue Jan 27, 2022
@timneutkens
Copy link
Member

Opened a PR that fixes this issue: #33731

@kodiakhq kodiakhq bot closed this as completed in #33731 Jan 31, 2022
kodiakhq bot pushed a commit that referenced this issue Jan 31, 2022
Fixes #32539

Implements what was shared at #32539 (comment).



## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `yarn lint`
@davidgruar
Copy link

I still had this issue after upgrading to next@12.0.10, which I believe incorporates the fix. I managed to get it working with the help of @blaketastic2's solution.

@balazsorban44
Copy link
Member

Hi, @davidgruar could you test canary, and if the error still happens open a new issue with a reproduction? I would be happy to have a look if there is still a problem here.

@davidgruar
Copy link

@balazsorban44 The funny thing is, it's now working just fine with 12.0.10 and without @swc/jest. Not sure why it wasn't before. Apologies!

natew pushed a commit to natew/next.js that referenced this issue Feb 16, 2022
Fixes vercel#32539

Implements what was shared at vercel#32539 (comment).



## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `yarn lint`
@github-actions
Copy link
Contributor

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 12, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
SWC Related to minification/transpilation in Next.js. Testing Related to testing with Next.js.
Projects
None yet
Development

Successfully merging a pull request may close this issue.