Reputation: 1109
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.
Upvotes: 1
Views: 4218
Reputation: 1
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
Upvotes: 0
Reputation: 116
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(),
]
})
Upvotes: 3