Browser Testing

Master Raiken's multi-browser testing capabilities to ensure your application works consistently across Chromium, Firefox, and WebKit browsers.

Overview

Raiken provides comprehensive multi-browser testing support through Playwright, enabling you to test your application across different browser engines with consistent APIs and rich reporting capabilities.

Supported Browsers

Chromium

  • Based on: Google Chrome and Microsoft Edge
  • Use Cases: Primary testing browser, most web applications
  • Features: Full DevTools protocol support, perfect video recording
  • Mobile Testing: Android emulation

Firefox

  • Based on: Mozilla Firefox
  • Use Cases: Cross-browser compatibility, Gecko engine testing
  • Features: Excellent screenshot capabilities, privacy-focused testing
  • Mobile Testing: Limited mobile emulation

WebKit

  • Based on: Safari browser engine
  • Use Cases: Safari compatibility, iOS behavior testing
  • Features: Native macOS/iOS behavior simulation
  • Mobile Testing: iOS Safari emulation

Browser Configuration

Default Settings

Raiken comes with optimized browser configurations:

// playwright.config.ts (auto-generated by Raiken)
export default {
  projects: [
    {
      name: 'chromium',
      use: { 
        ...devices['Desktop Chrome'],
        video: 'retain-on-failure',
        screenshot: 'only-on-failure'
      },
    },
    {
      name: 'firefox',
      use: { 
        ...devices['Desktop Firefox'],
        video: 'retain-on-failure',
        screenshot: 'only-on-failure'
      },
    },
    {
      name: 'webkit',
      use: { 
        ...devices['Desktop Safari'],
        video: 'retain-on-failure',
        screenshot: 'only-on-failure'
      },
    },
  ],
}

Custom Browser Settings

Configure browsers through Raiken's interface:

  1. Open Settings - Click the gear icon in Raiken
  2. Navigate to Browser - Select browser configuration
  3. Configure Options:
    • Headless mode (on/off)
    • Viewport size
    • Device emulation
    • Video recording
    • Screenshot capture

Command Line Configuration

# Run tests on specific browser
npx playwright test --project=chromium

# Run tests on all browsers
npx playwright test

# Run with headed browsers (visible)
npx playwright test --headed

# Run with specific viewport
npx playwright test --headed --viewport=1920,1080

Writing Cross-Browser Tests

Browser-Agnostic Test Patterns

Write tests that work consistently across browsers:

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

test.describe('Cross-Browser Navigation', () => {
  test('should navigate between pages consistently', async ({ page, browserName }) => {
    await page.goto('/dashboard')
    
    // Wait for page to be fully loaded (important for all browsers)
    await page.waitForLoadState('networkidle')
    
    // Use data-testid selectors (consistent across browsers)
    await page.click('[data-testid="nav-products"]')
    
    // Verify URL change
    await expect(page).toHaveURL('/products')
    
    // Check page content loaded
    await expect(page.locator('[data-testid="product-list"]')).toBeVisible()
  })
})

Browser-Specific Considerations

Handle browser-specific behaviors:

test('should handle file downloads', async ({ page, browserName }) => {
  // Different browsers handle downloads differently
  const downloadPromise = page.waitForEvent('download')
  
  await page.click('[data-testid="download-button"]')
  const download = await downloadPromise
  
  // WebKit might need additional handling
  if (browserName === 'webkit') {
    // WebKit-specific download handling
    await download.saveAs('./downloads/' + download.suggestedFilename())
  } else {
    // Standard handling for Chromium/Firefox
    await download.path()
  }
})

Mobile Browser Testing

Device Emulation

Test mobile experiences across browser engines:

import { test, devices } from '@playwright/test'

// iPhone testing (WebKit)
test.describe('Mobile Safari', () => {
  test.use({ ...devices['iPhone 13'] })
  
  test('should work on iPhone', async ({ page }) => {
    await page.goto('/mobile-app')
    
    // Touch interactions
    await page.tap('[data-testid="menu-button"]')
    
    // Mobile-specific assertions
    await expect(page.locator('[data-testid="mobile-menu"]')).toBeVisible()
  })
})

// Android testing (Chromium)
test.describe('Mobile Chrome', () => {
  test.use({ ...devices['Pixel 5'] })
  
  test('should work on Android', async ({ page }) => {
    await page.goto('/mobile-app')
    
    // Android-specific behaviors
    await page.locator('[data-testid="input"]').tap()
    await page.keyboard.type('Mobile text input')
  })
})

Responsive Design Testing

Test responsive breakpoints across browsers:

const viewports = [
  { width: 375, height: 667, name: 'iPhone SE' },
  { width: 768, height: 1024, name: 'iPad' },
  { width: 1920, height: 1080, name: 'Desktop' },
]

viewports.forEach(({ width, height, name }) => {
  test(`should work on ${name}`, async ({ page }) => {
    await page.setViewportSize({ width, height })
    await page.goto('/responsive-page')
    
    // Responsive layout checks
    if (width < 768) {
      await expect(page.locator('[data-testid="mobile-nav"]')).toBeVisible()
    } else {
      await expect(page.locator('[data-testid="desktop-nav"]')).toBeVisible()
    }
  })
})

Performance Testing

Browser Performance Comparison

Measure performance across different browsers:

