Files
claude-skills-reference/engineering-team/playwright-pro/templates/onboarding/welcome-tour.md
Alireza Rezvani d33d03da50 feat: add playwright-pro plugin — production-grade Playwright testing toolkit (#254)
Complete Claude Code plugin with:
- 9 skills (/pw:init, generate, review, fix, migrate, coverage, testrail, browserstack, report)
- 3 specialized agents (test-architect, test-debugger, migration-planner)
- 55 test case templates across 11 categories (auth, CRUD, checkout, search, forms, dashboard, settings, onboarding, notifications, API, accessibility)
- TestRail MCP server (TypeScript) — 8 tools for bidirectional sync
- BrowserStack MCP server (TypeScript) — 7 tools for cross-browser testing
- Smart hooks (auto-validate tests, auto-detect Playwright projects)
- 6 curated reference docs (golden rules, locators, assertions, fixtures, pitfalls, flaky tests)
- Leverages Claude Code built-ins (/batch, /debug, Explore subagent)
- Zero-config for core features; TestRail/BrowserStack via env vars
- Both TypeScript and JavaScript support throughout

Co-authored-by: Leo <leo@openclaw.ai>
2026-03-05 13:50:05 +01:00

4.8 KiB
Raw Blame History

Welcome Tour Template

Tests step-by-step onboarding tour, skip, and completion behaviour.

Prerequisites

  • Newly registered session (first login) via {{newUserStorageStatePath}}
  • Tour has {{tourStepCount}} steps
  • App running at {{baseUrl}}

TypeScript

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

test.describe('Welcome Tour', () => {
  test.use({ storageState: '{{newUserStorageStatePath}}' });

  // Happy path: tour shown on first login
  test('shows welcome tour on first login', async ({ page }) => {
    await page.goto('{{baseUrl}}/dashboard');
    await expect(page.getByRole('dialog', { name: /welcome|tour/i })).toBeVisible();
    await expect(page.getByText(/step 1 of {{tourStepCount}}/i)).toBeVisible();
  });

  // Happy path: advance through all steps
  test('advances through all tour steps', async ({ page }) => {
    await page.goto('{{baseUrl}}/dashboard');
    for (let i = 1; i <= {{tourStepCount}}; i++) {
      await expect(page.getByText(new RegExp(`step ${i} of {{tourStepCount}}`, 'i'))).toBeVisible();
      if (i < {{tourStepCount}}) {
        await page.getByRole('button', { name: /next/i }).click();
      } else {
        await page.getByRole('button', { name: /finish|done|get started/i }).click();
      }
    }
    await expect(page.getByRole('dialog', { name: /welcome|tour/i })).toBeHidden();
  });

  // Happy path: back navigation within tour
  test('navigates back to previous step', async ({ page }) => {
    await page.goto('{{baseUrl}}/dashboard');
    await page.getByRole('button', { name: /next/i }).click();
    await expect(page.getByText(/step 2 of {{tourStepCount}}/i)).toBeVisible();
    await page.getByRole('button', { name: /back|previous/i }).click();
    await expect(page.getByText(/step 1 of {{tourStepCount}}/i)).toBeVisible();
  });

  // Happy path: skip tour
  test('skips tour and dismisses overlay', async ({ page }) => {
    await page.goto('{{baseUrl}}/dashboard');
    await page.getByRole('button', { name: /skip.*tour|skip/i }).click();
    await expect(page.getByRole('dialog', { name: /welcome|tour/i })).toBeHidden();
    await expect(page.getByRole('heading', { name: /dashboard/i })).toBeVisible();
  });

  // Happy path: tour not shown on subsequent logins
  test('tour not shown on second login', async ({ page }) => {
    await page.goto('{{baseUrl}}/dashboard');
    // Complete or skip tour
    await page.getByRole('button', { name: /skip.*tour|skip/i }).click();
    // Simulate re-login by reloading
    await page.reload();
    await expect(page.getByRole('dialog', { name: /welcome|tour/i })).toBeHidden();
  });

  // Happy path: tooltip highlights correct element
  test('tour tooltip highlights the correct UI element', async ({ page }) => {
    await page.goto('{{baseUrl}}/dashboard');
    const tooltip = page.getByRole('tooltip').or(page.getByRole('dialog', { name: /tour/i }));
    await expect(tooltip).toBeVisible();
    const targetEl = page.getByRole('{{tourStep1TargetRole}}', { name: /{{tourStep1TargetName}}/i });
    await expect(targetEl).toBeVisible();
  });

  // Edge case: close button (×) dismisses tour
  test('× button dismisses tour', async ({ page }) => {
    await page.goto('{{baseUrl}}/dashboard');
    await page.getByRole('dialog', { name: /welcome|tour/i })
      .getByRole('button', { name: /close|×/i }).click();
    await expect(page.getByRole('dialog', { name: /welcome|tour/i })).toBeHidden();
  });
});

JavaScript

const { test, expect } = require('@playwright/test');

test.describe('Welcome Tour', () => {
  test.use({ storageState: '{{newUserStorageStatePath}}' });

  test('shows welcome tour on first login', async ({ page }) => {
    await page.goto('{{baseUrl}}/dashboard');
    await expect(page.getByRole('dialog', { name: /welcome|tour/i })).toBeVisible();
  });

  test('skips tour on button click', async ({ page }) => {
    await page.goto('{{baseUrl}}/dashboard');
    await page.getByRole('button', { name: /skip/i }).click();
    await expect(page.getByRole('dialog', { name: /tour/i })).toBeHidden();
  });

  test('advances through all steps to completion', async ({ page }) => {
    await page.goto('{{baseUrl}}/dashboard');
    for (let i = 1; i < {{tourStepCount}}; i++) {
      await page.getByRole('button', { name: /next/i }).click();
    }
    await page.getByRole('button', { name: /finish|done|get started/i }).click();
    await expect(page.getByRole('dialog', { name: /tour/i })).toBeHidden();
  });
});

Variants

Variant Description
Tour on first login Dialog shown with step 1 of N
Full completion All steps advanced → tour dismissed
Back navigation Previous step accessible
Skip tour Dismissed immediately
Not shown again Tour absent on subsequent visits
Tooltip target Tour highlights correct element
Close button × closes tour