user-journeys

安装量: 134
排名: #6445

安装

npx skills add https://github.com/alinaqi/claude-bootstrap --skill user-journeys

User Journeys Skill

Load with: base.md + playwright-testing.md

For defining and testing real user experiences - not just specs, but actual flows humans take through your application.

Philosophy

Specs test features. Journeys test experiences.

A feature can pass all specs but still deliver a terrible experience. User journeys capture:

How users actually navigate (not how we think they should) Emotional states at each step (frustrated, confused, delighted) Recovery from mistakes (users will make them) Real-world conditions (slow networks, interruptions, distractions) Journey Documentation Structure _project_specs/ ├── journeys/ │ ├── _template.md # Journey template │ ├── critical/ # Must-work journeys (revenue, core value) │ │ ├── signup-to-first-value.md │ │ ├── checkout-purchase.md │ │ └── login-to-dashboard.md │ ├── common/ # Frequent user paths │ │ ├── browse-and-search.md │ │ ├── update-profile.md │ │ └── invite-team-member.md │ └── edge-cases/ # Error recovery, unusual paths │ ├── payment-failure-retry.md │ ├── session-timeout-recovery.md │ └── offline-reconnection.md

Journey Template

Journey: [Name]

Overview

| Attribute | Value |

|-----------|-------|

| Priority | Critical / High / Medium |

| User Type | New / Returning / Admin |

| Frequency | Daily / Weekly / One-time |

| Success Metric | Conversion rate, time to complete, drop-off rate |

User Goal

What is the user trying to accomplish? Write from their perspective.

"I want to [goal] so that I can [benefit]."

Preconditions

  • User state (logged in, has subscription, first visit)
  • Data state (has items in cart, has team members)
  • Environment (mobile, desktop, slow connection)

Journey Steps

Step 1: [Entry Point]

User Action: What the user does System Response: What they should see/experience Success Criteria: - [ ] Page loads in < 2 seconds - [ ] Primary CTA is immediately visible - [ ] User understands what to do next

Potential Friction: - Slow load time → Show skeleton/loader - Unclear CTA → A/B test copy variations


Step 2: [Next Action]

User Action: ... System Response: ... Success Criteria: - [ ] ...

Potential Friction: - ...


Error Scenarios

E1: [Error Name]

Trigger: What causes this error User Sees: Error message/state Recovery Path: How user gets back on track Test: How to verify recovery works

Metrics to Track

  • Time to complete journey
  • Drop-off rate at each step
  • Error rate and recovery rate
  • User satisfaction (if surveyed)

E2E Test Reference

Link to Playwright test: e2e/tests/journeys/[name].spec.ts

Critical Journey Examples Signup to First Value

Journey: Signup to First Value

Overview

| Attribute | Value |

|-----------|-------|

| Priority | Critical |

| User Type | New |

| Frequency | One-time |

| Success Metric | % reaching "aha moment" within 5 min |

User Goal

"I want to try this product quickly to see if it solves my problem."

Preconditions

  • First visit to site
  • No account
  • Came from landing page or ad

Journey Steps

Step 1: Landing Page

User Action: Clicks "Get Started Free" or "Try Now" System Response: Signup form appears (modal or new page) Success Criteria: - [ ] CTA visible above fold - [ ] No distracting elements - [ ] Clear value proposition visible

Potential Friction: - Too many form fields → Reduce to email + password only - Social login missing → Add Google/GitHub options

Step 2: Account Creation