test('should load quickly in all browsers', async ({ page, browserName }) => {
  const startTime = Date.now()
  
  await page.goto('/performance-test')
  await page.waitForSelector('[data-testid="content-loaded"]')
  
  const loadTime = Date.now() - startTime
  
  // Different browsers have different performance characteristics
  let threshold = 3000 // Default 3 seconds
  if (browserName === 'webkit') {
    threshold = 4000 // WebKit might be slower on some systems
  }
  
  expect(loadTime).toBeLessThan(threshold)
  
  // Measure JavaScript performance
  const jsMetrics = await page.evaluate(() => {
    return performance.getEntriesByType('navigation')[0]
  })
  
  console.log(`${browserName} load time: ${jsMetrics.loadEventEnd - jsMetrics.loadEventStart}ms`)
})

Visual Testing

Cross-Browser Screenshots

Compare visual appearance across browsers:

test('should look consistent across browsers', async ({ page, browserName }) => {
  await page.goto('/visual-test')
  
  // Wait for all images and fonts to load
  await page.waitForLoadState('networkidle')
  
  // Take screenshot with browser name
  await expect(page).toHaveScreenshot(`homepage-${browserName}.png`)
})

Handling Visual Differences

Account for expected browser differences:

test('should handle browser-specific rendering', async ({ page, browserName }) => {
  await page.goto('/styled-page')
  
  // Different browsers might render fonts slightly differently
  const screenshotOptions = {
    threshold: browserName === 'webkit' ? 0.3 : 0.2,
    maxDiffPixels: 100
  }
  
  await expect(page).toHaveScreenshot('styled-page.png', screenshotOptions)
})

Browser-Specific Features

Chromium Features

Leverage Chromium's advanced capabilities:

test('should use Chromium DevTools features', async ({ page, browserName }) => {
  test.skip(browserName !== 'chromium', 'Chromium-specific test')
  
  // Network interception (best on Chromium)
  await page.route('**/api/slow-endpoint', route => {
    route.fulfill({ 
      status: 200, 
      body: JSON.stringify({ fast: true }) 
    })
  })
  
  // Performance monitoring
  await page.coverage.startJSCoverage()
  await page.goto('/app')
  const coverage = await page.coverage.stopJSCoverage()
  
  expect(coverage.length).toBeGreaterThan(0)
})

Firefox Features

Test Firefox-specific behaviors:

test('should handle Firefox privacy features', async ({ page, browserName }) => {
  test.skip(browserName !== 'firefox', 'Firefox-specific test')
  
  // Firefox privacy mode testing
  await page.goto('/privacy-sensitive-page')
  
  // Test cookies and storage restrictions
  await page.evaluate(() => {
    try {
      localStorage.setItem('test', 'value')
      return true
    } catch (e) {
      return false
    }
  })
})

WebKit Features

Test Safari-specific behaviors:

test('should handle WebKit touch events', async ({ page, browserName }) => {
  test.skip(browserName !== 'webkit', 'WebKit-specific test')
  
  await page.goto('/touch-interface')
  
  // WebKit touch handling
  await page.touchscreen.tap(100, 100)
  
  // Safari-specific date picker
  await page.locator('[type="date"]').click()
  await expect(page.locator('.date-picker')).toBeVisible()
})

CI/CD Integration

Multi-Browser Pipeline

Set up CI/CD for cross-browser testing:

# .github/workflows/test.yml
name: Cross-Browser Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        browser: [chromium, firefox, webkit]
    
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Install Playwright browsers
        run: npx playwright install --with-deps
      
      - name: Run tests
        run: npx playwright test --project=${{ matrix.browser }}
      
      - name: Upload test results
        uses: actions/upload-artifact@v3
        if: always()
        with:
          name: test-results-${{ matrix.browser }}
          path: test-results/

Parallel Browser Testing

Run browsers in parallel for faster feedback:

- name: Run parallel browser tests
  run: npx playwright test --workers=3

Debugging Browser Issues

Browser-Specific Debugging

Debug issues in specific browsers:

# Debug in specific browser with UI
npx playwright test --project=firefox --debug

# Run headed for visual debugging
npx playwright test --project=webkit --headed

# Trace specific browser issues
npx playwright test --project=chromium --trace=on

Browser Logs and Console

Capture browser-specific console output:

test('should capture browser console', async ({ page, browserName }) => {
  const consoleMessages = []
  
  page.on('console', msg => {
    consoleMessages.push(`[${browserName}] ${msg.type()}: ${msg.text()}`)
  })
  
  await page.goto('/console-test')
  
  // Check for browser-specific console messages
  expect(consoleMessages.some(msg => msg.includes('loaded'))).toBe(true)
})

Best Practices

Cross-Browser Compatibility

  1. Use Standard Selectors: Prefer data-testid over CSS selectors
  2. Handle Timing: Use waitFor methods instead of hard waits
  3. Test Critical Paths: Focus on user workflows across browsers
  4. Monitor Performance: Track performance differences between browsers

Browser Selection Strategy

  1. Primary Browser: Chromium for development and most testing
  2. Compatibility Testing: Firefox for cross-engine verification
  3. Safari Testing: WebKit for iOS/macOS specific features
  4. Mobile Testing: Device emulation for responsive design

Maintenance Tips

  1. Keep Browsers Updated: Regular npx playwright install
  2. Monitor Test Flakiness: Some tests may be browser-specific
  3. Use Conditional Logic: Skip unsupported features per browser
  4. Regular Visual Updates: Update screenshots when design changes

Next Steps

Now that you understand browser testing:


Ready for automation? Continue with CI/CD Integration to set up automated cross-browser testing.