Nextjs,Jest:元素类型无效:需要一个字符串(对于内置组件)或一个类/函数(对于复合组件)但得到:对象

问题描述 投票:0回答:1

我正在尝试在我的 Nextjs 项目上设置单元测试。我已经按照official Nextjs docs上的文档进行设置。

我遇到的问题似乎与配置本身或

@headlessui/react
库及其导入方式有关。

当我尝试运行测试时,我收到以下错误消息:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) 但得到的是:对象。 检查

Listbox
.

的渲染方法

该组件在运行时和构建时工作得很好。

这是我的项目配置。

tsconfig.json

{
  "compilerOptions": {
    "target": "ES6",
    "lib": ["dom", "dom.iterable", "esnext"],
    "baseUrl": "./",
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "forceConsistentCasingInFileNames": true,
    "removeComments": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

jest.config.mjs

import nextJest from 'next/jest.js';

const createJestConfig = nextJest({
  dir: './',
});

/** @type {import('jest').Config} */
const config = {
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  testEnvironment: 'jest-environment-jsdom',
  moduleDirectories: ['node_modules', '<rootDir>/'],
  testMatch: ['**/*.(test|spec).(js|jsx|ts|tsx)'],
  coveragePathIgnorePatterns: ['/node_modules/'],
};

export default createJestConfig(config);

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [{ protocol: 'https', hostname: '**.pixabay.com' }],
  },
  reactStrictMode: true,
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    });
    return config;
  },
};

module.exports = nextConfig;

__tests__/components

中的测试文件
import { render, screen } from '@testing-library/react';
import { ListType } from 'components/calculator/builder/utils/types/list';
import List from 'components/ui/fields/list/list';

jest.mock('components/calculator/context/hooks', () => ({
 // ... mock custom hook.
}));

const mockList: ListType = {
// ... mock data
};

const renderComponent = () => {
  render(<List list={mockList} />);
};

describe('List component', () => {
  test('check if the correct list options are displayed', () => {
    renderComponent();
    expect(screen.getAllByRole('option')).toHaveLength(mockList.options.length);
    expect(screen.getByText(mockList.description)).toBeInTheDocument();
    expect(screen.getByText(mockList.placeholder)).toBeInTheDocument();
  });
});

实际测试组件的片段

import { Listbox } from '@headlessui/react'; // <= the actual Listbox import from node_modules
// some other inner imports

interface ListProps {
  list: ListType;
}

export default function List({ list }: ListProps) {
return (
    <Listbox>
       // ...implementation is irrelevant
    </Listbox>)
}

package.json

{
  "name": "cw-client",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "typescript": "tsc",
    "test": "jest",
    "test:ci": "jest --ci"
  },
  "engines": {
    "node": ">=19.3.0"
  },
  "dependencies": {
    "@dnd-kit/core": "^6.0.7",
    "@dnd-kit/modifiers": "^6.0.1",
    "@dnd-kit/sortable": "^7.0.2",
    "@dnd-kit/utilities": "^3.2.1",
    "@headlessui/react": "^1.7.7",
    "@next/font": "13.1.1",
    "lodash.debounce": "^4.0.8",
    "mathjs": "^11.6.0",
    "next": "13.1.1",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-number-format": "^5.1.4"
  },
  "devDependencies": {
    "@next/eslint-plugin-next": "^13.1.1",
    "@svgr/webpack": "^6.5.1",
    "@tailwindcss/forms": "^0.5.3",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^14.0.0",
    "@types/lodash.debounce": "^4.0.7",
    "@types/node": "18.11.17",
    "@types/react": "18.0.26",
    "@types/react-dom": "18.0.10",
    "@typescript-eslint/eslint-plugin": "^5.47.0",
    "@typescript-eslint/parser": "^5.47.0",
    "autoprefixer": "^10.4.13",
    "eslint": "8.30.0",
    "eslint-config-next": "13.1.1",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-prettier": "^4.2.1",
    "eslint-plugin-react": "^7.31.11",
    "jest": "^29.5.0",
    "jest-environment-jsdom": "^29.5.0",
    "postcss": "^8.4.20",
    "prettier": "2.8.1",
    "prettier-plugin-tailwindcss": "^0.2.1",
    "tailwindcss": "^3.3.1",
    "typescript": "4.9.4"
  }
}

我检查了资源,大多数时候它们与两个问题有关。

  1. 使用默认导出但导入命名模块。这不是我的情况,正如您根据预览看到的那样,还有组件在运行时工作的事实。
  2. 不使用函数返回实际的 JSX(常量组件 = )。这也不是我的情况,但错误也略有不同,因为它说它 git
    object
    而不是未定义。

所以这些对我的情况都没有帮助。我还看到这可能是使用路径别名时的问题,您可以将路径别名添加到 tsconfig.json 中的

path
并在 jest.config.json 中进行修改。但是因为我没有使用路径别名,所以我认为它不相关。

有趣的是,我尝试使用来自 Nextjs 样板的 repo 进行测试并且它有效。但是我的应用程序已经变得很大,可以重新开始了。

我尝试过的其他一些选择是:

  1. 在顶部导入反应。
  2. export default
    移动到底部。

这些都没有帮助。

typescript next.js jestjs config
1个回答
0
投票

所以,我设法找到了根本原因。

问题并不像最初想象的那样出现在导入或别名中。问题是我正在使用

@svgr/webpack
将 .svg 文件转换为反应组件。

然而,这些不是 JSX 组件,它们在测试中抛出错误,因为 Jest 不知道如何解析 svg 导入。

对于遇到类似问题的任何人,这里是修复程序。

  1. 创建一个你想使用的模拟 svg。就我而言,我使用以下代码创建了文件夹
    __mocks__/svg.tsx

    import React, { SVGProps } from 'react';

    const SvgrMock = React.forwardRef<SVGSVGElement, SVGProps<SVGSVGElement>>(
      (props, ref) => <svg ref={ref} {...props} />
    );

    export const ReactComponent = SvgrMock;
    export default SvgrMock;

  1. 将配置添加到
    jest.config.mjs
  moduleNameMapper: {
    '^.+\\.(svg)$': '<rootDir>/__mocks__/svg.tsx',
  },

此配置解析导入到模拟 svg,如果有任何组件用于开玩笑,以便您可以测试功能。

我希望它能帮助遇到类似问题的任何人。

© www.soinside.com 2019 - 2024. All rights reserved.