4

我正在尝试为控制器编写单元测试,它是用 react-native 和 expo 编写的 以下是单元测试失败的登录方法

登录.tsx

import React, { useState } from 'react';
import { StyleSheet, SafeAreaView, Text, Button, Image, View, Alert, TouchableWithoutFeedback, TouchableOpacity, NativeSyntheticEvent, TextInputChangeEventData, TextInput } from 'react-native';
import axios from "axios"
import { StackNavigationProp } from '@react-navigation/stack';
import { RouteProp } from '@react-navigation/native';
import { RootStackParamList } from '~/navigations/Navigations'

interface props {
    navigation: StackNavigationProp<RootStackParamList, 'Login'>;
    route: RouteProp<RootStackParamList, 'Login'>;
    value: string;
    name: string;
}

const instance = axios.create({
    baseURL: '',
    timeout: 3000,
    timeoutErrorMessage: 'do again',
});

const Login: React.FC<props> = ({ value, name, ...props }) => {

    const [inputValue, setInputValue] = useState({
        email: "",
        pwd: ""
    });

    const [errorMesseage, setErrorMesseage] = useState("");

    const onChangeText = (e: string, name: string): void => {

        let input = e;

        setInputValue(prev => ({
            ...prev,
            [name]: input,
        }));

        if (name === "email") {
            const emailRegx = /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{3}$/i;

            const emailList = ["naver.com", "gmail.com", "daum.net", "nante.com", "hanmail.net"];

            let eMailAddress = input.slice(input.indexOf('@') + 1, input.length);
            let eMailboolean = emailList.includes(eMailAddress) && name === 'email';

            setErrorMesseage(eMailboolean && emailRegx.test(input) ? "" : "eamil regx");

        }

    }

    const loginButton = async () => {

        if (errorMesseage.length === 0) {

            props.navigation.navigate("Main");

            try {

                const emailPost = await instance.post("/user", {
                    "email": inputValue.email,
                    "password": inputValue.pwd
                });

                console.log(emailPost);

            } catch (error) {
                if (error.response) {

                    console.log(error.response.data);
                    console.log(error.response.status);
                    console.log(error.response.headers);

                } else if (error.request) {

                    console.log(error.request);

                } else {

                    console.log('Error', error.message);

                }

                console.log(error.config);
            }

        } else {
            Alert.alert("email regx");
        }

    }

    return (
        <>
            <SafeAreaView style={styles.container} >
                <View>
                    <View>
                        <TextInput onChangeText={text => onChangeText(text, 'email')} placeholder="email" placeholderTextColor={"#eee"} value={inputValue["email"]} autoCorrect={false} secureTextEntry={false} autoCapitalize="none" />
                    </View>

                    <Text>{errorMesseage}</Text>
                    <View>
                        <TextInput onChangeText={e => onChangeText(e, 'pwd')} placeholder="pwd" placeholderTextColor={"#eee"} value={inputValue["pwd"]} autoCorrect={false} secureTextEntry={true} autoCapitalize="none" />
                    </View>
                    <TouchableOpacity style={[styles.loginButton, { opacity: (!errorMesseage) && inputValue.pwd ? 1 : 0.3 }]} disabled={(!errorMesseage) && inputValue.pwd ? false : true} onPress={loginButton} >
                        <Text style={styles.loginText}>login</Text>
                    </TouchableOpacity>

                    <TouchableWithoutFeedback
                        onPress={() => props.navigation.navigate("Find")}
                    >
                        <Text>pwd find</Text>
                    </TouchableWithoutFeedback>
                </View>
            </SafeAreaView >
        </>
    );
};

export default Login;

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center',
    },
    loginButton: {
        backgroundColor: "#0095F6",
    },
    loginText: {
        textAlign: "center",
        color: "#fff"
    }
});

上面代码的单元测试是用 react-native 和 expo 编写的

登录.test.tsx

import { TextInput, SafeAreaView, TouchableOpacity, TouchableWithoutFeedback, View, Text } from 'react-native';
import React from 'react';
import { render, cleanup, fireEvent } from 'react-native-testing-library';
import '@testing-library/jest-dom/extend-expect'
import TestRenderer from 'react-test-renderer';
import Login from "../src/screen/login/Index";

afterEach(cleanup);

const createTestProps = (props: Object) => ({
    navigation: {
        navigate: jest.fn()
    },
    ...props
});


describe("Login page rendering test", () => {

    jest.useFakeTimers()

    let props: any;
    let rerender: any;
    let testRenderer: any;
    let testInstance: any;

    beforeEach(() => {
        rerender = render(<Login {...props} />);
        testRenderer = TestRenderer.create(<Login {...props} />);
        testInstance = testRenderer.root;
    });

    test('renders Login component', () => {

        const component = rerender.toJSON();
        expect(component).toBeTruthy();
    });

    it("SafeAreaView renders", () => {

        expect(testInstance.findAllByType(SafeAreaView).length).toBe(1);
    });

    it("View renders", () => {

        expect(testInstance.findAllByType(View).length).toBe(5);
    });

    it("textInput renders", () => {

        const expectedPlaceholder = ['email', 'pwd'];

        expect(testInstance.findAllByType(TextInput).length).toBe(2);
        expectedPlaceholder.forEach((text: string) => {
            rerender.findByPlaceholder(text);
        });
    });

    it("TouchableOpacity renders", () => {

        const element = testInstance.findByType(TouchableOpacity).findByType(Text);

        expect(testInstance.findAllByType(TouchableOpacity).length).toBe(1);
        expect(element.props.children).toEqual('login');


    });

    it("TouchableWithoutFeedback renders", () => {

        const element = testInstance.findByType(TouchableWithoutFeedback).findByType(Text);

        expect(testInstance.findAllByType(TouchableWithoutFeedback).length).toBe(1);
        expect(element.props.children).toEqual('pwd find');
    });


});

describe('login page funtion test', () => {

    let props: any;
    let rerender: any;

    beforeEach(() => {


        props = {
            onChangeText: jest.fn(),
        }

        rerender = render(<Login {...props} />);

        emailInput = rerender.getByPlaceholder('email');

        fireEvent.changeText(emailInput, 'ab');

    });

    it('email input change', async () => {

        rerender.getByDisplayValue("ab");

        expect(props.onChangeText).toHaveBeenCalledWith('ab');
        expect(props.onChangeText).toHaveBeenCalledTimes(1);

    })

})

错误部分

describe('login page funtion test', () => {

    let props: any;
    let rerender: any;

    beforeEach(() => {


        props = {
            onChangeText: jest.fn(),
        }

        rerender = render(<Login {...props} />);

        emailInput = rerender.getByPlaceholder('email');

        fireEvent.changeText(emailInput, 'ab');

    });

    it('email input change', async () => {

        rerender.getByDisplayValue("ab");

        expect(props.onChangeText).toHaveBeenCalledWith('ab');
        expect(props.onChangeText).toHaveBeenCalledTimes(1);

    })

})

我收到以下错误。需要知道我在这里缺少什么吗?

 expect(jest.fn()).toHaveBeenCalledWith(...expected)

    Expected: "ab"

    Number of calls: 0

      116 | 
    > 117 |         expect(props.onChangeText).toHaveBeenCalledWith('ab');
          |                                    ^
      118 |         expect(props.onChangeText).toHaveBeenCalledTimes(1);
      119 | 
      120 |     })

图书馆

"expo": "^37.0.12",
"jest-dom": "^4.0.0",
"react": "~16.9.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz",
"react-test-renderer": "^16.13.1",
"react-native-testing-library": "^2.1.0",
4

0 回答 0