TypeError无法读取未定义的属性“状态”

时间:2019-10-24 13:43:13

标签: reactjs jestjs enzyme

我一直在这一行中收到此错误,并且不确定是什么原因使它成为玩笑/反应/酶的新手

const { from } = this.props.location.state || { from: { pathname: "/" } };

每当我尝试运行此命令时就会发生这种情况

import React from 'react';
import { shallow, mount, render } from '../../enzyme';
import Login from '../login'

describe('Login Test Suite', () => {

    it('should render the form', () => {
        const wrapper = shallow(<Login />);

        expect(wrapper.find('form').exists()).toBe(true);
        expect(wrapper.find('#userName').length).toEqual(1);
        expect(wrapper.find('#password').length).toEqual(1);
    })
})

describe('userName Test Suite', () => {

    it('should change the state of the Login component', () => {

        const wrapper = shallow(<Login />);
        wrapper.find('#userName').simulate('blur',
            {
                target: { name: 'userName', value: 'adastest' }
            });

        expect(wrapper.state('userName')).toEqual('adastest');
    })
})

describe('Password Test Suite', () => {

    it('should change the state of the Login component', () => {

        const wrapper = mount(<Login />);
        wrapper.find('#password').simulate('blur',
            {
                target: { name: 'password', value: 'adastest' }
            });

        expect(wrapper.state('password')).toEqual('adastest');
    })
})

我应该检查的任何建议/文档吗?谢谢

这也是我的登录组件

import TextField from "@material-ui/core/TextField";
import clsx from "clsx";
import Button from "@material-ui/core/Button";
import { createMuiTheme, makeStyles } from "@material-ui/core/styles";
import { ThemeProvider } from "@material-ui/styles";
import { red, grey } from "@material-ui/core/colors";
import Paper from "@material-ui/core/Paper";
import "../App.css";
import { Route, Redirect } from "react-router-dom";

var tokenUi = require("./../token-ui.js");
var fetchUi = require("./../fetch-ui.js");

const theme = createMuiTheme({
  palette: {
    primary: { main: red[900] },
    secondary: { main: grey[900] }
  }
});

const useStyles = makeStyles(theme => ({
  margin: {
    margin: theme.spacing(1)
  },
  textField: {
    flexBasis: 200
  }
}));

const AuthCentralState = {
  isAuthenticated: false,
  jwt: "",
  async authenticate(user, pass, callback) {
    let loginInfo = { password: pass, username: user };
    try {
      var response = await fetchUi.post(
        "/adas/user/checkuser",
        JSON.stringify(loginInfo),
        false
      );
      this.jwt = await response.json();

      if (this.jwt.tokenId) {
        this.isAuthenticated = true;
        tokenUi.updateToken(this.jwt.tokenId);
      }
    } catch (error) {
      alert(`Error occurred: ${error.message}`);
    }

    setTimeout(callback, 300);
  }
};

export class Login extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      username: "",
      password: "",
      redirectToReferrer: false,
      showPassword: false
    };
    this.login = this.login.bind(this);
  }

  onChange = prop => event => {
    this.setState({ [prop]: event.target.value });
  };

  login = event => {
    event.preventDefault();

    var username = this.state.username;
    var password = this.state.password;

    AuthCentralState.authenticate(username, password, () => {
      this.setState({
        redirectToReferrer: true
      });
    }); 
  };

  handleClickShowPassword = () => {
    this.setState({ ...this.state, showPassword: !this.state.showPassword });
  };

  render() {
    const { from } = this.props.location.state || { from: { pathname: "/" } };
    const { redirectToReferrer } = this.state;
    if (redirectToReferrer === true) {
      this.props.history.push(from.pathname);
    }
    return (
      <div>
        <Paper elevation={2} className={useStyles.root} id="container">
          <ThemeProvider theme={theme}>
            <form onSubmit={this.login}>
              <TextField
                autoFocus
                id="outlined-multiline-flexible"
                label="Username"
                fullWidth
                onChange={this.onChange("username")}
                className={clsx(useStyles.margin, useStyles.textField)}
                margin="normal"
                variant="outlined"
              />
              <br />
              <TextField
                id="outlined-adornment-password"
                fullWidth
                onChange={this.onChange("password")}
                className={clsx(useStyles.margin, useStyles.textField)}
                variant="outlined"
                type={this.state.showPassword ? "text" : "password"}
                label="Password"
                // InputProps={{
                //   endAdornment: (
                //     <InputAdornment position="end">
                //       <IconButton
                //         edge="end"
                //         aria-label="Toggle password visibility"
                //         onClick={this.handleClickShowPassword}
                //       >
                //         {this.state.showPassword ? (
                //           <VisibilityOff />
                //         ) : (
                //           <Visibility />
                //         )}
                //       </IconButton>
                //     </InputAdornment>
                //   )
                // }}
              />
              <br />
              <Button type="submit">Log in</Button>
            </form>
          </ThemeProvider>
        </Paper>
      </div>
    );
  }
}
export default Login;

export const ProtectedRoute = ({ component: Component, ...rest }) => (
  <Route
    {...rest}
    render={props =>
      tokenUi.getToken() ? (
        <Component {...props} />
      ) : (
        <Redirect
          to={{ pathname: "/login", state: { from: props.location } }}
        />
      )
    }
  />
);

1 个答案:

答案 0 :(得分:0)

您需要提供react-router上下文才能访问props.location。根据{{​​1}}文档,您可以使用react-router组件来实现。

doc示例为例:

MemoryRouter