使用 jest 和 ionic 为 reactjs 组件编写测试覆盖率

问题描述

我正在尝试为使用 ionic react 实现的注册组件编写测试覆盖率。我有一个提交功能submitRegistration();,一旦填写了表单字段,它就会处理表单提交。但是,我无法通过测试来覆盖整个功能实现。 这是我的组件:

imports...

const Registration: React.FC = () => {

    /*Start Hooks*/
    const [name,setName] = useState('')
    const [surname,setSurname] = useState('')
    const [phone,setPhone] = useState('')
    const [birthdate,setBirthdate] = useState('')
    const [email,setEmail] = useState('')
    const [emailVerify,setEmailVerify] = useState('')
    const [password,setPassword] = useState('')
    const [passwordVerify,setPasswordVerify] = useState('')
    const [checkedTerms,setCheckedTerms] = useState(false)
    const [checkedGDPR,setCheckedGDPR] = useState(false)
    const [checkedCaptcha,setCheckedCaptcha] = useState('')
    const [error,setError] = useState('')
    const [showLoading,setShowLoading] = useState(false)
    //Modals for terms and Conditions and GDPR
    const [showGDPRModal,setShowGDPRModal] = useState(false)
    const [showTermsAndConditionsModal,setShowTermsAndConditionsModal] = useState(false)


    const history = useHistory()
    const maxLengthInput = 25

    function onChange(value: any) {
        //console.log("Captcha value:",value);
        if (value === null) setCheckedCaptcha('')
        else setCheckedCaptcha(value)
    }

    const handleNameInput = (e: any) => {
        setName(e.target.value)
    }
    const handleSurnameInput = (e: any) => {
        setSurname(e.target.value)
    }
    const handlePhoneInput = (e: any) => {
        setPhone(e.target.value)
    }
    const handleBirthdateInput = (e: any) => {
        setBirthdate(e.detail.value)
    }
    const handleEmailInput = (e: any) => {
        setEmail(e.target.value)
    }
    const handleEmailVerifyInput = (e: any) => {
        setEmailVerify(e.target.value)
    }
    const handlePasswordInput = (e: any) => {
        setPassword(e.target.value)
    }
    const handlePasswordVerifyInput = (e: any) => {
        setPasswordVerify(e.target.value)
    }
    const toggleButton = () => {
        return !name || !surname || !birthdate || !phone || !email || !emailVerify || !password || !passwordVerify || !checkedTerms || !checkedCaptcha || !checkedGDPR
    }
    function checkBirthdate18() {
        const years = moment().diff(birthdate,'years',true)
        if (years >= 18) return true

        return false
    }
    function checkEqualEmail() {
        return email === emailVerify
    }
    function checkEqualPassword() {
        return password === passwordVerify
    }

    function createuser() {
        return Service.registrationControllerRegistrationProcess({
            email: email,emailConfirmation: emailVerify,password: password,passwordConfirmation: passwordVerify,name: name,surname: surname,birthdate: birthdate,phone: phone,termsAndConditions: checkedTerms,gdpr: checkedGDPR,captcha: checkedCaptcha,})
            .then((response: any) => {
                setShowLoading(false)
                const emailSent = true
                history.push({
                    pathname: '/login',state: emailSent,})
            })
            .catch((e) => {
                console.error('Error:',error)
                setError(e.message)
                firebase.auth().signOut()
                setShowLoading(false) //dismiss loading
            })
    }

    const submitRegistration = async () => {

        //check if name is not empty. Should never happen
        if (!name) {
            setError('Name is empty.')
            return
        }
        //check if name is not empty. Should never happen
        if (!surname) {
            setError('Surname is empty.')
            return
        }
        //check if phone number is not empty. Should never happen
        if (!phone) {
            setError('Phone number is empty.')
            return
        }
        //check if birthdate is not empty. Should never happen
        if (!birthdate) {
            setError('Birthdate is empty')
            return
        }
        if (!checkBirthdate18()) {
            setError('You must be at least 18 years old')
            return
        }

        //check if email is not empty. Should never happen
        if (!email) {
            setError('Email is empty.')
            return
        }
        //check if emailVerify is not empty. Should never happen
        if (!emailVerify) {
            setError('Email confirmation is empty.')
            return
        }
        //Check if emails are the same
        if (!checkEqualEmail()) {
            setError('Email and Email confirmation must be equal.')
            return
        }

        //check if password is not empty. Should never happen
        if (!password) {
            setError('Password is empty.')
            return
        }
        //check if passwordVerify is not empty. Should never happen
        if (!passwordVerify) {
            setError('Password confirmation is empty.')
            return
        }
        //Check if password supplied are the same
        if (!checkEqualPassword()) {
            setError('Password and Password confirmation must be equal')
            return
        }
        //Password strong enough
        // One number 
        // One symbol 
        // At least 8 characters 
        // Personal data of the user
        // Create a schema
        const schema = new passwordValidator()
        // Add properties to it
        schema
            .is().min(8)                                    // Minimum length 8
            .is().max(20)                                   // Maximum length 20
            .has().symbols(1)                               // Must have at leasst 1 symbols
            .has().digits(1)                                // Must have at least 1 digits
            .has().not().spaces()                           // Should not have spaces
            .is().not().oneOf([name,surname,email]) // Blacklist these values

        const validator = schema.validate(password,{ list: true })
        if (validator.length) {
            //Password not strong enough
            setError('Password must have: \n at least 8 chars \n 1 symbol \n 1 digit \n no spaces \n no your name \n no your surname \n no your email')
            return
        }
        //check if Terms is not empty. Should never happen
        if (!checkedTerms) {
            setError('Terms and Conditions must be checked.')
            return
        }

        if (!checkedGDPR) {
            setError('GDPR must be checked.')
            return
        }
        

        //Enable loading
        setShowLoading(true)
        setError('')

        //Create user
        createuser()
    }

    const dismissGDPRModal = () => {
        setShowGDPRModal(false)
        setCheckedGDPR(false)
    }

    const dismissGDPRModalWithAcceptance = () => {
        setShowGDPRModal(false)
        setCheckedGDPR(true)
    }

    const clickGDPRLink = (event: any) => {
        event.preventDefault()
        //Show GDPR modal
        setShowGDPRModal(true)
    }

    const dismisstermsAndConditionsModal = () => {
        setShowTermsAndConditionsModal(false)
        setCheckedTerms(false)
    }

    const dismisstermsAndConditionsModalWithAcceptance = () => {
        setShowTermsAndConditionsModal(false)
        setCheckedTerms(true)
    }

    const clickTermsAndConditionsLink = (event: any) => {
        event.preventDefault()
        //Show terms and conditions modal
        setShowTermsAndConditionsModal(true)
    }

    return (
      <IonPage>
        <IonHeader>
          <IonToolbar>
            <IonTitle data-testid="title">Sign up</IonTitle>
            <IonText
              data-testid="account-exists"
              className="ion-padding"
              slot="end"
            >
              Do you already have an account?{" "}
              <IonRouterLink data-testid="login-page" href="/login">
                Sign in
              </IonRouterLink>
            </IonText>
          </IonToolbar>
        </IonHeader>
        <IonContent fullscreen>
          <IonModal isOpen={showGDPRModal}>
            <GDPRModal />
            <IonItem>
              <IonButton
                data-testid="cancel"
                slot="end"
                onClick={() => dismissGDPRModal()}
              >
                Cancel
              </IonButton>
              <IonButton
                data-testid="accept"
                class="no-left-padding"
                slot="end"
                onClick={() => dismissGDPRModalWithAcceptance()}
              >
                Accept
              </IonButton>
            </IonItem>
          </IonModal>

          <IonModal isOpen={showTermsAndConditionsModal}>
            <TermsAndConditionsModal />
            <IonItem>
              <IonButton
                data-testid="cancel-gdpr"
                slot="end"
                onClick={() => dismisstermsAndConditionsModal()}
              >
                Cancel
              </IonButton>
              <IonButton
                data-testid="accept-gdpr"
                class="no-left-padding"
                slot="end"
                onClick={() => dismisstermsAndConditionsModalWithAcceptance()}
              >
                Accept
              </IonButton>
            </IonItem>
          </IonModal>
          <IonLoading isOpen={showLoading} message={"Please wait..."} />
          <IonHeader collapse="condense">
            <IonToolbar>
              <IonTitle data-testid="sign-up" size="large">
                Sign up
              </IonTitle>
            </IonToolbar>
          </IonHeader>
          <form
            data-testid="submit-form"
            onSubmit={(e) => {
              e.preventDefault();
              submitRegistration();
            }}
          >
            <IonGrid>
              <IonItemGroup class="ion-margin">
                <IonItemDivider>
                  <IonLabel data-testid="personal-info">
                    Personal information
                  </IonLabel>
                </IonItemDivider>
                {/* Start First row */}
                <IonRow>
                  <IonCol>
                    <IonItem>
                      <IonLabel data-testid="name" position="floating">
                        Name
                      </IonLabel>
                      <IonInput
                        name="name"
                        title="Name"
                        maxlength={maxLengthInput}
                        value={name}
                        onIonInput={(e: any) => handleNameInput(e)}
                      />
                    </IonItem>
                  </IonCol>
                  <IonCol>
                    <IonItem>
                      <IonLabel data-testid="surname" position="floating">
                        Surname
                      </IonLabel>
                      <IonInput
                        name="surname"
                        title="Surname"
                        value={surname}
                        onIonInput={(e: any) => handleSurnameInput(e)}
                      />
                    </IonItem>
                  </IonCol>
                </IonRow>
                {/* Start Second row */}
                <IonRow>
                  <IonCol>
                    <IonItem>
                      <IonLabel data-testid="date-of-birth" position="floating">
                        Birthdate
                      </IonLabel>
                      <IonDatetime
                        title="Birthdate"
                        value={birthdate}
                        onIonChange={(e: any) => handleBirthdateInput(e)}
                      />
                    </IonItem>
                  </IonCol>
                  <IonCol>
                    <IonItem>
                      <IonLabel data-testid="phone" position="floating">
                        Phone
                      </IonLabel>
                      <IonInput
                        type="tel"
                        title="Phone"
                        name="phone"
                        value={phone}
                        onIonInput={(e: any) => handlePhoneInput(e)}
                      />
                    </IonItem>
                  </IonCol>
                </IonRow>
              </IonItemGroup>
              {/* Start Third row */}
              <IonItemGroup class="ion-margin">
                <IonItemDivider>
                  <IonLabel data-testid="email-info">
                    Email information
                  </IonLabel>
                </IonItemDivider>
                <IonRow>
                  <IonCol>
                    <IonItem>
                      <IonLabel data-testid="email" position="floating">
                        Email
                      </IonLabel>
                      <IonInput
                        title="Email"
                        type="email"
                        value={email}
                        onIonInput={(e: any) => handleEmailInput(e)}
                      />
                    </IonItem>
                  </IonCol>
                </IonRow>
                <IonRow>
                  <IonCol>
                    <IonItem>
                      <IonLabel
                        position="floating"
                        data-testid="email-confirmation"
                      >
                        Email Confirmation
                      </IonLabel>
                      <IonInput
                        title="Email Confirmation"
                        type="email"
                        value={emailVerify}
                        onIonInput={(e: any) => handleEmailVerifyInput(e)}
                      />
                    </IonItem>
                  </IonCol>
                </IonRow>
              </IonItemGroup>
              <IonItemGroup class="ion-margin">
                <IonItemDivider>
                  <IonLabel data-testid="password-info">
                    Password information
                  </IonLabel>
                </IonItemDivider>
                <IonRow>
                  <IonCol>
                    <IonItem>
                      <IonLabel position="floating" data-testid="password">
                        Password
                      </IonLabel>
                      <IonInput
                        title="Password"
                        type="password"
                        value={password}
                        onIonInput={(e: any) => handlePasswordInput(e)}
                      />
                    </IonItem>
                  </IonCol>
                </IonRow>
                <IonRow>
                  <IonCol>
                    <IonItem>
                      <IonLabel
                        position="floating"
                        data-testid="password-confirmation"
                      >
                        Password Confirmation
                      </IonLabel>
                      <IonInput
                        title="Password Confirmation"
                        type="password"
                        value={passwordVerify}
                        onIonChange={(e: any) => handlePasswordVerifyInput(e)}
                      />
                    </IonItem>
                  </IonCol>
                </IonRow>
              </IonItemGroup>
              <IonRow>
                <IonCol>
                  <IonItem>
                    <IonLabel data-testid="agree-to-terms">
                      I agree to the{" "}
                      <IonRouterLink
                        href="#"
                        onClick={(e) => clickTermsAndConditionsLink(e)}
                      >
                        <IonText data-testid="terms" color="danger">
                          {" "}
                          Terms and Conditions{" "}
                        </IonText>{" "}
                      </IonRouterLink>{" "}
                    </IonLabel>
                    <IonCheckBox
                      checked={checkedTerms}
                      title="Terms"
                      onIonChange={(e: any) =>
                        setCheckedTerms(e.detail.checked)
                      }
                    />
                  </IonItem>
                </IonCol>
              </IonRow>
              <IonRow>
                <IonCol>
                  <IonItem>
                    <IonLabel>
                      I agree to the{" "}
                      <IonRouterLink href="#" onClick={(e) => clickGDPRLink(e)}>
                        <IonText color="danger"> GDPR </IonText>
                      </IonRouterLink>{" "}
                    </IonLabel>
                    <IonCheckBox
                      title="GDPR"
                      checked={checkedGDPR}
                      onIonChange={(e: any) => setCheckedGDPR(e.detail.checked)}
                    />
                  </IonItem>
                </IonCol>
              </IonRow>
              <IonRow>
                <IonCol className="ion-text-center">
                  {/* Captcha */}
                  <ReCAPTCHA
                    data-testid="recaptcha"
                    sitekey={process.env.REACT_APP_RECAPTCHA_KEY!}
                    onChange={onChange}
                  />
                </IonCol>
              </IonRow>
            </IonGrid>
            <div className="ion-text-center">
              <p className="redColor"> {error} </p>
            </div>
            <IonButton
              disabled={toggleButton()}
              className="ion-margin"
              type="submit"
              expand="block"
              data-testid="register"
            >
              Continue
            </IonButton>
          </form>
        </IonContent>
      </IonPage>
    );
}

