bencodezen / vue-enterprise-boilerplate

An ever-evolving, very opinionated architecture and dev environment for new Vue SPA projects using Vue CLI.
7.78k stars 1.32k forks source link

Jest can't find SVG used with `require` #70

Closed constantm closed 5 years ago

constantm commented 6 years ago

Hello! Firstly, thanks for this boilerplate. I'm relatively new to Vue, and I'm learning a ton of good patterns and conventions from it.

I'm having trouble with Jest not finding a an SVG I'm using in a component:

<inline-branded-svg :src="require('@/assets/generic.svg')" />

The reason I'm using the require is to alter the content of the SVG within the component, and it renders perfectly fine in the browser. However, when I run the Jest unit test for the component, it can't resolve my image:

[Vue warn]: Error in render: "Error: Cannot find module '@/assets/generic.svg' from 'nav-bar.vue'"

 (found in <Root>)
    console.error node_modules/vue/dist/vue.runtime.common.js:1739
      { Error: Cannot find module '@/assets/generic.svg' from 'nav-bar.vue'
          at Resolver.resolveModule (/repo/node_modules/jest-resolve/build/index.js:210:17)
          at Resolver._getVirtualMockPath (/repo/node_modules/jest-resolve/build/index.js:327:16)
          at Resolver._getAbsolutPath (/repo/node_modules/jest-resolve/build/index.js:313:14)
          at Resolver.getModuleID (/repo/node_modules/jest-resolve/build/index.js:290:31)
          at Runtime._shouldMock (/repo/node_modules/jest-runtime/build/index.js:701:37)
          at Runtime.requireModuleOrMock (/repo/node_modules/jest-runtime/build/index.js:457:14)
          at Proxy.render (/repo/src/components/nav-bar.vue:56:747)
          at VueComponent.Vue._render (/repo/node_modules/vue/dist/vue.runtime.common.js:4542:22)
          at VueComponent.updateComponent (/repo/node_modules/vue/dist/vue.runtime.common.js:2786:21)
          at Watcher.get (/repo/node_modules/vue/dist/vue.runtime.common.js:3140:25) code: 'MODULE_NOT_FOUND' }

  ● @components/nav-bar › displays the user's name in the profile link

I'm not sure if this is a config issue, or if this is even the right place to post this, but any help would be fantastic. :)

constantm commented 6 years ago

UPDATE:

So, I got Jest loading the SVG by adding '@/assets': 'src/assets' to the aliases.config.js file.

However, this seems to now break because the require is expecting JS, but instead receives an SVG:

SyntaxError: Unexpected token <
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30">...

I tried fixing this by adding babel-jest to transform the requires, but I couldn't find a way to get Babel to transform the JSX used in test/unit/setup.js:96. I eventually gave up on this approach.

I then used what I learned from this article, to try and load a blank JS file in the tests. I eventually got this working by:

I feel like there should be a better way to accomplish this. Any input on this would be great. :)

chrisvfritz commented 5 years ago

The @ alias is added automatically by Vue CLI, rather than coming from aliases.config.js, which caused the first part of the problem. To fix it, I've just overridden it to point to the root of the project (since we already have @src).

Then to fix the 2nd problem, I've updated jest.config.js to mock any static assets to an empty string:

moduleNameMapper: {
  ...require('./aliases.config').jest,
  // Transform any static assets to empty strings
  '\\.(jpe?g|png|gif|webp|svg|mp4|webm|ogg|mp3|wav|flac|aac|woff2?|eot|ttf|otf)$':
    '<rootDir>/tests/unit/fixtures/empty-string.js',
},

Let me know if those changes don't resolve the issue for you. 🙂

constantm commented 5 years ago

Fantastic, thank you!

constantm commented 5 years ago

@chrisvfritz there seems to be a minor issue with this. :) The load order is the wrong way around, so if it finds an asset to map from aliases, it will ignore the image module mapper. Changing the order around fixes this:

moduleNameMapper: {
  // Transform any static assets to empty strings
  '\\.(jpe?g|png|gif|webp|svg|mp4|webm|ogg|mp3|wav|flac|aac|woff2?|eot|ttf|otf)$':
    '<rootDir>/tests/unit/fixtures/empty-string.js',
  ...require('./aliases.config').jest,
},
chrisvfritz commented 5 years ago

@constantm Thanks! I just updated. 🙂

ruslanzharkov commented 4 years ago

@constantm Thanks a lot, this helped me!