I have setup a couple Jest tests but they just are not working and returning this error.
TypeError: Cannot read property 'parentNode' of null
44 | console.log(document.getElementById("body"));
45 | var title = document.getElementById("modalTitle"),
> 46 | parentTitle = title.parentNode,
When I run the program though it all works properly, no errors, it's just fine. I added some simulated changes to input some fake values into a journal to check if that would help, but it didn't.
So here is the test code.
DisplayJournal.spec.tsx
import * as React from "react";
import { shallow } from "enzyme";
import { DisplayJournal } from "./DisplayJournal";
import AddJournal from "./AddJournal";
let mock: any = jest.fn();
const DisplayJournal_Mock = shallow(
<DisplayJournal
selectedJournal={{
id: 1,
title: "hello",
notes: "frog",
reference: "Test",
date: "12"
}}
deselectJournal={mock}
onClickEditJournal={mock}
match={mock}
location={mock}
//@ts-ignorecls
history={{ push: mock }}
/>
);
test("DisplayJournal.Render() does not return null.", () => {
expect(DisplayJournal_Mock.type()).not.toBeNull();
expect(DisplayJournal_Mock.type()).not.toEqual(null);
expect(DisplayJournal_Mock.get(0)).not.toBeNull();
expect(DisplayJournal_Mock.get(0)).not.toEqual(null);
});
test("DisplayJournal.tsx contains information", () => {
expect(DisplayJournal_Mock.find(".modalBody")).not.toBeNull();
expect(DisplayJournal_Mock.find("#refPlaceholder")).not.toBeNull();
expect(DisplayJournal_Mock.find(".editButton")).not.toBeNull();
});
test("Checking onClick for edit button can be reached", () => {
const jestFunc = jest.fn();
const AddJournal_Mock = shallow(
<AddJournal handleSubmit={() => this._handleSubmit} />
);
AddJournal_Mock.find("#value").simulate("change", {
target: jestFunc,
value: "testVal",
preventDefault: jestFunc
});
AddJournal_Mock.find("#notes").simulate("change", {
target: jestFunc,
value: "testNotes",
preventDefault: jestFunc
});
AddJournal_Mock.find("#value").simulate("change", {
target: jestFunc,
value: "testName",
preventDefault: jestFunc
});
AddJournal_Mock.find("#button").simulate("click", {
preventDefault: jestFunc
});
const eventProps = {
preventDefault: jestFunc
};
const button = DisplayJournal_Mock.find("button").at(0);
button.simulate("click", eventProps);
expect(jestFunc).toBeCalled();
});
And now here is the file that is being tested against and I will BlockQuote the line that is having the issue.
import * as React from "react";
import { Journal } from "../Models";
import Modal from "../../../global/components/modal/Modal";
import * as css from "../css/journal.scss";
import { connect } from "react-redux";
import { hideJournal, editJournal } from "../Actions";
import { Route, RouteComponentProps, withRouter } from "react-router-dom";
import { getNames } from "../Selectors";
import { State } from "../Reducers";
interface Props extends RouteComponentProps {
selectedJournal: Journal;
deselectJournal: Function;
onClickEditJournal: Function;
}
interface States {
title: string;
body: string;
name: string;
date: string;
names: string[];
}
var edited = false;
export class DisplayJournal extends React.Component<Props, States> {
constructor(props: Props) {
super(props);
this.state = {
title: "",
body: "",
name: "",
date: "",
names: []
};
}
_dismiss(e: React.MouseEvent): void {
e.stopPropagation();
e.preventDefault();
}
handleClick = g => {
console.log(document.getElementById("body")); var title = document.getElementById("modalTitle"), parentTitle = title.parentNode,
titleInput = document.createElement("input");
var body = document.getElementById("body"),
parentBody = body.parentNode,
bodyInput = document.createElement("input");
var name = document.getElementById("name"),
parentName = name.parentNode,
nameInput = document.createElement("input");
var date = document.getElementById("date");
var currentDate = new Date();
var day = currentDate.getDate();
var month = currentDate.getMonth() + 1;
var year = currentDate.getFullYear();
var now = day + "/" + month + "/" + year;
titleInput.id = titleInput.name = "title";
bodyInput.id = bodyInput.name = "body";
nameInput.id = nameInput.name = "name";
titleInput.type = "text";
bodyInput.type = "text";
nameInput.type = "text";
titleInput.value = this.state.title;
bodyInput.value = this.state.body;
nameInput.value = this.state.name;
date.innerText = now;
this.setState({ date: now });
parentTitle.replaceChild(titleInput, title);
parentBody.replaceChild(bodyInput, body);
parentName.replaceChild(nameInput, name);
titleInput.addEventListener("blur", this.onBlurEdit, false);
bodyInput.addEventListener("blur", this.onBlurEdit, false);
nameInput.addEventListener("blur", this.onBlurEdit, false);
};
onBlurEdit = e => {
if (e.target.name === "title") {
let titleVal = e.target.value;
this.setState({ title: titleVal });
} else if (e.target.name === "body") {
let bodyVal = e.target.value;
this.setState({ body: bodyVal });
} else if (e.target.name === "name") {
let nameVal = e.target.value;
this.setState({ name: nameVal });
}
edited = true;
//@ts-ignore
let id = this.props.match.params.id;
let title = this.state.title;
let body = this.state.body;
let name = this.state.name;
let date = this.state.date;
this.props.onClickEditJournal(id, title, body, name, date);
};
render() {
const { selectedJournal } = this.props;
const Button = () => (
<Route
render={({ history }) => (
<span
className={css.viewJournalCloseButton}
title="Close the modal dialog"
onClick={() => {
this.props.history.push("/journal");
}}
>
X
</span>
)}
/>
);
if (selectedJournal == null) return null;
if (edited == true) {
selectedJournal.title = this.state.title;
selectedJournal.notes = this.state.body;
selectedJournal.reference = this.state.name;
selectedJournal.date = this.state.date;
}
return (
<Modal title={selectedJournal.title}>
<Button />
<div className={css.modalBody}>
<div>
<div className={css.displayNotes}>
<div id="body" className={css.notesSpan}>
{selectedJournal.notes}
</div>
</div>
<div className={css.row2}>
<div className={css.displayTogether}>
<div className={css.referenceSpan}>
<span id="refPlaceholder">Written by:</span>
<span id="name">{selectedJournal.reference}</span>
</div>
</div>
<div className={css.displayTogether}>
<div className={css.dateSpan}>
Date created:
<span id="date">{selectedJournal.date}</span>
</div>
</div>
</div>
<button className={css.editButton} onClick={this.handleClick}>
Edit
</button>
</div>
</div>
</Modal>
);
}
}
const mapStateToProps = (state: State) => ({
names: getNames(state)
});
const mapDispatchToProps = {
_dismiss: hideJournal,
onClickEditJournal: editJournal
};
export default connect<any, any, any, any>(
mapStateToProps,
mapDispatchToProps
)(withRouter(DisplayJournal));
This issue was that modalTitle
was part of the modal component. The way that I fixed this in the JEST testing was by changing shallow
to mount
I was also able to use shallow(AddJournal_Mock).dive();