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: "[email protected]",
password: "",
confirmPassword: "",
});
expect(emailInputElement.value).toBe("[email protected]");
});
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.
CodePudding user response:
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.