1

I am trying to run vitest snapshot tests on Storybook stories using the composeStories Fn from @storybook/testing-react, but I keep getting the error:

FAIL  src/components/common/Nav/Nav.test.tsx > Nav Component > it should match the snapshot
Error: Element type is invalid: expected a string (for built-in components) or a class/function
(for composite components) but got: undefined. You likely forgot to export your component from
the file it's defined in, or you might have mixed up default and named imports.

Check the render method of `Nav`.
//... stack trace

I believe it's related to the svg imports, as this only occurs in components that import svgs as react components via the SVGR library. i.e.

// components/common/Nav.tsx

import { ReactComponent as ECDLogo } from '@assets/ecd_logo.svg';

And my vite.config.ts uses the vite-svgr-plugin:

// vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';
import tsconfigPaths from 'vite-tsconfig-paths';
import path from 'path';

const tsConfigPathsOpts = {
  extensions: ['.svg', '.png', '.jpeg'],
  loose: true,
};

export default defineConfig({
  build: {
    outDir: 'build',
  },
  define: {
    global: {},
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@assets': path.resolve(__dirname, './src/assets'),
      '@styles': path.resolve(__dirname, './src/styles'),
      '@types': path.resolve(__dirname, './src/types'),
      '@components': path.resolve(__dirname, './src/components'),
    },
  },
  plugins: [react(), svgr(), tsconfigPaths(tsConfigPathsOpts)],
});

My Storybook config (.storybook/main.js) looks like so:

const path = require('path');
const { mergeConfig } = require('vite');
const tsconfigPaths = require('vite-tsconfig-paths');
const svgr = require('vite-plugin-svgr');

const tsConfigPathsOpts = {
  extensions: ['.svg', '.png', '.jpeg'],
  loose: true,
};


module.exports = {
  stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/preset-create-react-app',
    '@storybook/addon-a11y',
    '@storybook/node-logger',
    'storybook-addon-designs',
    'storybook-color-picker',
    'storybook-dark-mode',
  ],
  framework: '@storybook/react',
  core: {
    builder: '@storybook/builder-vite',
  },
  async viteFinal(config, { configType }) {
    return mergeConfig(config, {
      resolve: {
        alias: {
          '@': path.resolve(__dirname, '../src'),
          '@assets': path.resolve(__dirname, '../src/assets'),
          '@styles': path.resolve(__dirname, '../src/styles'),
          '@types': path.resolve(__dirname, '../src/types'),
          '@components': path.resolve(__dirname, '../src/components'),
        },
      },
      plugins: [svgr(), tsconfigPaths.default(tsConfigPathsOpts)],
    });
  },
};

I've come to understand that I need to mock these SVG's so that their snapshot is consistent, but I need direction on whether my mocking implementation is correct. See the vi.mock Fn below.

// components/common/Nav/Nav.test.tsx

import React from 'react';
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { composeStories } from '@storybook/testing-react';
import * as stories from './Nav.stories'; // import all stories from the stories file
import { vi } from 'vitest';

const { NavDefault } = composeStories(stories);

👀
vi.mock('@assets/*', () => {
  return {
    default: 'SVGUrl',
    ReactComponent: 'div',
  };
});

describe('Nav Component', () => {
  test('it should match the snapshot', () => {
    const { asFragment } = render(<NavDefault />);
    expect(asFragment()).toMatchSnapshot();
  });
});

I was expecting this to mock all the imports from @assets/* to be strings "SVGUrl" or 'div'

But I get the same error as above:

FAIL  src/components/common/Nav/Nav.test.tsx > Nav Component > it should match the snapshot
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

2 Answers 2

3

we had the same issue today and fixed it by adding the plugin svgr() in vitest.config.ts


import svgr from "vite-plugin-svgr";

export default defineConfig({
  plugins: [
    // ...other plugins
    svgr(),
  ]
})
Sign up to request clarification or add additional context in comments.

4 Comments

Interesting! Thanks for the response. I have svgr() listed as a plugin in my Vite.config.ts and am still experiencing the issue. Ultimately, we removed the snapshot tests as they were causing more headache then good.
hey, just a heads up, I mean on the viTEST.config.ts, not just vite.config.ts !
Does not work, added this plugin to vitest.config
worked for me. Might be worth noting that I have svgo: false in my next.config
0
svgr({
  svgrOptions: {
    ref: true,
    svgo: false,
    titleProp: true,
    exportType: 'named',
  },
  include: '**/*.svg',
})

Adding these options to svgr might work refernce github issue https://github.com/vitest-dev/vitest/discussions/5271

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.