User Action: Enters email and password (or uses social login) System Response: - Creates account - Sends verification email (don't block on it) - Redirects to onboarding

Success Criteria: - [ ] Account created in < 3 seconds - [ ] No email verification wall (verify later) - [ ] Clear next step shown

Potential Friction: - Email already exists → Offer login link - Weak password → Show requirements inline, not after submit

Step 3: Onboarding (Quick Win)

User Action: Completes 1-2 setup questions System Response: - Personalizes experience - Shows progress indicator - Leads to first action

Success Criteria: - [ ] Max 3 questions - [ ] Skip option available - [ ] < 60 seconds total

Potential Friction: - Too many questions → User abandons - No skip option → User feels trapped

Step 4: First Value (Aha Moment)

User Action: Completes core action (creates first X, sees first result) System Response: - Celebrates success - Shows value delivered - Suggests next step

Success Criteria: - [ ] User experiences core value - [ ] Completion feels rewarding - [ ] Clear path to continue

Error Scenarios

E1: Email Already Registered

Trigger: User tries existing email User Sees: "Already have an account? Log in or reset password" Recovery Path: Click to login or reset Test: signup-existing-email.spec.ts

E2: Social Login Fails

Trigger: OAuth provider error User Sees: "Couldn't connect. Try email signup or try again." Recovery Path: Email signup form shown as fallback Test: social-login-failure.spec.ts

Metrics to Track

  • Signup → First Value: Target < 5 min
  • Drop-off at each step
  • Social vs email signup ratio
  • Skip rate on onboarding

Checkout Purchase

Journey: Checkout Purchase

Overview

| Attribute | Value |

|-----------|-------|

| Priority | Critical (Revenue) |

| User Type | Any |

| Frequency | Variable |

| Success Metric | Checkout completion rate |

User Goal

"I want to pay quickly and securely without surprises."

Journey Steps

Step 1: Cart Review

User Action: Views cart before checkout System Response: - Shows all items with images, prices - Shows subtotal, taxes, shipping - Clear "Checkout" CTA

Success Criteria: - [ ] No hidden fees revealed later - [ ] Easy to modify quantities - [ ] Saved items visible

Step 2: Checkout Start

User Action: Clicks "Checkout" System Response: - Shows checkout form or redirect to payment - Progress indicator (Step 1 of 3) - Order summary sidebar

Success Criteria: - [ ] Guest checkout option - [ ] Express checkout (Apple/Google Pay) prominent - [ ] Form fields pre-filled if logged in

Step 3: Payment

User Action: Enters payment info System Response: - Secure input fields (Stripe/payment provider) - Real-time validation - Clear "Pay $XX" button

Success Criteria: - [ ] Card validation inline, not after submit - [ ] Multiple payment options - [ ] Security indicators visible

Step 4: Confirmation

User Action: Submits payment System Response: - Processing indicator - Success page with order details - Email confirmation sent

Success Criteria: - [ ] Confirmation within 5 seconds - [ ] Order number clearly visible - [ ] Next steps clear (shipping, access, etc.)

Error Scenarios

E1: Payment Declined

Trigger: Card declined by processor User Sees: "Payment declined. Please try another card." Recovery Path: - Stay on payment step - Pre-fill other fields - Offer alternative payment methods Test: payment-declined-recovery.spec.ts

E2: Session Timeout During Checkout

Trigger: User away too long User Sees: Cart preserved, re-auth required Recovery Path: - Quick login - Return to same checkout step - Cart contents intact Test: checkout-session-timeout.spec.ts

Journey Testing with Playwright Journey Test Structure // e2e/tests/journeys/signup-to-value.spec.ts import { test, expect } from '@playwright/test';

test.describe('Journey: Signup to First Value', () => { test.describe.configure({ mode: 'serial' }); // Run in order

test('Step 1: Landing page has clear CTA', async ({ page }) => { await page.goto('/');

// CTA visible above fold without scrolling
const cta = page.getByRole('button', { name: /get started|try free/i });
await expect(cta).toBeVisible();
await expect(cta).toBeInViewport();

});

test('Step 2: Can create account quickly', async ({ page }) => { await page.goto('/'); await page.getByRole('button', { name: /get started/i }).click();

// Minimal fields
await expect(page.getByLabel('Email')).toBeVisible();
await expect(page.getByLabel('Password')).toBeVisible();

// Complete signup
const startTime = Date.now();
await page.getByLabel('Email').fill('newuser@example.com');
await page.getByLabel('Password').fill('SecurePass123!');
await page.getByRole('button', { name: /sign up|create/i }).click();

// Should reach onboarding quickly
await expect(page).toHaveURL(/onboarding|welcome|setup/);
expect(Date.now() - startTime).toBeLessThan(5000); // < 5 seconds

});

test('Step 3: Onboarding is skippable', async ({ page }) => { // ... login as new user ... await page.goto('/onboarding');

// Skip option exists
const skipButton = page.getByRole('button', { name: /skip/i });
await expect(skipButton).toBeVisible();

});

test('Step 4: Can reach first value in < 5 min', async ({ page }) => { // Full journey timing const journeyStart = Date.now();

// ... complete full journey ...

// Verify first value delivered
await expect(page.getByText(/success|created|done/i)).toBeVisible();

// Total time check
const totalTime = (Date.now() - journeyStart) / 1000 / 60; // minutes
expect(totalTime).toBeLessThan(5);

}); });

Error Recovery Tests // e2e/tests/journeys/checkout-recovery.spec.ts import { test, expect } from '@playwright/test';

test.describe('Journey: Checkout Error Recovery', () => { test('recovers from payment decline gracefully', async ({ page }) => { // Setup: Add item to cart, go to checkout await page.goto('/products'); await page.getByTestId('add-to-cart').first().click(); await page.getByRole('link', { name: 'Checkout' }).click();

// Use Stripe test card that declines
const stripeFrame = page.frameLocator('iframe[name*="stripe"]');
await stripeFrame.getByPlaceholder('Card number').fill('4000000000000002');
await stripeFrame.getByPlaceholder('MM / YY').fill('12/30');
await stripeFrame.getByPlaceholder('CVC').fill('123');

await page.getByRole('button', { name: /pay/i }).click();

// Verify friendly error
await expect(page.getByText(/declined|try another/i)).toBeVisible();

// Verify still on checkout (not kicked out)
await expect(page).toHaveURL(/checkout/);

// Verify can try again with different card
await stripeFrame.getByPlaceholder('Card number').fill('4242424242424242');
await page.getByRole('button', { name: /pay/i }).click();

// Should succeed now
await expect(page).toHaveURL(/success|confirmation/);

});

test('preserves cart after session timeout', async ({ page, context }) => { // Add items to cart await page.goto('/products'); await page.getByTestId('add-to-cart').first().click();

// Clear session (simulate timeout)
await context.clearCookies();

// Return to site
await page.goto('/cart');

// Cart should be preserved (local storage or recovered)
await expect(page.getByTestId('cart-item')).toHaveCount(1);

}); });

User Experience Validation UX Checklist per Journey Step

UX Validation Checklist

Clarity

  • [ ] User knows where they are (breadcrumbs, progress)
  • [ ] User knows what to do next (clear CTA)
  • [ ] User knows what just happened (feedback)

Speed

  • [ ] Page loads < 2 seconds
  • [ ] Actions complete < 3 seconds
  • [ ] Progress shown for longer operations

Forgiveness

  • [ ] Mistakes are easy to undo
  • [ ] Errors explain what went wrong
  • [ ] Recovery path is clear

Accessibility

  • [ ] Keyboard navigation works
  • [ ] Screen reader announces changes
  • [ ] Focus management correct
  • [ ] Color contrast sufficient

Mobile

  • [ ] Touch targets >= 44px
  • [ ] No horizontal scroll
  • [ ] Forms don't zoom unexpectedly
  • [ ] Works on slow 3G

Automated UX Checks // e2e/utils/ux-validators.ts import { Page, expect } from '@playwright/test';

export async function validatePageLoad(page: Page, maxMs = 2000) { const timing = await page.evaluate(() => { const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming; return nav.loadEventEnd - nav.startTime; }); expect(timing).toBeLessThan(maxMs); }

export async function validateCTAVisible(page: Page, ctaText: RegExp) { const cta = page.getByRole('button', { name: ctaText }); await expect(cta).toBeVisible(); await expect(cta).toBeInViewport(); }

export async function validateNoLayoutShift(page: Page) { const cls = await page.evaluate(() => { return new Promise((resolve) => { let clsValue = 0; const observer = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (!(entry as any).hadRecentInput) { clsValue += (entry as any).value; } } }); observer.observe({ type: 'layout-shift', buffered: true }); setTimeout(() => { observer.disconnect(); resolve(clsValue); }, 1000); }); }); expect(cls).toBeLessThan(0.1); // Good CLS score }

