🧭 Introduction
Forms and API calls are where most real-world bugs happen:
- Invalid inputs slip through
- APIs fail silently
- Loading states are forgotten
- Error messages don’t appear
Testing these correctly separates beginner tests from professional-grade tests.
In this lesson, you’ll learn how to test user forms and API interactions the way production React apps do — confidently and reliably.
🎯 What You’ll Learn in This Lesson
By the end of this lesson, you will understand:
- How to test form inputs and submission
- How to simulate user typing and clicking
- How to test validation errors
- How to mock API calls
- How to test loading and error states
- Common mistakes to avoid
🧠 Testing Forms: Core Principles
When testing forms, always remember:
Test what the user does and sees — not the form library.
Focus on:
✔ Typing
✔ Submitting
✔ Seeing validation
✔ Seeing success or failure
🧩 Example Form Component
function LoginForm({ onSubmit }) {
const [email, setEmail] = React.useState("");
const [error, setError] = React.useState("");
const handleSubmit = e => {
e.preventDefault();
if (!email) {
setError("Email is required");
return;
}
onSubmit(email);
};
return (
<form onSubmit={handleSubmit}>
<input
placeholder="Email"
value={email}
onChange={e => setEmail(e.target.value)}
/>
<button type="submit">Login</button>
{error && <p>{error}</p>}
</form>
);
}
🧪 Testing User Typing (Very Important)
fireEvent.change(
screen.getByPlaceholderText("Email"),
{ target: { value: "user@test.com" } }
);
This simulates real typing.
🧪 Testing Form Submission
fireEvent.click(screen.getByText("Login"));
🧠 Testing Validation Errors
fireEvent.click(screen.getByText("Login"));
expect(
screen.getByText("Email is required")
).toBeInTheDocument();
✔ Tests validation
✔ Tests user feedback
🧠 Testing Successful Submission
const mockSubmit = jest.fn();
render(<LoginForm onSubmit={mockSubmit} />);
fireEvent.change(
screen.getByPlaceholderText("Email"),
{ target: { value: "user@test.com" } }
);
fireEvent.click(screen.getByText("Login"));
expect(mockSubmit).toHaveBeenCalledWith("user@test.com");
✔ Behavior-focused
✔ No internal state testing
🧠 Testing API Calls (Big Concept)
Real apps talk to APIs.
But in tests:
❌ Don’t hit real servers
❌ Don’t depend on network
Instead:
Mock API responses
🧩 Example API Component
function Users() {
const [users, setUsers] = React.useState([]);
const [error, setError] = React.useState("");
useEffect(() => {
fetch("/api/users")
.then(res => res.json())
.then(setUsers)
.catch(() => setError("Failed to load users"));
}, []);
if (error) return <p>{error}</p>;
return (
<ul>
{users.map(u => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
🧪 Mocking API Success Response
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve([
{ id: 1, name: "Avni" }
])
})
);
🧪 Testing API Success UI
expect(await screen.findByText("Avni"))
.toBeInTheDocument();
Notice:
findBywaits for async UI updates
🧠 Testing Loading State (Important)
If your component has loading UI:
if (loading) return <p>Loading...</p>;
Test it:
expect(screen.getByText("Loading..."))
.toBeInTheDocument();
🧪 Mocking API Failure
global.fetch = jest.fn(() =>
Promise.reject(new Error("API Error"))
);
🧠 Testing Error UI
expect(
await screen.findByText("Failed to load users")
).toBeInTheDocument();
🧠 Async Testing Rules (Must Remember)
✔ Use findBy for async UI
✔ Avoid arbitrary setTimeout
✔ Let the test wait for UI updates
Bad:
setTimeout(() => {}, 1000);
Good:
await screen.findByText("Data loaded");
🚨 Common Mistakes in Form & API Testing
❌ Testing form libraries internals
❌ Making real API calls
❌ Ignoring error states
❌ Not testing loading UI
❌ Over-mocking everything
🎯 Best Practices (Senior-Level)
✅ Test full user flow
✅ Mock APIs centrally
✅ Test success + failure
✅ Keep tests readable
✅ Avoid flaky async logic
✅ Use semantic queries
❓ FAQs — Forms & API Testing
🔹 Should I test backend validation?
No — frontend behavior only.
🔹 Should I mock fetch or axios?
Yes — always.
🔹 Are API tests slow?
No — if mocked properly.
🔹 Is this asked in interviews?
Yes — very frequently.
🧠 Quick Recap
✔ Test typing & submission
✔ Validate error messages
✔ Mock API success & failure
✔ Test loading & error UI
✔ Focus on user behavior
🎉 Conclusion
Forms and APIs are where:
- Users interact
- Bugs hide
- Apps break
Testing them properly ensures your app:
- Handles real-world scenarios
- Fails gracefully
- Delivers consistent UX
With this lesson, you’ve completed SECTION 9 — Testing React Applications 🧪⚛️
👉 Next Section
SECTION 10 — TypeScript with React
👉 Next Lesson
Lesson 32 — TypeScript Fundamentals for React