nuxt-community / svg-module

Super simple svg loading module for Nuxt.js
MIT License
339 stars 35 forks source link

Issues when using with Jest #84

Open adamchipperfield opened 3 years ago

adamchipperfield commented 3 years ago

This is a question and not an issue with this module (which I love, it's been super helpful in countless projects for me!)

I have Jest set up to run tests on my components, but as soon as I added SVGs into my components Jest started to throw errors. The main error I get is:

Could not locate module @/assets/icons/misc-close.svg?inline mapped as: /path/to/nuxt/$1.

I've tried to use a number of methods, including the one vue-svg-loader suggests, but nothing works. I even tried removing ?inline from the import but the same error persists.

Can anyone provide any guidance here please?

manuelodelain commented 3 years ago

Hi @adamchipperfield,

Can you provide a minimal example please?

Schascha commented 3 years ago

I stumble in the same error today. The problem is that jest can not transform inline SVGs.

Error message:

Test suite failed to run

    Configuration error:

    Could not locate module @/assets/logo.svg?inline mapped as:
    /path/to/nuxt/$1.

    Please check your configuration for these entries:
    {
      "moduleNameMapper": {
        "/^@\/(.*)$/": "/path/to/nuxt/$1"
      },
      "resolver": undefined
    }

Logo.vue

<template>
    <Logo />
</template>

<script>
import Logo from '@/assets/logo.svg?inline';

export default {
    components: {
        Logo
    }
};
</script>

Logo.test.js

import {mount} from '@vue/test-utils';
import Logo from './Logo';

describe('Logo', () => {
    test('is a Vue instance', () => {
        const wrapper = mount(Logo);
        expect(wrapper.vm).toBeTruthy();
    });
});

jest.config.js

module.exports = {
    moduleNameMapper: {
        '^@/(.*)$': '<rootDir>/$1',
        '^~/(.*)$': '<rootDir>/$1',
        '^vue$': 'vue/dist/vue.common.js'
    },
    moduleFileExtensions: [
        'js',
        'vue',
        'json'
    ],
    testEnvironment: 'jsdom',
    transform: {
        '^.+\\.js$': 'babel-jest',
        '.*\\.(vue)$': 'vue-jest'
    },
    collectCoverage: true,
    collectCoverageFrom: [
        '<rootDir>/components/**/*.vue',
        '<rootDir>/pages/**/*.vue'
    ]
};

Solution: Maybe something like this in the jest config https://github.com/visualfanatic/vue-svg-loader/issues/38#issuecomment-407657015 But unfortunately I have not yet found a solution that fits my project setup.

andorfermichael commented 2 years ago

The following configuration helped me, maybe it helps somebody else too:

my component

// Header.vue
<template>
    <navigation-header
        :title-component="{
            name: 'navigation-header-title',
            props: {
                imgSrcDefault:
                    theme === 'Default'
                        ? require('assets/images/logo_default.svg')
                        : require('assets/images/logo_graphite.svg')
            }
        }"
    />
</template>

<script>
import { mapGetters } from 'vuex'

export default {
    name: 'Header',
    computed: {
        ...mapGetters('config', ['theme'])
    }
}
</script>

my jest config

// jest.config.js
module.exports = {
    moduleNameMapper: {
        '^@/(.*)$': '<rootDir>/$1',
        '^~/(.*)$': '<rootDir>/$1',
        '^vue$': 'vue/dist/vue.common.js',
        '^.+/(.*\\.svg)': '<rootDir>/assets/images/$1'
    },
    moduleFileExtensions: ['js', 'vue', 'json'],
    transform: {
        '^.+\\.js$': 'babel-jest',
        '.*\\.(vue)$': 'vue-jest',
        '^.+\\.svg$': '<rootDir>/__tests__/setup/custom-transformers/svg-transformer.js'
    },
    collectCoverage: true,
    collectCoverageFrom: [
        '<rootDir>/components/**/*.vue',
    ],
    coverageReporters: ['cobertura', 'clover', 'json', 'lcov', ['text', { skipFull: true }]],
    testMatch: ['**/__tests__/**/?(*.)+(spec|test).[jt]s?(x)'] // respect only files in test folder which include spec or test in filename
}

my svg transformer:

// svg-transformer.js
module.exports = {
    process(src, filename) {
        return 'module.exports = ' + JSON.stringify(filename) + ';'
    }
}

my test:

    describe('renders navigation-header', () => {
        test('with default logo when theme is Default', () => {
            wrapper = shallowMount(Header, {
                localVue,
                store,
                computed: {
                    theme: () => 'Default'
                }
            })

            expect(wrapper.findComponent(NavigationHeader).props().titleComponent.props.imgSrcDefault).toBe(
                process.cwd() + '/assets/images/logo_default.svg'
            )
        })

        test('with graphite logo when theme is NOT Default', () => {
            wrapper = shallowMount(Header, {
                localVue,
                store,
                computed: {
                    theme: () => 'Special'
                }
            })

            expect(wrapper.findComponent(NavigationHeader).props().titleComponent.props.imgSrcDefault).toBe(
                process.cwd() + '/assets/images/logo_graphite.svg'
            )
        })
    })
wambugudavis commented 2 years ago

I was able to resolve this issue using jest-transform-stub and modifying this section in jest.config.js

moduleNameMapper: {
    '^.+/(.*\\.svg)': "jest-transform-stub",
    '^@/(.*)$': '<rootDir>/$1',
    '^~/(.*)$': '<rootDir>/$1',
    '^vue$': 'vue/dist/vue.common.js'
  }
RuNpiXelruN commented 2 years ago

Thanks @wambugudavis this solved it for me perfectly 👍