Next.js项目引入react-quill后Jest测试报错求助
使用Jest和react-testing-library测试Next.js应用时,原本正常的测试在加入react-quill组件后出现以下错误:
"Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of
ForwardRef(LoadableComponent)."
"Error: Uncaught [Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object."
我通过Next.js的dynamic方法动态导入react-quill(设置ssr: false),并在react-hook-form的表单中使用该组件,代码示例如下:
import FormItemInner from "../../ui/reusable/customForm/FormItemInner" import React, { FC, useState, useEffect } from 'react'; import dynamic from 'next/dynamic'; import { Controller } from "react-hook-form"; import { Form } from "react-bootstrap"; import ReportAttachment from "./ReportAttachment"; import { ValidationMessage } from "../../ui/reusable/Reusable"; const QuillNoSSRWrapper: any = dynamic(import('react-quill'), { ssr: false, loading: () => <p>Loading ...</p>, }) const ProofOfConcept: FC<{ getFiles: any, register: any, errors: any, control: any, translate: any, authTranslate: any }> = ({ getFiles, register, errors, control, translate, authTranslate }) => { const [loaded, setLoaded] = useState(false); useEffect(() => { setLoaded(true) }, []) return ( <div style={{ borderTop: '1px solid #BCBCBC59', paddingTop: '1rem' }}> <FormItemInner title={translate("impactTitle")} required description={translate('reportImpactDescription')}> <Form.Control className="mb-4 gray_input" id="inputReportImpact" data-testid="inputReportImpact" type="name" {...register("impact", { required: true, })} /> {errors?.impact?.type === "required" && ( <ValidationMessage message={authTranslate("RequiredField")} /> )} </FormItemInner> <FormItemInner title={translate("summaryTitle")} required description={translate('reportSummaryDescription')}> <Controller name="summary" control={control} render={({ field: { onChange, value }, }) => ( <QuillNoSSRWrapper className="wrapperClassName mb-4" theme="snow" value={value} onChange={onChange} /> )} /> </FormItemInner> <FormItemInner title={translate("recommendationTitle")} required description={translate('reportRecommendationDescription')}> <Controller name="recommendation" control={control} render={({ field: { onChange, value } }) => ( <QuillNoSSRWrapper className="wrapperClassName mb-4" theme="snow" value={value} onChange={onChange} /> )} /> </FormItemInner> <FormItemInner title={translate("attachmentTitle")} description={translate('reportAttachmentDescription')}> <ReportAttachment getFiles={getFiles} translate={translate} /> </FormItemInner> </div > ) } export default ProofOfConcept
这个错误源于Jest无法正确处理Next.js禁用SSR的动态导入组件,以下是三种可行的解决方式:
方法1:模拟react-quill组件
在测试文件顶部添加模拟代码,让Jest使用一个简易的替代组件,跳过真实Quill的加载逻辑:
jest.mock('react-quill', () => { return () => <div data-testid="mock-quill-editor" />; });
这种方式简单高效,适合不需要测试Quill编辑器具体功能的场景。
方法2:修正动态导入的写法
react-quill的导出是默认导出,动态导入时需要明确指定获取默认导出,避免因导入方式导致组件类型错误:
const QuillNoSSRWrapper: any = dynamic(() => import('react-quill').then(mod => mod.default), { ssr: false, loading: () => <p>Loading ...</p>, });
方法3:等待动态组件加载完成
如果需要测试真实的Quill组件行为,可在测试中使用waitFor等待动态组件加载完毕:
import { render, waitFor } from '@testing-library/react'; test('验证Quill编辑器渲染', async () => { const { getByTestId } = render(<ProofOfConcept {...你的props参数} />); await waitFor(() => expect(getByTestId('mock-quill-editor')).toBeInTheDocument()); });
注意:这种方式需要确保测试环境支持Quill的DOM依赖,若遇到环境兼容问题,还是推荐使用模拟组件的方式。
内容的提问来源于stack exchange,提问作者mostafa elbanna

