DEV Community

Kyle Y. Parsotan
Kyle Y. Parsotan

Posted on

End-to-End (E2E) testing pipeline

Let’s build a real End-to-End (E2E) testing pipeline like teams use in production using Playwright (recommended) and GitHub Actions.

I’ll show you:

  • πŸ§ͺ What E2E testing is
  • βš™οΈ Playwright setup (React app example)
  • πŸš€ GitHub Actions CI pipeline
  • πŸ“Έ Test reports + screenshots on failure
  • 🧠 Production best practices

🧠 0. What is E2E testing?

E2E (End-to-End) testing means:

β€œTest your app like a real user would use it.”

Instead of testing functions, you test:

  • Clicking buttons
  • Filling forms
  • Navigation
  • API + UI together

βš”οΈ Playwright vs Cypress (quick decision)

Feature Playwright Cypress
Speed πŸš€ Faster Ω…Ψͺوسط
Multi-browser βœ… Yes Limited
CI friendly ⭐ Excellent Good
Modern apps ⭐ Best choice Good

πŸ‘‰ We’ll use Playwright (industry standard in 2025)


🧱 1. Install Playwright (React project)

```bash id="pw1"
npm init playwright@latest




When prompted choose:

* JavaScript or TypeScript (TS recommended)
* Tests folder: `tests`
* GitHub Actions: YES

---

# πŸ“ 2. Project structure



```plaintext id="pw2"
my-app/
 β”œβ”€β”€ tests/
 β”‚    β”œβ”€β”€ example.spec.ts
 β”œβ”€β”€ playwright.config.ts
 β”œβ”€β”€ package.json
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini

πŸ§ͺ 3. First E2E test (real user flow)

Example: Login flow test

```ts id="test1"
import { test, expect } from '@playwright/test';

test('user can login successfully', async ({ page }) => {
await page.goto('http://localhost:3000/login');

await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="password"]', 'password123');

await page.click('button[type="submit"]');

await expect(page).toHaveURL(/dashboard/);
});




---

# πŸš€ 4. Run tests locally



```bash id="run1"
npx playwright test
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini

Open UI mode (very useful):

```bash id="ui1"
npx playwright test --ui




---

# πŸ“Έ 5. Auto screenshots on failure

Playwright automatically captures:

* screenshots
* videos
* traces

Enable in config:



```ts id="cfg1"
use: {
  screenshot: 'only-on-failure',
  video: 'retain-on-failure',
  trace: 'on-first-retry'
}
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini

βš™οΈ 6. GitHub Actions CI pipeline (E2E automation)

πŸ“ .github/workflows/e2e.yml

```yaml id="ci1"
name: E2E Tests (Playwright)

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest

steps:
  - uses: actions/checkout@v4

  - name: Setup Node
    uses: actions/setup-node@v4
    with:
      node-version: 20

  - name: Install dependencies
    run: npm install

  - name: Install Playwright browsers
    run: npx playwright install --with-deps

  - name: Run Playwright tests
    run: npx playwright test
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini



---

# 🧠 7. What happens in CI



```plaintext id="flow1"
Push code
   ↓
GitHub Actions starts
   ↓
Install dependencies
   ↓
Install browsers (Chromium, Firefox, WebKit)
   ↓
Run E2E tests
   ↓
Pass β†’ allow merge
Fail β†’ block PR + show report
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini

πŸ“Š 8. Add HTML test report

Enable report:

```ts id="rep1"
reporter: [['html'], ['list']]




Then in CI:



```yaml id="rep2"
- name: Upload Playwright report
  uses: actions/upload-artifact@v4
  if: always()
  with:
    name: playwright-report
    path: playwright-report
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini

🌐 9. Test real deployed app (PRO setup)

Instead of localhost:

```ts id="prod1"
await page.goto('https://your-app.vercel.app/login');




πŸ‘‰ This turns it into **true production E2E testing**

---

# πŸ§ͺ 10. Advanced real-world test examples

---

## 🟒 UI navigation test



```ts id="nav1"
test('navigate to dashboard', async ({ page }) => {
  await page.goto('/');
  await page.click('text=Dashboard');
  await expect(page).toHaveURL(/dashboard/);
});
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini

🟑 Form validation test

```ts id="form1"
test('shows error for empty email', async ({ page }) => {
await page.goto('/login');
await page.click('button[type="submit"]');

await expect(page.locator('.error')).toContainText('Email is required');
});




---

## πŸ”΅ API + UI combined test



```ts id="api1"
test('data loads after API call', async ({ page }) => {
  await page.goto('/dashboard');

  await expect(page.locator('.loading')).toBeHidden();
  await expect(page.locator('.chart')).toBeVisible();
});
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini

πŸ” 11. CI best practices (IMPORTANT)

βœ” Run E2E after build

```yaml id="bp1"

  • run: npm run build
  • run: npm start & ```

βœ” Use staging environment

  • staging.example.com
  • production.example.com

βœ” Retry flaky tests

```ts id="rt1"
retries: 2




---

# ⚠️ 12. Common mistakes

### ❌ Testing implementation instead of behavior

Bad:



```ts id="bad1"
expect(component.state).toBe(true)
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini

Good:

```ts id="good1"
expect(page).toHaveText('Welcome')




---

### ❌ No stable selectors

Use:



```html id="sel1"
data-testid="login-button"
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini

Then:

```ts id="sel2"
page.getByTestId('login-button')




---

### ❌ Running E2E without CI

Always run in GitHub Actions

---

# 🧠 Final architecture



```plaintext id="final1"
Push / PR
   ↓
CI (unit tests)
   ↓
E2E tests (Playwright)
   ↓
Build app
   ↓
Deploy to staging/production
   ↓
Report + screenshots stored in GitHub
πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini πŸ† Live Soccer TV: kyl/end to end ee testing pipeline dl - Pertandingan Hari Ini

πŸš€ What you just built

You now have:

  • πŸ§ͺ Real user simulation testing
  • πŸš€ CI/CD integrated E2E pipeline
  • πŸ“Έ Failure screenshots + videos
  • 🌍 Production-ready test system
  • πŸ”’ Safe deployment gating system

Top comments (0)