This is my first question on here so sorry if I mess up formatting or something.
As the title says, I'm using React. I'm using Axios to connect the frontend to the backend. I'm using Jest to test it. When you login to the app, it's supposed to redirect to the home page. Working with the application itself, I can tell this obviously does what it's supposed to. I want to see if I can check the URL change after clicking the login button for jest. However, every time I simulate clicking the button, I get an error that I can't seem to move past.
Here is the code for the login page (Login.js).
import React, { useState, useContext } from "react";
import axios from "axios";
import { useHistory } from "react-router-dom";
import { AuthContext } from "../helpers/AuthContext";
function Login() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const { setAuthState } = useContext(AuthContext);
let history = useHistory();
const login = () => {
const data = { username: username, password: password };
const req = axios.post("http://localhost:3001/users/login", data).then((response) => {
const id = response.data.id;
if (response.data.error) {
alert(response.data.error);
axios.post(`http://localhost:3001/audit/unsuccessfullogin/${id}`).then((response) => {
console.log("unsuccessful log in attempt added to audit log");
});
} else {
localStorage.setItem("accessToken", response.data.token);
setAuthState({
username: response.data.username,
id: response.data.id,
status: true,
});
//log successful login in audit_log table
axios.post(`http://localhost:3001/audit/successlogin/${id}`).then((response) => {
console.log("successful log in attempt added to audit log");
});
history.push("/");
}
}).catch(err => err);
};
return (
<div className="formContainer">
<label>Welcome Back!</label>
<label>Username: </label>
<input
type="text"
data-testid="usernameInput"
onChange={(event) => {
setUsername(event.target.value);
}} placeholder="Enter Username"
/>
<label>Password: </label>
<input
type="password"
data-testid="passwordInput"
onChange={(event) => {
setPassword(event.target.value);
}} placeholder="Enter Password"
/>
<button onClick={() => {login()} } data-testid="loginButton" >Login</button>
</div>
);
}
export default Login;
Here is the code for the test page (Login.test.js).
import axios from "axios";
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
import { screen, queryByTestId, getByText, waitFor, fireEvent } from '@testing-library/dom'
import * as enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
(enzyme).configure({ adapter: new Adapter() });
import { shallow, mount } from 'enzyme';
import expect from 'expect';
jest.mock('axios');
const mockHistoryPush = jest.fn();
import Login from "./Login"
const username = "testdriver";
const password = "testdpassword";
let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
it("Renders the welcome back message on login", () => {
act(() => {
render(<Login />, container);
});
expect(container.textContent).toBe("Welcome Back!Username: Password: Login");
});
let wrapper;
it("Fillable username input exists", async () => {
wrapper = mount(<Login />);
expect(wrapper.find('input[type="text"]').exists()).toBeTruthy();
});
it("Fillable password input exists", async () => {
wrapper = mount(<Login />);
expect(wrapper.find('input[type="password"]').exists()).toBeTruthy();
});
it("Clickable login button exists", async () => {
wrapper = mount(<Login />);
expect(wrapper.find('button').exists()).toBeTruthy();
});
const defaultProps = {
onClick: jest.fn(),
text: "Login",
};
it('test login', async () => {
// const onClick = jest.fn();
wrapper = shallow(<Login />);
const mockData = [{ username: username, password: password }];
axios.mockResolvedValue({ data: mockData });
const inputUsername = wrapper.find('input[type="text"]');
inputUsername.simulate('change', {target: {name: 'username', value: username}});
const inputPassword = wrapper.find('input[type="password"]');
inputPassword.simulate('change', {target: {name: 'username', value: username}});
const loginButton = wrapper.find("button");
loginButton.simulate('click');
// const { getByText } = render(<Login {...defaultProps} onClick={onClick} />)
// const loginButton = getByText("loginButton");
// fireEvent.click(loginButton);
});
it("Successful Axios Login Attempt", () => {
const data = { username: username, password: password };
axios.get.mockImplementation(() => Promise.resolve({ data: {data} }));
});
test("Failed Axios Login Attempt", () => {
const data = { username: username, password: "badpass" };
axios.get.mockImplementation(() => Promise.reject({ data: {data} }));
});
The issue is with the 5th test 'test login'. Simulating clicking the login button keeps causing this error.
ā test login
TypeError: Cannot read properties of undefined (reading 'then')
14 | const login = () => {
15 | const data = { username: username, password: password };
> 16 | const req = axios.post("http://localhost:3001/users/login", data).then((response) => {
| ^
17 | const id = response.data.id;
18 | if (response.data.error) {
19 | alert(response.data.error);
at login (src/pages/Login.js:16:19)
at onClick (src/pages/Login.js:57:33)
at fn (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:801:20)
at withSetStateAllowed (node_modules/enzyme-adapter-utils/src/Utils.js:100:18)
at Object.simulateEvent (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:797:11)
at ShallowWrapper.call (node_modules/enzyme/src/ShallowWrapper.js:1134:7)
at ShallowWrapper.single (node_modules/enzyme/src/ShallowWrapper.js:1654:21)
at ShallowWrapper.simulate (node_modules/enzyme/src/ShallowWrapper.js:1133:17)
at Object.<anonymous> (src/pages/Login.test.js:74:15)
As you can see, I have tried to use fireEvent as well to click the button. However, it seems that my button is not a DOM element. I don't know why it wouldn't be. I apologize, but this is the first time I've ever written anything in react. I don't understand the semantics super well.
And yes, if you are wondering, this is a school project.
Thank you so much in advance for taking a look at my question. I have been trying to figure this out on and off for days now, but I don't know how much more combing through documentation can help. I would really appreciate any help I could get from a human being.