export async function validateAccessibility(page: Page) { // Check focus visible on interactive elements const buttons = page.getByRole('button'); const count = await buttons.count();

for (let i = 0; i < Math.min(count, 5); i++) { await buttons.nth(i).focus(); await expect(buttons.nth(i)).toBeFocused(); } }

Journey Metrics Dashboard

Track journey health with these metrics:

// lib/journey-metrics.ts interface JourneyMetric { journey: string; step: string; timestamp: Date; duration: number; success: boolean; userId?: string; }

// Track in your analytics (PostHog, Mixpanel, etc.) export function trackJourneyStep(metric: JourneyMetric) { analytics.track('journey_step', { journey_name: metric.journey, step_name: metric.step, duration_ms: metric.duration, success: metric.success, }); }

// Example usage in app const journeyStart = Date.now(); // ... user completes step ... trackJourneyStep({ journey: 'signup_to_value', step: 'account_creation', timestamp: new Date(), duration: Date.now() - journeyStart, success: true, });

Common Journey Patterns Progressive Disclosure Journey

User sees simple view first, complexity revealed as needed.

Step 1: Show basic options only Step 2: "Advanced" expands more options Step 3: Expert mode unlocks everything

Guided Setup Journey

Hand-hold new users through initial configuration.

Step 1: Welcome + single choice Step 2: Core preference Step 3: Optional integrations (skippable) Step 4: First action with guidance Step 5: Success + remove training wheels

Recovery Journey

User returns after failure or abandonment.

Step 1: Recognize returning user Step 2: Restore previous state Step 3: Acknowledge what happened Step 4: Offer clear path forward Step 5: Complete original goal

Anti-Patterns Happy path only - Test error recovery, not just success Spec-driven testing - Test user goals, not features Ignoring time - Measure how long journeys take Desktop-only - Test mobile journeys separately Skipping emotions - Consider user frustration points No metrics - Track journey completion and drop-off Static journeys - Update as user behavior evolves Quick Reference Journey Priorities Priority Criteria Test Frequency Critical Revenue, core value Every deploy High Daily user actions Daily Medium Weekly features Weekly Low Edge cases On change Package.json Scripts { "scripts": { "test:journeys": "playwright test e2e/tests/journeys/", "test:journeys:critical": "playwright test e2e/tests/journeys/critical/", "test:journeys:report": "playwright show-report" } }

Journey Documentation Checklist User goal clearly stated All steps documented Success criteria per step Error scenarios covered Recovery paths defined Metrics identified E2E test linked

返回排行榜