๐ŸŽญ

Smash-QA-Framework

End-to-End Testing Strategy & Documentation

๐ŸŽฏ Overview

The Smash-QA-Framework is a comprehensive end-to-end test automation solution built with Playwright and TypeScript for testing Smashburger's online ordering platform at dev.smashburger.com. This framework validates the complete customer journey from menu browsing to order confirmation, ensuring a flawless digital ordering experience.

๐Ÿ” What We Test

  • Complete ordering workflow
  • Custom burger creation
  • Location selection (Pickup)
  • Cart management
  • Checkout & payment flow
  • Order confirmation

๐Ÿ› ๏ธ How We Test

  • Page Object Model (POM)
  • Data-driven scenarios
  • Fixtures for reusability
  • Parallel execution
  • CI/CD integration
  • Automated reporting

โšก Key Features

  • TypeScript for type safety
  • Semantic locators
  • Fast execution (30s/test)
  • Screenshot on failure
  • GitHub Pages reports
  • Mock data support

๐Ÿ“‹ Tech Stack Analysis

Based on DOM and network inspection, the Smashburger website (https://dev.smashburger.com) is built with modern, scalable technologies:

โš›๏ธ Core Frameworks

  • Next.js (React)
  • React
  • Tailwind CSS

๐Ÿ“Š Data Management

  • React Query
  • Via dehydratedState

๐Ÿ”Œ Third-Party

  • Google Tag Manager
  • Google Maps API
  • Google reCAPTCHA
  • Braze (engagement)
  • TrustArc (consent)

โ˜๏ธ Infrastructure

  • Cloudflare CDN
  • AWS S3 (assets)
  • Google Fonts
๐Ÿ’ก Implication: This stack implies modern, scalable, and component-driven front-end architecture optimized for performance and user experience.

๐Ÿ”Œ Observed APIs

Location & Menu

GET /api/location/search?query=80246
GET /api/location/menu
GET /api/location

Basket & Ordering

POST /api/basket
GET /api/basket
POST /api/basket/products
GET /api/basket/delivery-mode
POST /api/basket/validate
GET /api/basket/freedompay-iframe?billingMethod=creditcard

Page Data (Next.js)

GET /_next/data/.../menu/smashburgers/create-your-own.json
GET /_next/data/.../cart.json
GET /_next/data/.../cart/checkout.json
๐Ÿ’ก Key Insight: UI tests heavily rely on backend APIs. Failures may originate in backend rather than UI. Hybrid API+UI tests or API health monitoring could reduce flakiness and improve reliability.

๐Ÿ’ก Recommendations: Shift Left Testing Strategy

Based on the observed API dependencies, we recommend implementing a comprehensive Shift Left testing approach to catch defects earlier in the development cycle, reduce costs, and improve overall quality.

๐Ÿ”„ The Testing Pyramid

Move from heavy reliance on E2E tests to a balanced pyramid approach:

๐Ÿงฑ Unit Tests

Coverage: 70-80%

  • Fast execution (milliseconds)
  • Test individual functions/components
  • Low maintenance cost
  • High confidence in code quality

๐Ÿ”— Integration Tests

Coverage: 15-20%

  • Medium execution time (seconds)
  • Test API endpoints & database
  • Validate data flow
  • Catch integration issues early

๐Ÿ“‹ Contract Tests

Coverage: 5%

  • Fast execution (seconds)
  • Verify API contracts
  • Provider/Consumer validation
  • Prevent breaking changes

๐ŸŽญ E2E Tests

Coverage: 5-10%

  • Slow execution (30s per test)
  • Critical user journeys only
  • High maintenance cost
  • Focus on business value

๐ŸŽฏ Recommended Implementation Strategy

1. Unit Tests (Backend & Frontend)

Backend API Unit Tests:

// Example: Test basket creation logic
describe('Basket Service', () => {
  it('should create basket with valid VendorId', () => {
    const basket = basketService.create({ vendorId: '12345' });
    expect(basket.vendorId).toBe('12345');
    expect(basket.items).toEqual([]);
  });
  
  it('should throw error for invalid VendorId', () => {
    expect(() => basketService.create({ vendorId: null }))
      .toThrow('VendorId is required');
  });
});

Frontend Component Unit Tests:

// Example: Test CartItem component
describe('CartItem Component', () => {
  it('should display item name and price', () => {
    const item = { name: 'Classic Smash', price: 8.99 };
    render(<CartItem item={item} />);
    expect(screen.getByText('Classic Smash')).toBeInTheDocument();
    expect(screen.getByText('$8.99')).toBeInTheDocument();
  });
  
  it('should display fallback image when image URL missing', () => {
    const item = { name: 'Custom Burger', image: null };
    render(<CartItem item={item} />);
    const img = screen.getByRole('img');
    expect(img).toHaveAttribute('src', '/fallback-burger.png');
  });
});

2. Integration Tests (API Layer)

Test API endpoints with real database interactions:

// Example: Test basket API endpoints
describe('POST /api/basket', () => {
  it('should create basket and return basketId', async () => {
    const response = await request(app)
      .post('/api/basket')
      .send({ vendorId: '12345' })
      .expect(201);
    
    expect(response.body).toHaveProperty('basketId');
    expect(response.body.vendorId).toBe('12345');
  });
});

describe('POST /api/basket/products', () => {
  it('should add product to existing basket', async () => {
    const basketId = await createTestBasket();
    
    const response = await request(app)
      .post('/api/basket/products')
      .send({
        basketId,
        productId: 'burger-001',
        quantity: 1,
        options: { bun: 'classic', patty: 'double' }
      })
      .expect(200);
    
    expect(response.body.items).toHaveLength(1);
    expect(response.body.items[0].productId).toBe('burger-001');
  });
});

Key Integration Test Areas:

  • โœ… /api/location/* - Location search and menu retrieval
  • โœ… /api/basket/* - Basket creation, product addition, validation
  • โœ… /api/basket/delivery-mode - Pickup/delivery options
  • โœ… Database transactions - Ensure data consistency
  • โœ… External API integrations - Google Maps, payment gateway

3. Contract Tests (API Contracts)

Use tools like Pact or Spring Cloud Contract to ensure API contracts are honored:

// Example: Consumer-driven contract test
describe('Basket API Contract', () => {
  const provider = new Pact({
    consumer: 'SmashburgerUI',
    provider: 'BasketService'
  });
  
  it('should return basket with items', async () => {
    await provider.addInteraction({
      state: 'basket exists with items',
      uponReceiving: 'a request for basket',
      withRequest: {
        method: 'GET',
        path: '/api/basket',
        query: { basketId: '12345' }
      },
      willRespondWith: {
        status: 200,
        body: {
          basketId: '12345',
          items: Matchers.eachLike({
            productId: Matchers.string('burger-001'),
            name: Matchers.string('Classic Smash'),
            price: Matchers.decimal(8.99),
            quantity: Matchers.integer(1)
          })
        }
      }
    });
    
    // Consumer test validates the contract
    const basket = await basketClient.getBasket('12345');
    expect(basket.items).toBeDefined();
  });
});

Benefits of Contract Testing:

  • โœ… Prevent breaking changes to API contracts
  • โœ… Enable independent deployment of services
  • โœ… Fast feedback (runs in seconds)
  • โœ… Clear communication between frontend and backend teams

4. E2E Tests (Critical User Journeys)

Focus only on the most important business-critical scenarios:

  • โœ… Complete burger ordering flow (Create Your Own)
  • โœ… Pickup order placement and confirmation
  • โœ… Cart modifications and checkout
  • โŒ Avoid: Testing every burger variant (covered by lower layers)
  • โŒ Avoid: Testing API response formats (covered by contract tests)
  • โŒ Avoid: Testing individual component rendering (covered by unit tests)

E2E Test Optimization:

  • Keep tests under 30 seconds per scenario
  • Use API calls for test setup (faster than UI interactions)
  • Mock external dependencies when possible
  • Run E2E tests only for smoke testing in CI/CD

๐Ÿ“Š Expected Benefits

โšก Faster Feedback

Catch defects in seconds (unit tests) instead of minutes (E2E tests)

๐Ÿ’ฐ Lower Costs

Defects found early are 10-100x cheaper to fix than in production

๐Ÿ”ง Easier Maintenance

Unit/integration tests are more stable and easier to debug than E2E

๐Ÿ“ˆ Higher Coverage

Test more scenarios without exponentially increasing execution time

๐ŸŽฏ Shift Left Recommendation: Implement unit tests and integration tests for the observed APIs (/api/basket/*, /api/location/*) before expanding E2E coverage. This will provide faster feedback, reduce flakiness, and lower maintenance costs while ensuring comprehensive quality coverage across all layers.

๐Ÿงช Testing Strategy

Core Testing Principles

  • Scope: Focus on UI automation with Playwright + TypeScript, minimal framework overhead
  • Primary Flow: E2E burger ordering โ€” pickup order via "Create Your Own Burger" page
  • Data Setup: Use ZIP code 80246, select the first available restaurant
  • Validation Points: Ensure order details are consistent across Cart, Checkout, and Order Details pages
  • Design Pattern: Page Object Model (POM), modular code, fixtures for setup, utilities for reusability
  • Resilience: Prefer data-testid/ID locators, handle dynamic elements properly with proper waits
  • Quality: Parallel execution (3 workers), headless runs, screenshot capture on failures

๐Ÿ“‹ Test Coverage

1. Ordering a Burger (E2E Scenario)

Test Case: Place a pickup order with "Create Your Own" burger

Implementation: tests/pickup-create-your-own-order.spec.ts

  • Test URL: Create Your Own Burger Page
  • Flow:
    1. Navigate to Create Your Own page (product.gotoCreateYourOwn())
    2. Select pickup location by ZIP code 80246 (bootstrapPickupAtZip())
    3. Configure burger with custom options (create.createBurger(burger))
    4. Add to cart and proceed to checkout
    5. Verify cart displays correct burger details
    6. Fill customer information (name, email, phone)
    7. Fill payment information (credit card via iframe)
    8. Place order and verify confirmation page
  • Validations:
    • โœ… Cart page: Verify size, bun, cheese, toppings, sauces, add-ons
    • โœ… Checkout page: Verify order summary matches selections
    • โœ… Confirmation page: Verify "Thank You", order number, pickup details
    • โœ… End-to-end consistency across all pages

2. Data-Driven Testing Scenarios

Implementation: tests/pickup-orders-dataset.spec.ts

Data Source: test-data/burger-combinations.json

  • Test Approach: Parameterized tests using JSON data sets
  • Burger Customization Variants Covered:
    • Protein options: Double Beef, Single Beef, Crispy Chicken, Double Chicken, Turkey, Black Bean
    • Bun types: Classic, Spicy Chipotle
    • Cheese varieties: American, Aged Swiss, Pepper Jack, Aged Cheddar
    • Toppings: Lettuce, Tomatoes, Red Onion, Pickles, Jalapeรฑos, Grilled options
    • Sauces: Smash Sauceยฎ, Mayo, Ranch, BBQ, Chipotle Ranch, Truffle Mayo
    • Premium Add-ons: Applewood Smoked Bacon, Smashed Avocado
  • Test Execution:
    • 6 different burger scenarios from data file
    • Each scenario tests complete E2E flow
    • Parallel execution for faster feedback
    • Single customer profile (default) with ZIP 80246

3. Cart Page Item's Image Validation

Implementation: tests/cart-placeholder-images.spec.ts

Objective: Validate image handling for cart items with placeholder/missing images

Test Scenario

  • Setup: Add 3 items to cart from test-data/mock-cart-items.json
  • Items tested:
    • Double Smoked Brisket Bacon Smashยฎ (qty: 1)
    • Chili Cheese Dog (qty: 2)
    • Large French Fries (qty: 3)
  • Action: Navigate to Cart Page
  • Mock Implementation: Use Playwright route interception to replace placeholder images with actual burger image

Implementation Details

// Route interception for placeholder images
await page.route('**/placeholder.e96474ea.jpg', async (route) => {
  // Fetch the actual fallback image
  const response = await page.request.get(PLACEHOLDER_IMAGE_URL);
  const body = await response.body();
  
  // Fulfill request with real image
  await route.fulfill({
    status: 200,
    contentType: 'image/png',
    body
  });
});

