Introduction
Let's face it – testing isn't the most glamorous part of web development, but it's definitely one of the most important. Without solid tests, we're basically crossing our fingers and hoping our apps don't break when users start clicking around.
That's where Playwright comes in. It's a game-changer for end-to-end testing, making the process faster and more reliable than you might expect. In this guide, I'll walk you through setting up Playwright for a React app built with Vite and TypeScript, with special attention to handling API integration testing.
Setting Up Your React Playground
First things first, let's get a React app up and running. We'll use Vite because, honestly, who doesn't love lightning-fast build times?
npm create vite@latest my-react-app --template react-ts
cd my-react-app
npm install
Fire up the dev server with:
npm run dev
Getting Friendly with Playwright
Now for the fun part – adding Playwright to the mix:
npm init playwright@latest
It will create a tests folder and inside there will be an example.spec.ts file already created.There let's write our first test.
import { test, expect } from '@playwright/test';
test.describe('Basic tests', () => {
test.beforeAll(async () => {
console.log('Setting up test environment');
});
test('basic test', async ({ page }) => {
// Navigate to the application
await page.goto('http://localhost:5173');
// Check if the page title contains the expected text
await expect(page).toHaveTitle(/Vite \+ React/);
});
});
What's happening here?
- We're grouping our tests with
test.describe
for better organization - Using
test.beforeAll
to set up anything we need before testing - Navigating to our app and checking if the page title is what we expect
Run the test with:
npx playwright test
Building Something Worth Testing
Let's create a simple component that actually does something – like fetching user data from an API an display that to an UI:
import { useEffect, useState } from 'react';
type User = {
id: number;
name: string;
};
const UserList = () => {
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => {
setUsers(data);
setLoading(false);
});
}, []);
if (loading) return <p>Loading...</p>;
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
export default UserList;
And let's add this component to our App:
import UserList from './components/UserList';
function App() {
return (
<div>
<h1>User List</h1>
<UserList />
</div>
);
}
export default App;
Let's test the App
Now comes the really cool part – testing how our app handles API responses. Create a new test file tests/userlist.spec.ts
:
import { test, expect } from '@playwright/test';
test.describe('User List API Integration', () => {
test.beforeAll(async () => {
console.log('Starting API tests');
});
test('User list loads and displays correctly', async ({ page }) => {
// Intercept API request and provide mock data
await page.route('https://jsonplaceholder.typicode.com/users', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Doe' }
]),
});
});
// Navigate to the app
await page.goto('http://localhost:5173');
// Wait for API call and UI update
await expect(page.getByText('John Doe')).toBeVisible();
await expect(page.getByText('Jane Doe')).toBeVisible();
});
});
This is where the Playwright really shines. We're:
- Intercepting the API call and sending back our own mock data
- Loading up our app
- Making sure the UI actually shows the data we expect
No need to worry about flaky tests or timing issues – Playwright intelligently waits for elements to appear.
Run Those Tests!
Time to see if everything works:
npx playwright test
Want to actually see the tests running? Try UI mode:
npx playwright test --ui
Conclusion
And that's it! We've built a React app and set up Playwright for testing, and even tackled API integration testing. The best part? Playwright's API interception means we can test our UI components without worrying about backend dependencies. These techniques should give you confidence that your React components will handle API data correctly – even when things go wrong. If you like this blog and want to learn more about Frontend Development and Software Engineering, you can follow me on Dev.to.
Top comments (2)
We can't always expect the api response to be same all time right ? So how can we manage that ?
In those cases, we can check the API response status code and based on that we can run different tests. For example in the following code to add a new task will only run the final test if the status code is 201.