How to Generate Beautiful HTML Reports with Allure 2 and Playwright

How to Generate Beautiful HTML Reports with Allure 2 and Playwright

Test results buried in terminal output are nearly useless for teams. Allure Report transforms your Playwright test results into interactive HTML dashboards with screenshots, video attachments, execution history, and trend charts. Here's how to set it up.

Why Allure with Playwright

Playwright's built-in HTML reporter is good but limited — it lacks trend history, category breakdowns, and deep integration with test management. Allure 2 fills these gaps:

  • History trends across multiple builds
  • Test categories (product bugs, test bugs, broken tests)
  • Rich attachments — screenshots, traces, videos
  • Retries and flakiness tracking
  • Suite and feature organization

Installation

npm install -D allure-playwright allure-commandline

Add to your playwright.config.ts:

import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [
    ['line'],
    ['allure-playwright', {
      detail: true,
      outputFolder: 'allure-results',
      suiteTitle: true,
    }]
  ],
  use: {
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    trace: 'retain-on-failure',
  },
});

Writing Tests with Allure Metadata

Allure picks up metadata from decorators and API calls. Use @allure annotations to add structure:

import { test, expect } from '@playwright/test';
import { allure } from 'allure-playwright';

test('user can complete checkout', async ({ page }) => {
  await allure.label('feature', 'Checkout');
  await allure.label('story', 'Happy Path');
  await allure.severity('critical');
  await allure.description('Verifies the complete purchase flow from cart to order confirmation.');

  await allure.step('Navigate to product page', async () => {
    await page.goto('/products/widget-pro');
    await expect(page.locator('h1')).toContainText('Widget Pro');
  });

  await allure.step('Add to cart', async () => {
    await page.click('[data-testid="add-to-cart"]');
    await expect(page.locator('.cart-count')).toHaveText('1');
  });

  await allure.step('Proceed to checkout', async () => {
    await page.click('[data-testid="checkout-btn"]');
    await page.fill('#email', 'test@example.com');
    await page.fill('#card-number', '4242424242424242');
    await page.fill('#expiry', '12/28');
    await page.fill('#cvv', '123');
    await page.click('[data-testid="place-order"]');
    await expect(page.locator('.order-confirmation')).toBeVisible();
  });
});

Steps appear as collapsible sections in Allure, making failures easy to pinpoint.

Attaching Custom Data

Add attachments programmatically:

test('API response validation', async ({ request }) => {
  const response = await request.get('/api/orders');
  const body = await response.json();

  // Attach the raw response for debugging
  await allure.attachment('API Response', JSON.stringify(body, null, 2), 'application/json');

  expect(response.status()).toBe(200);
  expect(body.orders).toHaveLength(10);
});

For screenshots on specific steps (not just failures):

await allure.step('Verify dashboard loaded', async () => {
  await expect(page.locator('.dashboard')).toBeVisible();
  const screenshot = await page.screenshot();
  await allure.attachment('Dashboard Screenshot', screenshot, 'image/png');
});

Generating the Report

After running tests:

npx playwright test

<span class="hljs-comment"># Generate the HTML report
npx allure generate allure-results --clean -o allure-report

<span class="hljs-comment"># Open in browser
npx allure open allure-report

Or add to package.json:

{
  "scripts": {
    "test": "playwright test",
    "report": "allure generate allure-results --clean -o allure-report && allure open allure-report",
    "test:report": "npm test && npm run report"
  }
}

The most powerful Allure feature requires persisting history between runs. Copy the history directory before generating:

# Before running tests, restore history
<span class="hljs-built_in">cp -r allure-report/history allure-results/history 2>/dev/null <span class="hljs-pipe">|| <span class="hljs-literal">true

<span class="hljs-comment"># Run tests
npx playwright <span class="hljs-built_in">test

<span class="hljs-comment"># Generate with history
npx allure generate allure-results --clean -o allure-report

In CI (GitHub Actions):

- name: Restore Allure history
  uses: actions/cache@v3
  with:
    path: allure-report/history
    key: allure-history-${{ github.ref }}
    restore-keys: allure-history-

- name: Run tests
  run: npx playwright test

- name: Copy history to results
  run: cp -r allure-report/history allure-results/history 2>/dev/null || true

- name: Generate Allure Report
  run: npx allure generate allure-results --clean -o allure-report

- name: Save Allure history
  uses: actions/cache@v3
  with:
    path: allure-report/history
    key: allure-history-${{ github.ref }}

- name: Upload report artifact
  uses: actions/upload-artifact@v3
  with:
    name: allure-report
    path: allure-report/

Categorizing Test Failures

Create allure-results/categories.json to auto-classify failures:

[
  {
    "name": "Product Defects",
    "matchedStatuses": ["failed"],
    "messageRegex": ".*Expected.*Received.*"
  },
  {
    "name": "Timeout Issues",
    "matchedStatuses": ["broken"],
    "messageRegex": ".*Timeout.*exceeded.*"
  },
  {
    "name": "Network Errors",
    "matchedStatuses": ["broken"],
    "messageRegex": ".*net::ERR.*|.*ECONNREFUSED.*"
  }
]

This gives you an instant breakdown: how many failures are real bugs vs. infrastructure noise vs. flaky network calls.

Integrating with HelpMeTest

If you're running continuous monitoring alongside your Playwright suite, HelpMeTest can run your tests on a schedule and alert you when they start failing — without you having to check reports manually. The combination of Allure for detailed post-mortem analysis and HelpMeTest for proactive alerting covers both ends of the observability spectrum.

Troubleshooting Common Issues

Report shows no tests: Check that allure-results/ contains .json files. If the folder is empty, the reporter wasn't configured correctly.

Videos not appearing: Set video: 'retain-on-failure' and ensure allure-playwright version matches your Playwright version.

History not loading: The history subfolder must be inside allure-results/ before you run allure generate, not after.

Slow report generation: Large suites with many attachments slow generation. Use --single-file flag to get a portable single HTML file instead of a directory.

Summary

Allure 2 + Playwright gives you production-grade test reporting without custom tooling. The key steps: install allure-playwright, configure the reporter, annotate tests with steps and metadata, persist history between CI runs, and categorize failures for fast triage. The result is a report your whole team — not just engineers — can actually use.

Read more