INTEGRATION TESTING · LESSON 14 OF 24
Network events without races
Observe real requests and wait for the event that matters.
- waitForResponse
- event ordering
- predicates
- HTTP
Your runnable checkpoint
Extract into a new practice folder. Each download contains tests, configuration, the complete local practice app and an offline lesson. Use Node.js 22 or 24. Each checkpoint is independent.
Install dependencies and browser binaries using the commands below. The test runner starts the practice server on port 4174. Tests target localhost, never the production EduPoly site.
1. Understand the concepts
Start waiting before performing the action that emits the event. If the response is fast, waiting afterwards can miss it and time out even though the application worked.
Match the intended request precisely: URL path and method are often useful. The response status is evidence to assert rather than always part of the match, so a server error does not become an unexplained wait timeout.
After receiving a response, check the rendered outcome too. A successful backend response does not prove the UI displayed it correctly.
Avoid using networkidle as a universal readiness signal. Background polling, analytics or long-lived connections can make it misleading. Wait for a specific response or user-visible state.
2. Build and run
These are complete test files and configuration. The download also includes app/ and server.mjs; preserve their paths. Stop any manually started practice server before running the suite.
npm install
npx playwright install chromium
npm run check
npm testtests/lesson.spec.ts
import { test, expect } from '@playwright/test';
test('observe the real local course request', async ({ page }) => {
await page.goto('/');
const responsePromise = page.waitForResponse(response =>
new URL(response.url()).pathname === '/api/courses' && response.request().method() === 'GET');
await page.getByRole('button', { name: 'Load courses' }).click();
const response = await responsePromise;
expect(response.status()).toBe(200);
await expect(page.getByRole('list', { name: 'Courses', exact: true }).getByRole('listitem')).toHaveText(['Playwright', 'TypeScript']);
});
playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 1 : 0,
workers: process.env.CI ? 2 : undefined,
timeout: 30000,
expect: { timeout: 5000 },
reporter: [['list'], ['html', { open: 'never' }]],
use: { baseURL: 'http://127.0.0.1:4174', trace: 'retain-on-failure', screenshot: 'only-on-failure' },
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
webServer: { command: 'node server.mjs', url: 'http://127.0.0.1:4174', reuseExistingServer: false, timeout: 15000 }
});
package.json
{
"name": "edupoly-playwright-network-events-and-request-waits",
"version": "1.0.0",
"private": true,
"scripts": {
"test": "playwright test",
"test:headed": "playwright test --headed",
"test:ui": "playwright test --ui",
"check": "tsc --noEmit",
"report": "playwright show-report",
"serve": "node server.mjs"
},
"devDependencies": {
"@playwright/test": "1.56.1",
"typescript": "5.9.3",
"@types/node": "22.20.5"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"moduleResolution": "Node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"types": [
"node"
],
"noEmit": true
},
"include": [
"tests/**/*.ts",
"pages/**/*.ts",
"playwright.config.ts"
]
}
.gitignore
node_modules/
playwright-report/
test-results/
playwright/.auth/
.env
3. Trace the code and check the result
- The promise is created before the click.
- The predicate distinguishes the course endpoint from other assets.
- The locator assertion checks the final UI independently.
Verify your result
- The response status is 200.
- The page renders both real local course titles.
4. Practice independently
Assert the response body includes the TypeScript course.
Show the explanation
Read await response.json() after the response arrives and use expect.arrayContaining with expect.objectContaining({ title: "TypeScript" }).
When something goes wrong
If a browser executable is missing, run npx playwright install chromium in the project folder. If port 4174 is occupied, stop your manual practice server. Read assertion call logs for mismatched locators or expectations. Use npm run report to inspect failures; do not add fixed sleeps or broad resets to hide them.
