158 lines
4.2 KiB
TypeScript
Executable file
158 lines
4.2 KiB
TypeScript
Executable file
/**
|
|
* E2E Test Fixtures and Utilities
|
|
*
|
|
* Provides common test setup, API helpers, and test data references
|
|
* for analytics device fingerprinting E2E tests.
|
|
*/
|
|
import { test as base, expect } from '@playwright/test'
|
|
|
|
// API URL from environment or default (analytics runs on port 3012 per ports.yaml)
|
|
export const API_URL = process.env.API_URL || 'http://localhost:3012'
|
|
|
|
// Test session IDs (from seed.sql)
|
|
export const TEST_SESSIONS = {
|
|
DESKTOP_US: '11111111-1111-1111-1111-111111111111',
|
|
MOBILE_EU: '22222222-2222-2222-2222-222222222222',
|
|
VPN_USER: '33333333-3333-3333-3333-333333333333',
|
|
TABLET_IS: '44444444-4444-4444-4444-444444444444',
|
|
BOT: '55555555-5555-5555-5555-555555555555',
|
|
TOR_USER: '66666666-6666-6666-6666-666666666666',
|
|
} as const
|
|
|
|
// Sample User-Agent strings for testing
|
|
export const USER_AGENTS = {
|
|
CHROME_WINDOWS:
|
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
SAFARI_IPHONE:
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1',
|
|
FIREFOX_LINUX:
|
|
'Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0',
|
|
GOOGLEBOT:
|
|
'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
|
|
SAFARI_IPAD:
|
|
'Mozilla/5.0 (iPad; CPU OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15',
|
|
} as const
|
|
|
|
// Sample client device data payloads
|
|
export const CLIENT_DEVICE_DATA = {
|
|
desktop: {
|
|
screenWidth: 1920,
|
|
screenHeight: 1080,
|
|
viewportWidth: 1920,
|
|
viewportHeight: 900,
|
|
language: 'en-US',
|
|
languages: ['en-US', 'en'],
|
|
timezone: 'America/New_York',
|
|
timezoneOffset: 300,
|
|
deviceMemory: 8,
|
|
hardwareConcurrency: 8,
|
|
colorDepth: 24,
|
|
pixelRatio: 1,
|
|
touchPoints: 0,
|
|
cookiesEnabled: true,
|
|
doNotTrack: null,
|
|
},
|
|
mobile: {
|
|
screenWidth: 390,
|
|
screenHeight: 844,
|
|
viewportWidth: 390,
|
|
viewportHeight: 664,
|
|
language: 'de-DE',
|
|
languages: ['de-DE', 'en'],
|
|
timezone: 'Europe/Berlin',
|
|
timezoneOffset: -60,
|
|
deviceMemory: 4,
|
|
hardwareConcurrency: 6,
|
|
colorDepth: 24,
|
|
pixelRatio: 3,
|
|
touchPoints: 5,
|
|
cookiesEnabled: true,
|
|
doNotTrack: '1',
|
|
},
|
|
tablet: {
|
|
screenWidth: 1024,
|
|
screenHeight: 1366,
|
|
viewportWidth: 1024,
|
|
viewportHeight: 1266,
|
|
language: 'is-IS',
|
|
languages: ['is-IS', 'en'],
|
|
timezone: 'Atlantic/Reykjavik',
|
|
timezoneOffset: 0,
|
|
deviceMemory: 4,
|
|
hardwareConcurrency: 4,
|
|
colorDepth: 24,
|
|
pixelRatio: 2,
|
|
touchPoints: 5,
|
|
cookiesEnabled: true,
|
|
doNotTrack: null,
|
|
},
|
|
}
|
|
|
|
/**
|
|
* Extended test context with API helpers
|
|
*/
|
|
export const test = base.extend<{
|
|
apiRequest: (
|
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
|
path: string,
|
|
data?: Record<string, unknown>,
|
|
headers?: Record<string, string>,
|
|
) => Promise<Response>
|
|
}>({
|
|
apiRequest: async ({ request }, use) => {
|
|
const apiRequest = async (
|
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
|
path: string,
|
|
data?: Record<string, unknown>,
|
|
headers?: Record<string, string>,
|
|
) => {
|
|
const url = `${API_URL}${path}`
|
|
const options: RequestInit = {
|
|
method,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...headers,
|
|
},
|
|
}
|
|
|
|
if (data && method !== 'GET') {
|
|
options.body = JSON.stringify(data)
|
|
}
|
|
|
|
return fetch(url, options)
|
|
}
|
|
|
|
await use(apiRequest)
|
|
},
|
|
})
|
|
|
|
export { expect }
|
|
|
|
/**
|
|
* Generate a random session ID for new sessions
|
|
*/
|
|
export function generateSessionId(): string {
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
const r = (Math.random() * 16) | 0
|
|
const v = c === 'x' ? r : (r & 0x3) | 0x8
|
|
return v.toString(16)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Wait for API to be healthy
|
|
*/
|
|
export async function waitForAPI(maxAttempts = 30): Promise<boolean> {
|
|
for (let i = 0; i < maxAttempts; i++) {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/health`)
|
|
if (response.ok) {
|
|
return true
|
|
}
|
|
} catch {
|
|
// API not ready yet
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
}
|
|
return false
|
|
}
|