美文网首页
TypeScript + Jest + React-Testin

TypeScript + Jest + React-Testin

作者: NANAISNANA | 来源:发表于2020-03-19 15:38 被阅读0次

    纯Typescript测试相关配置

    1: 安装jest相关的依赖
    yarn add --dev jest @types/jest ts-jest
    

    jest -- 我们的test runner, 测试断言库, mock库
    @types/jest -- Jest的Typescript版
    ts-jest -- 把Typescript编译为JavaScript

    2:创建jest.config.js

    在项目根目录下创建一个jest.config.js文件作为jest的配置文件,且添加以下内容

    // jest.config.js
    module.exports = {
        roots: ['<rootDir>/src'],
        transform: {
            '^.+\\.tsx?$': 'ts-jest',
        },
        testRegex: '^.+\\.test\\.(ts|tsx)$',
        moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
    };
    
    3: 添加跑测试的脚本
    // package.json
    "scripts": {
        "test": "jest",
          //....
      },
    

    完成以上相关配置,我们就可以对一个Typescript纯函数进行测试了,例如以下例子:

    //stringProcessor.ts
    function reverseString(str: string) {
        return str.split('').reverse().join('');
    }
    export {reverseString}
    
    //stringProcessor.test.ts
    import {reverseString} from './stringProcessor';
    test('', ()=> {
        expect(reverseString('hello')).toBe('olleh');
    });
    

    但是,如果我们需要测一个React component测试,我们需要借助另一个库Enzyme以及相关其他依赖。接下来,让我们来完成这部分的配置:

    React测试相关配置

    安装React测试相关的依赖
    yarn add  --dev @testing-library/react @testing-library/react-hooks @testing-library/jest-dom
    

    @testing-library/react 测试React Component的库
    @testing-library/react-hooks 测试自己写的的React Hooks的库
    @testing-library/jest-dom 提供更多利于dom测试的断言

    往jest.config.js文件里面添加支持React component测试的相关配置
    //jest.config.js
    module.exports = {
        roots: ['<rootDir>/src'],
        setupFiles: ['<rootDir>/test.setup.js', '<rootDir>/test.shim.js'],
        transform: {
            '^.+\\.tsx?$': 'ts-jest',
        },
     
        moduleNameMapper: {
            '\\.(css|scss)': 'identity-obj-proxy', // mock 在react组件里import的CSS
            '\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
                '<rootDir>/testMocks/assetsMocks.js', //mock 在react组件里import的图片
        },
        testRegex: '^.+\\.test\\.(ts|tsx)$',
        moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
    };
    
    在项目根目录添加testMocks/assetsMocks.js
    //testMocks/assetsMocks.js
    module.exports = '';
    

    测试一个最简单的React组件

    组件文件counter.tsx

    //counter.tsx
    import * as React from 'react';
    import { useState } from 'react';
    
    const Counter = () => {
        const [count, setCount] = useState(0);
    
        return (
            <div>
                <div data-testid='count-announcement'> you have been clicked {count} times</div>
                <button
                    data-testid='increase-button'
                    onClick={() => {
                        setCount(count + 1);
                    }}
                >
                    {' '}
                    increase count
                </button>
            </div>
        );
    };
    export default Counter;
    
    

    测试文件counter.test.tsx

    //counter.test.tsx
    import * as React from 'react';
    import Counter from './counter';
    import { render, fireEvent } from '@testing-library/react';
    import '@testing-library/jest-dom/extend-expect';
    
    test('the count should be 1 when you click the increase button once', () => {
        // render
        const { getByTestId } = render(<Counter />);
        const increaseButton = getByTestId('increase-button');
        // act
        fireEvent.click(increaseButton);
        // assert
        expect(getByTestId('count-announcement')).toHaveTextContent('1');
    });
    
    
    测试一个有<Link>的React组件

    组件文件HomePage.tsx

    //HomePage.tsx
    import React from 'react';
    import logo from './images/logo.svg';
    import pink from './images/pink.png';
    import './HomePage.scss';
    import { Link } from 'react-router-dom';
    
    function App() {
        const name = `nana`;
        return (
            <div className='App'>
                <header className='App-header'>
                    <img src={logo} className='App-logo' alt='logo' />
                    <img src={pink} className='' alt='pink' />
                    <Link to='/blogList'>Blog List Page</Link>
                </header>
                <p data-testid='name'>name: {name}</p>
            </div>
        );
    }
    
    export default App;
    
    

    测试文件HomePage.test.tsx

    //HomePage.test.tsx
    import * as React from 'react';
    import HomePage from './HomePage';
    import { render } from '@testing-library/react';
    import '@testing-library/jest-dom/extend-expect';
    import { BrowserRouter } from 'react-router-dom';
    
    //This is testing demo to testing a react component with CSS and Images import
    test('should render name correctly', () => {
        // render
        const { getByTestId } = render(
            //对于有Link的组件,在测试的时候,必须把它包到BrowserRouter里面
            <BrowserRouter>
                <HomePage />
            </BrowserRouter>,
        );
        const name = getByTestId('name');
        // act
        // assert
        expect(name).toHaveTextContent('nana');
    });
    
    

    这里需要特别注意的是: 对于有Link的组件,在测试的时候,必须把它包到BrowserRouter里面,不然JEST会不过。

    测试一个有axios请求的组件

    组件文件profile.tsx

    //profile.tsx
    import * as React from 'react';
    import axios from 'axios';
    import { useEffect, useState } from 'react';
    
    const Profile = () => {
        const [isLoading, setIsLoading] = useState(true);
        const [username, setUsername] = useState('');
        const [errorMessage, setErrorMessage] = useState('');
    
        useEffect(() => {
            async function fetchData() {
                try {
                    const response = await axios.get('https://my-json-server.typicode.com/pengmq/mock-server/profile', {});
                    setIsLoading(false);
                    setUsername(response.data.data.username);
                } catch (error) {
                    setIsLoading(false);
                    setErrorMessage(error);
                }
            }
    
            fetchData();
        }, []);
    
        return (
            <div>
                <div data-testid='error-message'>{errorMessage}</div>
                <div data-testid='loading-text'>
                    <span>{isLoading ? 'loading....' : ''}</span>
                </div>
                <div data-testid='username'>{username}</div>
            </div>
        );
    };
    export default Profile;
    
    

    测试文件profile.test.tsx

    //profile.test.tsx
    import * as React from 'react';
    import { render, waitForElement } from '@testing-library/react';
    import Profile from './profle';
    import axios from 'axios';
    
    //jest.mock(...)自动mock axios的API调用,这行代码必须放在文件最外层,不能放到test里面
    jest.mock('axios');
    const mockedAxios = axios as jest.Mocked<typeof axios>; //This line is needed when work with typescript
    
    test('loading text should hide and user name should show after get profile data successfully from server ', async () => {
    
        //mock axios的API返回,这行代码必须在render之前
        mockedAxios.get.mockResolvedValueOnce({ data: { data: { username: 'nana' } } });
        const { getByTestId, container } = render(<Profile />);
        // awaiting for sync function to be done with  await waitForElement()
        const [loadingText, username] = await waitForElement(() => [getByTestId('loading-text'), getByTestId('username')], {
            container,
        });
        //assert dom changes
        expect(loadingText).toHaveTextContent('');
        expect(username).toHaveTextContent('nana');
    });
    
    

    相关文章

      网友评论

          本文标题:TypeScript + Jest + React-Testin

          本文链接:https://www.haomeiwen.com/subject/lotlyhtx.html