最近的项目使用阿里umijs框架,在做Unit Test时遇到了一些问题,在此记录一下,以供日后查阅。
创建Umi项目 使用以下命令创建一个新的Umi项目,项目模版选择ant-design-pro
,npm client选择npm
,npm registry选择npm
。
生成jest配置 Umi的方便之处是可以一键生成jest
配置,只需运行如下命令即可:
运行测试 使用以下命令运行测试
这时如果不出意外,你会遇到第一个错误:
第一个错误 1 2 3 Error: Jest: Failed to parse the TypeScript config file D:\personal\codes\react\umi-app-umi-jest\jest.config.ts TSError: ⨯ Unable to compile TypeScript: error TS5095: Option 'bundler' can only be used when 'module' is set to 'preserve' or to 'es2015' or later.
看提示信息大概能猜到问题的原因,就是tsconfig.json
中的moduleResolution
配置与module
配置之间有冲突。解决办法是修改moduleResolution
的配置。打开项目根目录下的tsconfig.json
文件,并设置moduleResolution
为node
,如下所示:
1 2 3 4 5 6 { "extends" : "./src/.umi/tsconfig.json" , "compilerOptions" : { "moduleResolution" : "node" } }
再次运行测试npm test
,这时会遇到第二个错误:
第二个错误 1 AssertionError [ERR_ASSERTION]: Invalid config keys: antd, access, model, initialState, request, layout
这是因为我们的项目模板是ant-design-pro
,自动集成了max,所以应该使用max来生成jest配置。 首先删除jest.config.ts
文件,然后使用以下命令重新生成jest配置:
再次运行测试,已经没有错误了,但是会提示没有测试用例,所以我们添加一个测试用例。
我们在src/pages
下添加一个login
目录,并在该目录下添加一个index.tsx
文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 import { LockOutlined , UserOutlined } from '@ant-design/icons' ;import { history } from '@umijs/max' ;import { Button , Card , Form , Input , message } from 'antd' ;import React from 'react' ;import styles from './index.less' ;interface LoginParams { username : string ; password : string ; } const LoginPage : React .FC = () => { const [form] = Form .useForm (); const [loading, setLoading] = React .useState (false ); const handleSubmit = async (values : LoginParams ) => { try { setLoading (true ); console .log ('Login attempt with:' , values); await new Promise (resolve => setTimeout (resolve, 1000 )); message.success ('Login successful!' ); history.push ('/' ); } catch (error) { message.error ('Login failed. Please check your credentials.' ); console .error ('Login error:' , error); } finally { setLoading (false ); } }; return ( <div className ={styles.container} > <Card className ={styles.loginCard} title ="Login" bordered ={false} > <Form form ={form} name ="login" layout ="vertical" requiredMark ={false} onFinish ={handleSubmit} > <Form.Item name ="username" rules ={[{ required: true , message: 'Please enter your username !' }]} > <Input prefix ={ <UserOutlined /> } placeholder="Username" size="large" /> </Form.Item > <Form.Item name ="password" rules ={[{ required: true , message: 'Please enter your password !' }]} > <Input.Password prefix ={ <LockOutlined /> } placeholder="Password" size="large" /> </Form.Item > <Form.Item > <Button type ="primary" htmlType ="submit" size ="large" block loading ={loading} > Log in </Button > </Form.Item > </Form > </Card > </div > ); }; export default LoginPage ;
然后添加一个样式文件index.less
,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 .container { display : flex; justify-content : center; align-items : center; min-height : 100vh ; background-color : #f0f2f5 ; } .loginCard { width : 100% ; max-width : 400px ; :global { .ant-card-head-title { text-align : center; font-size : 24px ; font-weight : 500 ; } } }
最后再添加一个测试用例index.test.tsx
,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 import { render, screen } from '@testing-library/react' ;import LoginPage from './index' ;describe ('LoginPage' , () => { it ('renders the login form correctly' , () => { render (<LoginPage /> ); expect (screen.getByPlaceholderText ('Username' )).toBeInTheDocument (); expect (screen.getByPlaceholderText ('Password' )).toBeInTheDocument (); expect (screen.getByRole ('button' , { name : /log in/i })).toBeInTheDocument (); }); });
再次运行测试,这时候你会遇到第三个错误:
第三个错误 1 TypeError: window.matchMedia is not a function
解决办法:在项目根目录下的jest.setup.ts
文件中添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 Object .defineProperty (window , 'matchMedia' , { writable : true , value : (query : unknown ) => ({ matches : false , media : query, onchange : null , addListener : () => { }, removeListener : () => { }, addEventListener : () => { }, removeEventListener : () => { }, dispatchEvent : () => { }, }) });
再次运行测试,这时候已经没有错误了,感谢您的观看,祝您编程愉快!