1

I am completely new to both react and testing and am a bit stumped. I was just wondering if someone could tell me why my test fails. I assume I making a basic mistake in how this should work. I am trying to test a log in page. At the moment I am just trying to get my test to fire an onclick from a button and check that that a function has been called.

The log in component code can be seen below.

import React, { Component, Fragment } from "react";
import { Redirect } from "react-router-dom";

// Resources
//import logo from "assets/img/white-logo.png";
//import "./Login.css";

// Material UI
import {
  withStyles,
  MuiThemeProvider,
  createMuiTheme
} from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import TextField from "@material-ui/core/TextField";
import Person from "@material-ui/icons/Person";
import InputAdornment from "@material-ui/core/InputAdornment";

// Custom Components
import Loading from "components/Loading/Loading.jsx";

// bootstrat 1.0
import { Alert, Row } from "react-bootstrap";

// MUI Icons
import LockOpen from "@material-ui/icons/LockOpen";

// remove
import axios from "axios";

// API
import api2 from "../../helpers/api2";

const styles = theme => ({
  icon: {
    color: "#fff"
  },
  cssUnderline: {
    color: "#fff",
    borderBottom: "#fff",
    borderBottomColor: "#fff",

    "&:after": {
      borderBottomColor: "#fff",
      borderBottom: "#fff"
    },
    "&:before": {
      borderBottomColor: "#fff",
      borderBottom: "#fff"
    }
  }
});

const theme = createMuiTheme({
  palette: {
    primary: { main: "#fff" }
  }
});

class Login extends Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      username: "",
      password: "",
      isAuthenticated: false,
      error: false,
      toggle: true,

      // loading
      loading: false
    };
  }

  openLoading = () => {
    this.setState({ loading: true });
  };

  stopLoading = () => {
    this.setState({ loading: false });
  };

  toggleMode = () => {
    this.setState({ toggle: !this.state.toggle });
  };

  handleReset = e => {
    const { username } = this.state;

    this.openLoading();
    api2
      .post("auth/admin/forgotPassword", { email: username })
      .then(resp => {
        this.stopLoading();
        console.log(resp);
      })
      .catch(error => {
        this.stopLoading();
        console.error(error);
      });
  };

  handleSubmit = event => {
    event.preventDefault();
    localStorage.clear();
    const cred = {
      username: this.state.username,
      password: this.state.password
    };

    api2
      .post("auth/admin", cred)
      .then(resp => {
        console.log(resp);
        localStorage.setItem("api_key", resp.data.api_key);
        localStorage.setItem("username", cred.username);
        return this.setState({ isAuthenticated: true });
      })
      .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);
        return this.setState({ error: true });
      });
  };

  handleInputChange = event => {
    const target = event.target;
    const value = target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  };

  forgotPassword = () => {
    console.log("object");
  };

  render() {
    const { error } = this.state;

    const { isAuthenticated } = this.state;

    const { classes } = this.props;

    if (isAuthenticated) {
      return <Redirect to="/home/dashboard" />;
    }

    return (
      <div className="login-page">
        <video autoPlay muted loop id="myVideo">
          <source
            src=""
            type="video/mp4"
          />
        </video>

        <div className="videoOver" />
        <div className="midl">
          <Row className="d-flex justify-content-center">
             <img src={''} className="Login-logo" alt="logo" />
          </Row>
          <br />
          <Row className="d-flex justify-content-center">
            {error && (
              <Alert style={{ color: "#fff" }}>
                The username/password entered is incorrect. Try again!
              </Alert>
            )}
          </Row>
          <MuiThemeProvider theme={theme}>
            <Row className="d-flex justify-content-center">
              <TextField
                id="input-username"
                name="username"
                type="text"
                label="username"
                value={this.state.username}
                onChange={this.handleInputChange}
                InputProps={{
                  className: classes.icon,
                  startAdornment: (
                    <InputAdornment position="start">
                      <Person className={classes.icon} />
                    </InputAdornment>
                  )
                }}
              />
            </Row>

            {this.state.toggle ? (
              <Fragment>
                <br />

                <Row className="d-flex justify-content-center">
                  <TextField
                    id="input-password"
                    name="password"
                    type="password"
                    label="pasword"
                    value={this.state.password}
                    onChange={this.handleInputChange}
                    className={classes.cssUnderline}
                    InputProps={{
                      className: classes.icon,
                      startAdornment: (
                        <InputAdornment position="start">
                          <LockOpen className={classes.icon} />
                        </InputAdornment>
                      )
                    }}
                  />
                </Row>
              </Fragment>
            ) : (
              ""
            )}
          </MuiThemeProvider>
          <br />

          <Row className="d-flex justify-content-center">
            {this.state.toggle ? (
              <Button
                className="button login-button"
                data-testid='submit'
                type="submit"
                variant="contained"
                color="primary"
                onClick={this.handleSubmit}
                name = "logIn"
              >
                Login
              </Button>
            ) : (
              <Button

                className="button login-button"
                type="submit"
                variant="contained"
                color="primary"
                onClick={this.handleReset}
              >
                Reset
              </Button>
            )}
          </Row>
          <Row className="d-flex justify-content-center">
            <p onClick={this.toggleMode} className="text-link">
              {this.state.toggle ? "Forgot password?" : "Login"}
            </p>
          </Row>
        </div>
        <Loading open={this.state.loading} onClose={this.handleClose} />
      </div>
    );
  }
}

export default withStyles(styles)(Login);

My current test which fails.

import React from 'react'
import {render, fireEvent, getByTestId} from 'react-testing-library'
import Login from './login'
describe('<MyComponent />', () => {
  it('Function should be called once', () => {
    const functionCalled = jest.fn()
    const {getByTestId} = render(<Login handleSubmit={functionCalled} />)
    const button = getByTestId('submit');
    fireEvent.click(button);
    expect(functionCalled).toHaveBeenCalledTimes(1)
    });
});
4

1 回答 1

1

我对 React 测试库也很陌生,但看起来你的按钮正在使用this.handleSubmit,所以将你的模拟函数作为道具传递不会做任何事情。如果您要从某个容器中传递 handleSubmit,那么我相信您的测试(正如您目前拥有的那样)会通过。

于 2019-03-13T21:40:59.597 回答