Reactjs TypeError无法读取属性';州';未定义的
我一直在这条线上遇到这个错误,我不确定是什么导致了它,因为我对开玩笑/反应/酶还很陌生Reactjs TypeError无法读取属性';州';未定义的,reactjs,jestjs,enzyme,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
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');
})
})
从“React”导入React;
从“../../enzyme”导入{shall,mount,render};
从“../Login”导入登录名
描述('登录测试套件',()=>{
它('应该呈现表单',()=>{
常量包装器=浅();
expect(wrapper.find('form').exists()).toBe(true);
expect(wrapper.find('#userName').length).toEqual(1);
expect(wrapper.find(“#password”).length.toEqual(1);
})
})
描述('用户名测试套件',()=>{
它('应该更改登录组件的状态',()=>{
常量包装器=浅();
wrapper.find(“#userName”).simulate('blur',
{
目标:{name:'userName',value:'adastest'}
});
expect(wrapper.state('userName')).toEqual('adastest');
})
})
描述('密码测试套件',()=>{
它('应该更改登录组件的状态',()=>{
const wrapper=mount();
wrapper.find(“#password”).simulate('blur',
{
目标:{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 } }}
/>
)
}
/>
);
从“@material ui/core/TextField”导入TextField;
从“clsx”导入clsx;
从“@物料界面/核心/按钮”导入按钮;
从“@material ui/core/styles”导入{createMuiTheme,makeStyles}”;
从“@material ui/styles”导入{ThemeProvider}”;
从“@material ui/core/colors”导入{红色,灰色}”;
从“@material ui/core/Paper”导入纸张;
导入“./App.css”;
从“react router dom”导入{Route,Redirect};
var tokenUi=require(“../../tokenUi.js”);
var fetchUi=require(“../../fetchUi.js”);
const theme=createMuiTheme({
调色板:{
主:{main:red[900]},
次要:{main:grey[900]}
}
});
const useStyles=makeStyles(主题=>({
保证金:{
页边空白:主题。间距(1)
},
文本字段:{
弹性基准:200
}
}));
常量AuthCentralState={
I认证:错误,
jwt:“,
异步身份验证(用户、传递、回调){
让loginInfo={密码:pass,用户名:user};
试一试{
var response=wait fetchUi.post(
“/adas/user/checkuser”,
JSON.stringify(loginInfo),
假的
);
this.jwt=await response.json();
if(this.jwt.tokenId){
this.isAuthenticated=true;
tokenUi.updateToken(this.jwt.tokenId);
}
}捕获(错误){
警报(`Error occurrent:${Error.message}`);
}
setTimeout(回调,300);
}
};
导出类登录扩展React.Component{
建造师(道具){
超级(道具);
此.state={
用户名:“”,
密码:“”,
转发者:错,
showPassword:false
};
this.login=this.login.bind(this);
}
onChange=prop=>event=>{
this.setState({[prop]:event.target.value});
};
登录=事件=>{
event.preventDefault();
var username=this.state.username;
var password=this.state.password;
AuthCentralState.authenticate(用户名、密码,()=>{
这是我的国家({
真的吗
});
});
};
handleClickShowPassword=()=>{
this.setState({…this.state,showPassword:!this.state.showPassword});
};
render(){
const{from}=this.props.location.state | |{from:{pathname:“/”};
const{redirectToReferrer}=this.state;
如果(重定向到转发程序===真){
this.props.history.push(from.pathname);
}
返回(
登录
);
}
}
导出默认登录;
export const ProtectedRoute=({component:component,…rest})=>(
tokenUi.getToken()(
) : (
)
}
/>
);
您需要提供react router
上下文才能访问道具位置。根据react router
文档,您可以使用MemoryRouter
组件实现这一点
从示例中可以看出:
//app.test.js
测试(“单击筛选链接更新产品查询参数”,()=>{
让历史、地点;
渲染(
{
历史=历史;
位置=位置;
返回null;
}}
/>
,
节点
);
行动(()=>{
//示例:单击一个目标/产品?id=1234
});
//关于url的断言
expect(location.pathname).toBe(“/products”);
const searchParams=新的URLSearchParams(location.search);
expect(searchParams.has(“id”).toBe(true);
expect(searchParams.get(“id”)).toEqual(“1234”);
});
登录
是在没有任何道具的情况下安装的
,因此我猜是错误的。location
来自哪里?Aprops
您是从父组件定义还是从父组件定义props?向您展示登录
组件请道具。位置
来自React路由器,但在测试中您会进行浅装载,因此不可用。您必须手动传递位置道具
// app.test.js
test("clicking filter links updates product query params", () => {
let history, location;
render(
<MemoryRouter initialEntries={["/my/initial/route"]}>
<App />
<Route
path="*"
render={({ history, location }) => {
history = history;
location = location;
return null;
}}
/>
</MemoryRouter>,
node
);
act(() => {
// example: click a <Link> to /products?id=1234
});
// assert about url
expect(location.pathname).toBe("/products");
const searchParams = new URLSearchParams(location.search);
expect(searchParams.has("id")).toBe(true);
expect(searchParams.get("id")).toEqual("1234");
});