// Verify all cart images are visible
const cartImages = page.getByRole('img', { name: /cart item/i });
const count = await cartImages.count();
for (let i = 0; i < count; i++) {
  await expect(cartImages.nth(i)).toBeVisible();
}

Validation Points

  • โœ… All cart items display images after route interception
  • โœ… Placeholder image URL (placeholder.e96474ea.jpg) is intercepted
  • โœ… Replacement image loaded successfully from S3
  • โœ… Images are visible in DOM (toBeVisible())
  • โœ… Cart layout remains consistent with images

๐ŸŽฏ Test Execution

โšก Parallel Execution

Tests run with 3 workers for faster execution and efficient resource utilization

๐Ÿ”„ Continuous Integration

Automated runs on push/PR to main branch via GitHub Actions

๐Ÿ“Š Reporting

HTML reports deployed to GitHub Pages automatically with full test artifacts

๐Ÿ” Quality Gates

Screenshot on failure, continue-on-error for visibility, detailed test summaries

๐Ÿ”’ Test Data Strategy

Environment Configuration

  • Base URL: https://dev.smashburger.com
  • Test ZIP Code: 80246 (Denver, CO area)
  • Restaurant Selection: First available location
  • Payment Method: Test credit card data https://neapay.com/online-tools/credit-card-number-generator-validator.html

Test User Management

Guest checkout flow primarily tested to avoid account dependencies and simplify test maintenance.

๐Ÿ“ˆ Success Metrics

Performance Targets

  • E2E Scenario Execution Time: Under 30 seconds per test scenario
  • Full Suite Execution: Complete within CI/CD pipeline timeout (60 minutes max)
  • Test Reliability: 95%+ pass rate on consecutive runs
  • Defect Detection: UI regressions caught before production deployment

Coverage Goals

  • โœ… Critical user journey: Create Your Own burger order (E2E)
  • โœ… Data-driven scenarios for typical food ordering flows
  • โœ… Cross-browser compatibility (Chromium, Firefox, WebKit)
  • โœ… Mobile viewport testing for responsive design
๐ŸŽฏ Primary Goal: Ensure every Smashburger customer gets a flawless digital ordering experience from menu browsing to order confirmation, with each E2E scenario completing in under 30 seconds for rapid feedback.