[英]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.