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

feat(next/jest): mock static imports of svg, image and others differently #36907

Closed

Conversation

bb-in-hoodie
Copy link

@bb-in-hoodie bb-in-hoodie commented May 14, 2022

Related to #36230 , #35028 . (and PR #34350)


For now, every statically imported file gets mocked by a single fileMock.js.

// (current) jest.config.js
moduleNameMapper = {
  '^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp)$': require.resolve(`./__mocks__/fileMock.js`),
  '^.+\\.(svg)$': require.resolve(`./__mocks__/fileMock.js`),
  ...
}

https://github.com/vercel/next.js/blob/canary/packages/next/build/jest/jest.ts#L86-L107

// (current) fileMock.js
module.exports = {
  src: '/img.jpg',
  height: 24,
  width: 24,
  blurDataURL: 'data:image/png;base64,imagedata',
}

https://github.com/vercel/next.js/blob/canary/packages/next/build/jest/__mocks__/fileMock.js


As a result, In jest environment, every statically imported file will be mocked as a mock jpg file (to be specific, it is a StaticImageData-typed object). But the thing is, in real world scenario, svg file doesn't get imported in a way that jpg or other image files do. Svg files gets imported by @svgr/webpack so that the import results of svg file and other images end up being different. You can observe this by simply do console.log both imported files.

image image
png file (StaticImageData-typed object) svg file (a function)

In fact, next.js itself is treating svg and other images differently. (look image-types)


So to make both svg file and other image files get imported properly under jest environment, fileMock.js should be split into each dedicated mock files as below.

// (updated) jest.config.js
moduleNameMapper = {
  '\\.svg$': '<rootDir>/__mocks__/svgMock.js',
  '\\.(jpg|jpeg|png|gif|webp)$': '<rootDir>/__mocks__/imageMock.js',
  '\\.(eot|otf|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/__mocks__/fileMock.js',
  ...
}
// (added) svgMock.js
const React = require('react');

module.exports = (...props) => {
  const svg = React.createElement('svg', {
    fill: 'none',
    xmlns: 'http://www.w3.org/2000/svg',
    ...props[0],
  });
  return svg;
};
// (added) imageMock.js
module.exports = {
  src: '/mock-image.png',
  height: 24,
  width: 24,
  blurDataURL: 'data:image/png;base64,imagedata',
}
// (modified) fileMock.js
module.exports = 'test-file-stub';

fileMock.js doesn't have to be changed but it feels quite awkward for me to mock non-image files as a mock jpg file.

In svgMock.js, I tried to mimic the way how @svgr/webpack treats a svg file. If a svg file gets mocked in such way, now svg-as-component will work well in jest environment too. (ex. <SvgFile width={10} height={20} />).


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

@bb-in-hoodie
Copy link
Author

By the way, I want to test the updated next/jest with new next.ts by running this test code locally, but I don't know how.

The above test code is importing next/jest by require('next/jest') so it imports remote module not the one I edited. How could I test my own next.ts?

(Above test code should be update too. As far as I know, a statically imported svg file cannot be the src of <Image> component.)

@bb-in-hoodie bb-in-hoodie force-pushed the fix/split-image-mocks branch from 405f61f to 65264ef Compare May 14, 2022 08:43
@balazsorban44
Copy link
Member

balazsorban44 commented May 15, 2022

To run tests with your changes, you need to build Next.js locally. In development, you should be able to run yarn dev in the monorepo, or yarn build for a production build.

More about testing here: https://github.com/vercel/next.js/blob/canary/test/readme.md

@bb-in-hoodie
Copy link
Author

bb-in-hoodie commented May 16, 2022

To run tests with your changes, you need to build Next.js locally. In development, you should be able to run yarn dev in the monorepo, or yarn build for a production build.

More about testing here: https://github.com/vercel/next.js/blob/canary/test/readme.md

So if I want to test with my local changes, should I run any test (like yarn testonly --testPathPattern "production/jest/index" -t "next/jest") while my local next.js is running? (via yarn dev or yarn start)

So if I run yarn dev or yarn build once, and then all the after tests I run would be running on that locally built next.js? (in this case, locally built next/jest)

I've read the testing docs for sure but I still don't get which binary will be used when I run a test.

I'm asking this because even though I run yarn build, this line in the test code seems to load the remote next/jest. (I changed how does svg gets mocked but it mocks as current next does on testing environment)

Copy link
Member

@timneutkens timneutkens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the thing is, in real world scenario, svg file doesn't get imported in a way that jpg or other image files do. Svg files gets imported by @svgr/webpack so that the import results of svg file and other images end up being different.

This isn't the case in Next.js by default. You likely made customizations to webpack to add another svg loader that turns imported svg files into React components, so this change can't be landed in Next.js as it's particular to your application.

@bb-in-hoodie
Copy link
Author

bb-in-hoodie commented May 16, 2022

This isn't the case in Next.js by default. You likely made customizations to webpack to add another svg loader that turns imported svg files into React components, so this change can't be landed in Next.js as it's particular to your application.

wow.. I have always thought it must be a default settings because I haven't noticed my teammate had set up @svgr/webpack quite a long time ago. I just realized that, I'm sorry. I'll close the PR for now and may open it later if there is a better workaround. thank you!

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants