I'm having a few issues with testing in React with Typescript. I'm following a tutorial in React.js and am new to Typescript also so am not sure how to remove some errors.
App.ts
import { useState } from "react";
import validator from "validator";
interface signupInput {
email: string;
password: string;
confirmPassword: string;
}
function App() {
const [signupInput, setSignupInput] = useState<signupInput>({
email: "",
password: "",
confirmPassword: "",
});
const [error, setError] = useState<string>("");
const handleChange = (e: any) => {
setSignupInput({
...signupInput,
[e.target.name]: e.target.value,
});
};
const handleClick = (e: any) => {
e.preventDefault();
if (!validator.isEmail(signupInput.email)) {
return setError("the email you input is invalid");
} else if (signupInput.password.length < 5) {
return setError("your password needs 5 or more characters");
} else if (signupInput.password !== signupInput.confirmPassword) {
return setError("your passwords do not match");
} else {
return setError("");
}
};
return (
<div className="container my-5">
<form>
<div className="mb-3">
<label htmlFor="email" className="form-label">
Email Address
</label>
<input
type="email"
id="email"
name="email"
className="form-control"
value={signupInput.email}
onChange={handleChange}
/>
</div>
<div className="mb-3">
<label htmlFor="password" className="form-label">
Password
</label>
<input
type="password"
id="password"
name="password"
className="form-control"
value={signupInput.password}
onChange={handleChange}
/>
</div>
<div className="mb-3">
<label htmlFor="confirm-password" className="form-label">
Confirm Password
</label>
<input
type="password"
id="confirm-password"
name="confirmPassword"
className="form-control"
value={signupInput.confirmPassword}
onChange={handleChange}
/>
</div>
{error && <p className="text-danger">{error}</p>}
<button type="submit" className="btn btn-primary" onClick={handleClick}>
Submit
</button>
</form>
</div>
);
}
export default App;
I feel like I need to pass my interface signup through to the testing file which I've done and it has removed a lot of red lines but not sure if I've done it correctly.
App.test.tsx
import { render, screen } from "@testing-library/react";
import App from "./App";
import "@testing-library/jest-dom/extend-expect";
import userEvent from "@testing-library/user-event";
interface signupInput {
email: string;
password: string;
confirmPassword: string;
}
beforeEach(() => {
// eslint-disable-next-line testing-library/no-render-in-setup
render(<App />);
});
const typeIntoForm = ({ email, password, confirmPassword }: signupInput) => {
const emailInputElement = screen.getByRole<HTMLInputElement>("textbox", {
name: /email/i,
});
const passwordInputElement =
screen.getByLabelText<HTMLInputElement>("Password");
const confirmPasswordInputElement =
screen.getByLabelText<HTMLInputElement>(/confirm password/i);
if (email) {
userEvent.type(emailInputElement, email);
}
if (password) {
userEvent.type(passwordInputElement, password);
}
if (confirmPassword) {
userEvent.type(confirmPasswordInputElement, confirmPassword);
}
return {
emailInputElement,
passwordInputElement,
confirmPasswordInputElement,
};
};
I'm trying to clean up my code. I'm not sure if I've passed the interface through correctly and also in my test:
test("should be able to type an email", () => {
const { emailInputElement } = typeIntoForm({
email: "selena@gmail.com",
password: "",
confirmPassword: "",
});
expect(emailInputElement.value).toBe("selena@gmail.com");
});
if I remove:
password: "",
confirmPassword: "",
from const { emailInputElement } I get an error:
Argument of type '{ email: string; }' is not assignable to parameter of type 'signupInput'.
Type '{ email: string; }' is missing the following properties from type 'signupInput': password, confirmPasswordts(2345)
What could I change so I can only mention the email that isn't an empty string?
Also if there is any good documentation for testing in Typescript.
You could try to modify the type of your typeIntoForm function like so :
interface SignupInput {
email?: string;
password?: string;
confirmPassword?: string;
}
const typeIntoForm = (input: SignupInput) => {
Or :
const typeIntoForm = (Partial<SignupInput>: signupInput) => {
https://www.typescriptlang.org/docs/handbook/utility-types.html
https://www.typescriptlang.org/docs/handbook/2/functions.html#optional-parameters
I suggest you capitalize your types and interfaces.