export default Registration

这是代码覆盖率的快照:

Snapshot of test coverage

更新: 这是我写的用来处理注册表单测试的测试:

it("onSubmit to have been called",async () => {
    const mock = jest.fn();
     const { findByTitle,getByTestId,findByTestId,findByText } = render(<Registration />);

     const name = await findByTitle("Name");
     const surname = await findByTitle("Surname");
     const email = await findByTitle("Email");
     const emailConfirm = await findByTitle("Email Confirmation");
     const password = await findByTitle("Password");
     const birthdate = await findByTitle("Birthdate");
     const phone = await findByTitle("Phone");
     const passwordConfirm = await findByTitle("Password Confirmation");
     const termsAndConditions = await findByTitle("Terms");
   

     const button = await findByText("Continue");

     fireEvent.ionInput(name,"name");
     fireEvent.ionInput(surname,"surname");
 fireEvent.ionInput(email,“my email");
     fireEvent.ionInput(emailConfirm,"my email");
     fireEvent.ionChange(birthdate,"date of birth");
     fireEvent.ionInput(phone,"121212121212");
     fireEvent.ionInput(password,"pass123");
     fireEvent.ionChange(passwordConfirm,"pass123");
     fireEvent.ionChange(termsAndConditions,"true");

     fireEvent.click(button);
    const form = getByTestId("submit-form");
    fireEvent.submit(form);
    expect(mock).not.toHaveBeenCalled();

  });

感谢任何帮助或建议。 谢谢

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...