[英]Yup and Formik not validating form when testing with Jest and React Testing Library
我最近将 Jest 更新为最新的 28. 版本,我的单元测试停止工作,特别是在使用 Yup 和 Formik 验证我的表单并显示错误消息的测试中。 如果我回滚 Jest 版本,它确实可以正常工作。
这是我的 package.json 依赖项
"dependencies": {
"@chakra-ui/icons": "^1.0.16",
"@chakra-ui/react": "^1.6.10",
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@types/styled-components": "^5.1.15",
"axios": "^0.24.0",
"formik": "^2.2.9",
"framer-motion": "^4.1.17",
"graphql": "^16.3.0",
"graphql-request": "^4.0.0",
"next": "^12.2.0",
"next-i18next": "^10.2.0",
"nookies": "^2.5.2",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-icons": "^4.3.1",
"react-number-format": "^4.9.3",
"react-query": "^3.34.6",
"styled-components": "^5.3.3",
"yup": "^0.32.11"
},
"devDependencies": {
"@testing-library/dom": "^8.16.0",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "^7.0.2",
"@testing-library/user-event": "^13.5.0",
"@types/node": "18.0.5",
"@types/react": "17.0.33",
"eslint": "7.32.0",
"eslint-config-next": "12.0.1",
"eslint-config-prettier": "^8.3.0",
"jest": "^28.1.3",
"jest-environment-jsdom": "^28.1.3",
"msw": "^0.39.2",
"react-test-renderer": "^17.0.2",
"typescript": "4.4.4"
}
这是我的 jest.config.js
// jest.config.js
const nextJest = require('next/jest');
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
});
// Add any custom config to be passed to Jest
const customJestConfig = {
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleNameMapper: {
// Handle module aliases (this will be automatically configured for you soon)
'^@/components/(.*)$': '<rootDir>/components/$1',
'^@/pages/(.*)$': '<rootDir>/pages/$1',
},
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jsdom',
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);
这是我失败的测试
it('validates empty form values', async () => {
server.use(
graphql.query('GetAllProducts', (req, res, ctx) => {
return res(ctx.status(200), ctx.data(getProductsResponseBody));
})
);
const signupResult = renderWithDefaultClient(<ProductPage />);
await userEvent.click(
await signupResult.findByText('addProductButtonLabel')
);
await userEvent.click(await signupResult.findByText('createButtonLabel'));
expect(await signupResult.findByText('required')).toBeInTheDocument();
});
这是我正在测试的组件
import {
Button,
FormControl,
FormErrorMessage,
FormLabel,
HStack,
Input
} from '@chakra-ui/react';
import { Field, Form, Formik } from 'formik';
import { useTranslation } from 'next-i18next';
import React from 'react';
import * as Yup from 'yup';
import {
FormProduct,
IProduct
} from '../../interfaces/pages/product/ProductInterface';
import { returnEmptyStringIfNull } from '../../utils/StringUtils';
const ProductForm = () => {
const { t } = useTranslation(['product', 'shared']);
const ProductFormSchema = Yup.object().shape({
code: Yup.string().max(45, t('characterLimitFortyFive', { ns: 'shared' })),
name: Yup.string()
.max(45, t('characterLimitFortyFive', { ns: 'shared' }))
.required(t('required', { ns: 'shared' })),
});
const initialValues: FormProduct = {
code: returnEmptyStringIfNull(product.code),
name: returnEmptyStringIfNull(product.name),
};
const onSubmitForm = (productForm: FormProduct) => {
createMutation.mutate(productForm);
};
return (
<>
<Formik
initialValues={initialValues}
validationSchema={ProductFormSchema}
onSubmit={(form) => {
onSubmitForm(form);
}}
>
{(props) => (
<Form data-testid='productForm' style={{ marginTop: '20px' }}>
<HStack spacing={'24px'} w={'2xl'} mb={3}>
<Field name='code'>
{
// @ts-ignore
({ field, form }) => (
<FormControl
isInvalid={form.errors.code && form.touched.code}
>
<FormLabel htmlFor='code'>{t('codeLabel')}</FormLabel>
<Input {...field} id='code' data-testid='code' />
<FormErrorMessage>{form.errors.code}</FormErrorMessage>
</FormControl>
)
}
</Field>
<Field name='name'>
{
// @ts-ignore
({ field, form }) => {
return (
<FormControl
isInvalid={form.errors.name && form.touched.name}
isRequired
>
<FormLabel htmlFor='name'>{t('nameLabel')}</FormLabel>
<Input {...field} id='name' data-testid='name' />
<FormErrorMessage>{form.errors.name}</FormErrorMessage>
</FormControl>
);
}
}
</Field>
</HStack>
<HStack spacing={'24px'} mt={4}>
<Button colorScheme='blue' type='submit'>
{t('createButtonLabel', { ns: 'shared' })}
</Button>
</HStack>
</Form>
)}
</Formik>
</>
);
};
export default ProductForm;
如您所见,我正在尝试验证是否确实显示了所需的错误消息,但是在我更新 jest 并安装 jsdom 后它不起作用。
它通过安装 Jest 27.5.1 再次起作用,我所有失败的测试都是由于 formik 的错误而没有显示。
显然 JSDOM 现在正在验证 HTML5 表单输入,当它具有所需的属性集时,在我取出 ChakraUI 上的“isRequired”后它起作用了,即使这是在真实浏览器环境中所期望的,但以前的版本就像我使用的那样没有按照应有的方式验证表单。
可以在这里看到对 JSDOM 的引用: https ://github.com/jsdom/jsdom/issues/2898
做了一些搜索,我发现了这个 GitHub 问题: https://github.com/jaredpalmer/formik/issues/544
尝试将noValidate
添加到您的表单组件。 我在进行更改时通过了它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.