End-to-end testing checks if your whole app works like a real user would use it. Playwright helps you do this by controlling a browser automatically.
End-to-end testing with Playwright in Remix
Introduction
Syntax
Remix
import { test, expect } from '@playwright/test'; test('test name', async ({ page }) => { await page.goto('http://your-app-url'); await page.click('selector'); await expect(page.locator('selector')).toHaveText('expected text'); });
Use page.goto() to open a page.
Use page.click() to simulate user clicks.
Examples
Remix
import { test, expect } from '@playwright/test'; test('check homepage title', async ({ page }) => { await page.goto('http://localhost:3000'); await expect(page).toHaveTitle('My Remix App'); });
Remix
import { test, expect } from '@playwright/test'; test('login form works', async ({ page }) => { await page.goto('http://localhost:3000/login'); await page.fill('input[name="username"]', 'user1'); await page.fill('input[name="password"]', 'pass123'); await page.click('button[type="submit"]'); await expect(page.locator('text=Welcome user1')).toBeVisible(); });
Sample Program
This test simulates a user opening the app, logging in, and visiting the dashboard. It checks important texts to confirm each step worked.
Remix
import { test, expect } from '@playwright/test'; test('full user flow test', async ({ page }) => { // Open homepage await page.goto('http://localhost:3000'); // Click login link await page.click('a[href="/login"]'); // Fill login form await page.fill('input[name="username"]', 'testuser'); await page.fill('input[name="password"]', 'mypassword'); // Submit form await page.click('button[type="submit"]'); // Check welcome message await expect(page.locator('text=Welcome testuser')).toBeVisible(); // Navigate to dashboard await page.click('a[href="/dashboard"]'); // Check dashboard heading await expect(page.locator('h1')).toHaveText('Dashboard'); });
Important Notes
Use clear and stable selectors like data-testid attributes for locating elements.
Run tests in headed mode to watch the browser during development by using npx playwright test --headed.
Keep tests small and focused on one user action or flow at a time.
Summary
End-to-end tests check the whole app like a real user.
Playwright controls browsers to run these tests automatically.
Write simple steps: open page, click, fill, check text.
Practice
1. What is the main purpose of end-to-end testing with Playwright in a Remix app?
easy
Solution
Step 1: Understand end-to-end testing goal
End-to-end testing simulates real user actions to check the whole app's behavior.Step 2: Identify Playwright's role
Playwright automates browser actions to perform these user-like tests.Final Answer:
To simulate real user actions and verify the entire app works correctly -> Option BQuick Check:
End-to-end testing = simulate user actions [OK]
Hint: End-to-end tests mimic user steps in the browser [OK]
Common Mistakes:
- Confusing end-to-end with unit testing
- Thinking Playwright tests only backend
- Assuming it checks code style
2. Which of the following is the correct way to navigate to the homepage in a Playwright test?
easy
Solution
Step 1: Recall Playwright navigation method
Playwright usespage.goto(url)to open a page.Step 2: Check syntax correctness
Onlyawait page.goto('https://example.com')is valid syntax.Final Answer:
await page.goto('https://example.com') -> Option DQuick Check:
Navigate with page.goto() [OK]
Hint: Use await page.goto(url) to open pages [OK]
Common Mistakes:
- Using non-existent methods like navigate or visit
- Forgetting to await async calls
- Calling browser.open instead of page.goto
3. Consider this Playwright test snippet:
What will be logged if the button triggers a success message 'Success!' inside
await page.goto('https://example.com');
await page.click('button#submit');
const message = await page.textContent('div#result');
console.log(message);What will be logged if the button triggers a success message 'Success!' inside
div#result?medium
Solution
Step 1: Understand the test flow
The test opens the page, clicks the submit button, then reads text fromdiv#result.Step 2: Analyze expected result
If clicking triggers 'Success!' text indiv#result,page.textContentreturns 'Success!'.Final Answer:
'Success!' -> Option AQuick Check:
page.textContent() returns visible text [OK]
Hint: page.textContent(selector) returns visible text content [OK]
Common Mistakes:
- Assuming textContent returns undefined if element exists
- Confusing selector errors with normal flow
- Expecting empty string when text is present
4. You wrote this Playwright test:
But the test fails with timeout error. What is the most likely cause?
await page.goto('https://example.com');
await page.click('button.submit');
await expect(page.locator('div.result')).toHaveText('Success!');But the test fails with timeout error. What is the most likely cause?
medium
Solution
Step 1: Analyze failure reason
Timeout usually means the element was not found or text did not appear.Step 2: Check selectors and syntax
Ifbutton.submitselector matches no element, click does nothing and result never updates.Final Answer:
The selector 'button.submit' does not match any element -> Option AQuick Check:
Timeout often means selector missing [OK]
Hint: Check selectors carefully if test times out [OK]
Common Mistakes:
- Assuming syntax error causes timeout
- Ignoring selector correctness
- Blaming URL without checking selectors
5. You want to test a Remix app form that requires filling two fields and submitting. Which Playwright code snippet correctly fills 'name' and 'email' inputs and submits the form?
hard
Solution
Step 1: Identify correct Playwright methods
page.fill(selector, value)fills inputs;page.click(selector)clicks buttons.Step 2: Validate selectors and actions
await page.fill('input[name="name"]', 'Alice'); await page.fill('input[name="email"]', 'alice@example.com'); await page.click('button[type="submit"]'); uses correct selectors and methods: fills inputs by name attribute and clicks submit button by type.Final Answer:
await page.fill('input[name="name"]', 'Alice'); await page.fill('input[name="email"]', 'alice@example.com'); await page.click('button[type="submit"]'); -> Option CQuick Check:
Use page.fill() and page.click() with proper selectors [OK]
Hint: Use page.fill() for inputs and page.click() for buttons [OK]
Common Mistakes:
- Using non-existent methods like setValue or submit
- Wrong selectors like IDs when none exist
- Using page.type() which is deprecated in Playwright
Recommended
Ready to prove it?
Pass the test and this pattern moves unknown
10 questions ~5 mineasy hard
