我正在使用MERN堆栈和Redux。我正在尝试为各种组件编写一些测试用例。对于任何连接的我都会收到错误消息...
“在“ Connect(Subject)”的上下文中找不到“存储”。要么将根组件包装在中,要么将自定义的React上下文提供程序传递给Connect(Subject),并将相应的React上下文使用者传递给Connect选项。”
我尝试将其包装在提供程序中,但仍然收到相同的消息。有人知道如何解决这个问题吗?
测试
import React from "react";
import { shallow } from "enzyme";
import { mount } from "enzyme";
import Provider from "react";
import { createStore, applyMiddleware } from "redux";
import Subject from "../components/layout/Subject";
import thunk from "redux-thunk";
import combineReducers from "../reducers/index";
const store = createStore(combineReducers, undefined, applyMiddleware(thunk));
it("Subject should render without errors", () => {
const component = mount(
<Provider store={store}>
<Subject />
</Provider>
);
const wrapper = component.find("#Subject");
expect(wrapper.length).toBe(1);
});
组件
import React, { Component } from "react";
import PropTypes from "prop-types";
import GoogleSearch from "./GoogleSearch";
import { connect } from "react-redux";
import { fetchLatestSubjects } from "../../actions/subject";
import { fetchTopicSubjects } from "../../actions/subject";
import { fetchTopicComments } from "../../actions/comment";
import { fetchComments } from "../../actions/comment";
import { rateSubject } from "../../actions/subject";
import { fetchUsers } from "../../actions/authActions";
import { rateUser } from "../../actions/authActions";
import { rateComment } from "../../actions/comment";
import { trueVote } from "../../actions/subject";
import { mostlyTrueVote } from "../../actions/subject";
import { mostlyFalseVote } from "../../actions/subject";
import { halfAndHalfVote } from "../../actions/subject";
import { falseVote } from "../../actions/subject";
class Subject extends Component {
// on loading the subjects and comments
// are fetched from the database
componentDidMount() {
this.props.fetchLatestSubjects();
this.props.fetchComments();
this.props.fetchUsers();
console.log(
fetch("https://extreme-ip-lookup.com/json").then((res) => res.json())
);
}
constructor(props) {
super(props);
this.state = {
// set inital state for subjects
// description, summary and comments all invisible
viewDesription: -1,
viewSummary: -1,
comments: [],
topic: "subjects",
};
}
componentWillReceiveProps(nextProps) {
// new subject and comments are added to the top
// of the arrays
if (nextProps.newPost) {
this.props.subjects.unshift(nextProps.newPost);
}
if (nextProps.newPost) {
this.props.comments.unshift(nextProps.newPost);
}
}
clickHandler = (id) => {
// when a subject title is clicked pass in its id
const { viewDescription } = this.state;
this.setState({ comments: [] });
var temp = [];
// get the details of the author of the subject and save to state
const subject = this.props.subjects.find((subject) => subject._id === id);
const user = this.props.users.find((user) => user._id === subject.author);
// save comments for subject to temp array
var i;
for (i = 0; i < this.props.comments.length; i++) {
if (this.props.comments[i].subject === id) {
temp.unshift(this.props.comments[i]);
}
}
console.log(temp);
// for each comment add a property with the authors name
temp.forEach((comment) => {
var commentAuthor = this.props.users.find(
(user) => user._id === comment.author
);
comment.authName = commentAuthor.name;
});
// save the subject id to local storage
// this is done incase a new comment is added
// then the subject associated with it can be retrieved
// and added as a property of that comment
localStorage.setItem("passedSubject", id);
localStorage.setItem("passedTopic", subject.topic);
// add all changes to the state
this.setState({
viewDescription: viewDescription === id ? -1 : id,
comments: temp,
subAuthor: user.name,
authRating: user.rating,
authNoOfVotes: user.noOfVotes,
});
};
// hovering on and off subjects toggles the visibility of the summary
hoverHandler = (id) => {
this.setState({ viewSummary: id });
};
hoverOffHandler = () => {
this.setState({ viewSummary: -1 });
};
rateHandler = (id, rate, item) => {
if (item === "subject") {
// this function rates the subject and the author
const subject = this.props.subjects.find((subject) => subject._id === id);
const author = this.props.users.find(
(user) => user._id === subject.author
);
// call the rateSubject and rateUser functions
this.props.rateSubject(id, rate, subject.noOfVotes, subject.rating);
this.props.rateUser(author._id, rate, author.noOfVotes, author.rating);
console.log(author.name);
alert("Thank you for rating this subject.");
} else if (item === "comment") {
const comment = this.props.comments.find((comment) => comment._id === id);
const author = this.props.users.find(
(user) => user._id === comment.author
);
// call the rateComment and rateUser functions
this.props.rateComment(id, rate, comment.noOfVotes, comment.rating);
this.props.rateUser(author._id, rate, author.noOfVotes, author.rating);
console.log(author.name);
alert("Thank you for rating this comment.");
}
};
voteHandler = (id, currVote, vote) => {
if (vote === "True") {
console.log(id, currVote, vote);
this.props.trueVote(id, currVote);
alert("Thanks for voting!");
window.location.reload(false);
} else if (vote === "False") {
console.log(id, currVote, vote);
this.props.falseVote(id, currVote);
alert("Thanks for voting!");
window.location.reload(false);
} else if (vote === "mostlyFalse") {
console.log(id, currVote, vote);
this.props.mostlyFalseVote(id, currVote);
alert("Thanks for voting!");
window.location.reload(false);
} else if (vote === "mostlyTrue") {
console.log(id, currVote, vote);
this.props.mostlyTrueVote(id, currVote);
alert("Thanks for voting!");
window.location.reload(false);
} else if (vote === "halfAndHalf") {
console.log(id, currVote, vote);
this.props.halfAndHalfVote(id, currVote);
alert("Thanks for voting!");
window.location.reload(false);
}
};
render() {
const subjectItems = this.props.subjects.map((subject) => {
// if the state equals the id set to visible if not set to invisible
var view = this.state.viewDescription === subject._id ? "" : "none";
var hover = this.state.viewSummary === subject._id ? "" : "none";
var comments = this.state.comments;
var subjectAuthor = this.state.subAuthor;
var authRating = this.state.authRating;
var authNoOfVotes = this.state.authNoOfVotes;
var className = "";
if (subject.category === "Education") {
className = "Education";
} else if (subject.category === "Environment") {
className = "Environment";
} else if (subject.category === "Politics") {
className = "Politics";
} else if (subject.category === "Health") {
className = "Health";
} else if (subject.category === "Other") {
className = "Other";
}
return (
<div key={subject._id}>
<div
className={className}
onMouseEnter={() => this.hoverHandler(subject._id)}
onMouseLeave={() => this.hoverOffHandler()}
>
<p className="title" onClick={() => this.clickHandler(subject._id)}>
{subject.title}
</p>
<p className="vote" style={{ textAlign: "Right" }}>
Rating: {(subject.rating / subject.noOfVotes).toFixed(1)}/5
</p>
<p className="summary" style={{ display: hover }}>
{subject.summary}
</p>
</div>
<div className="truthResult" style={{ display: view }}>
<p className="false">
FALSE -{" "}
{(
(100 /
(subject.true +
subject.false +
subject.mostlyTrue +
subject.mostlyFalse +
subject.halfAndHalf)) *
subject.false
).toFixed(1)}
%
</p>
<p className="mostlyFalse">
MOSTLY FALSE -{" "}
{(
(100 /
(subject.true +
subject.false +
subject.mostlyTrue +
subject.mostlyFalse +
subject.halfAndHalf)) *
subject.mostlyFalse
).toFixed(1)}
%
</p>
<p className="halfAndHalf">
HALF AND HALF -{" "}
{(
(100 /
(subject.true +
subject.false +
subject.mostlyTrue +
subject.mostlyFalse +
subject.halfAndHalf)) *
subject.halfAndHalf
).toFixed(1)}
%
</p>
<p className="mostlyTrue">
MOSTLY TRUE -{" "}
{(
(100 /
(subject.true +
subject.false +
subject.mostlyTrue +
subject.mostlyFalse +
subject.halfAndHalf)) *
subject.mostlyTrue
).toFixed(1)}
%
</p>
<p className="true">
TRUE -{" "}
{(
(100 /
(subject.true +
subject.false +
subject.mostlyTrue +
subject.mostlyFalse +
subject.halfAndHalf)) *
subject.true
).toFixed(1)}
%
</p>
</div>
<div className="subjectBody " style={{ display: view }}>
<div className="leftSubjectBody">
<div className="subjectAuthor">
<p className="author">
Subject created by: {subjectAuthor} -{" "}
{(authRating / authNoOfVotes).toFixed(1)}/5 Star user
{/* <br /> {subject.date} */}
</p>
</div>
<div className="subjectDescription">
<p className="description">{subject.description}</p>
</div>
<div className="subjectLinks">
Supporting Link: <br />
<a href={subject.links} target="blank">
{subject.links}
</a>
</div>
</div>
<div className="rightSubjectBody">
<div className="rate">
<p>
<b>Rate this subject</b>
</p>
<button
onClick={() => this.rateHandler(subject._id, 1, "subject")}
>
1
</button>
<button
onClick={() => this.rateHandler(subject._id, 2, "subject")}
>
2
</button>
<button
onClick={() => this.rateHandler(subject._id, 3, "subject")}
>
3
</button>
<button
onClick={() => this.rateHandler(subject._id, 4, "subject")}
>
4
</button>
<button
onClick={() => this.rateHandler(subject._id, 5, "subject")}
>
5
</button>
</div>
<div className="voting">
<p>
Do you think this subject question is false, mostly false,
half and half, mostly true or true, based on the evidence
provided and your own reseach in the area? Please vote below
and leave comments.
</p>
<div
className="voteButton"
onClick={() =>
this.voteHandler(subject._id, subject.false, "False")
}
>
FALSE
</div>
<div
className="voteButton"
onClick={() =>
this.voteHandler(
subject._id,
subject.mostlyFalse,
"mostlyFalse"
)
}
>
MOSTLY FALSE
</div>
<div
className="voteButton"
onClick={() =>
this.voteHandler(
subject._id,
subject.halfAndHalf,
"halfAndHalf"
)
}
>
HALF AND HALF
</div>
<br />
<div
className="voteButton"
onClick={() =>
this.voteHandler(
subject._id,
subject.mostlyTrue,
"mostlyTrue"
)
}
>
MOSTLY TRUE
</div>
<div
className="voteButton"
onClick={() =>
this.voteHandler(subject._id, subject.true, "True")
}
>
TRUE
</div>
</div>
</div>
<div className="subjectComments">
<p style={{ fontWeight: "bold" }}>Comments:</p>
{comments.map((comment, i) => {
return (
<div key={i} className="singleComment">
<p>
{comment.title} - Comment rating :{" "}
{(comment.rating / comment.noOfVotes).toFixed(1)}/5
<br />
{comment.comment}
<br />
Comment by : {comment.authName} - This user has a rating
of {(comment.rating / comment.noOfVotes).toFixed(1)}/5
STARS
</p>
<div className="rate">
Rate this comment :{" "}
<button
onClick={() =>
this.rateHandler(comment._id, 1, "comment")
}
>
1
</button>
<button
onClick={() =>
this.rateHandler(comment._id, 2, "comment")
}
>
2
</button>
<button
onClick={() =>
this.rateHandler(comment._id, 3, "comment")
}
>
3
</button>
<button
onClick={() =>
this.rateHandler(comment._id, 4, "comment")
}
>
4
</button>
<button
onClick={() =>
this.rateHandler(comment._id, 5, "comment")
}
>
5
</button>
</div>
</div>
);
})}
<br />
<a href="/addcomment">
<div className="buttonAddComment">ADD COMMENT</div>
</a>
</div>
</div>
</div>
);
});
return (
<div id="Subject">
<GoogleSearch />
{subjectItems}
</div>
);
}
}
Subject.propTypes = {
fetchLatestSubjects: PropTypes.func.isRequired,
fetchTopicSubjects: PropTypes.func.isRequired,
fetchTopicComments: PropTypes.func.isRequired,
fetchComments: PropTypes.func.isRequired,
fetchUsers: PropTypes.func.isRequired,
rateSubject: PropTypes.func.isRequired,
rateComment: PropTypes.func.isRequired,
rateUser: PropTypes.func.isRequired,
trueVote: PropTypes.func.isRequired,
falseVote: PropTypes.func.isRequired,
subjects: PropTypes.array.isRequired,
comments: PropTypes.array.isRequired,
users: PropTypes.array.isRequired,
newPost: PropTypes.object,
};
const mapStateToProps = (state) => ({
subjects: state.subjects.items,
newSubject: state.subjects.item,
comments: state.comments.items,
users: state.auth.users,
newComment: state.comments.item,
});
// export default Subject;
export default connect(mapStateToProps, {
fetchLatestSubjects,
fetchTopicSubjects,
fetchTopicComments,
fetchComments,
fetchUsers,
rateSubject, // rate subject
rateUser,
rateComment,
trueVote,
mostlyTrueVote,
falseVote,
mostlyFalseVote,
halfAndHalfVote,
})(Subject, Comment);
答案 0 :(得分:0)
这就是我们在React Testing Library中的工作方式。您可以通过相应地替换实用程序功能将其转换为酶。
it('renders with redux', () => {
render(<Provider store={store}>
<ReduxCode />
</Provider>);
//further code...
})