import { Page } from '@playwright/test'; export async function getSessionId(page: Page): Promise { const cookies = await page.context().cookies(); const sessionCookie = cookies.find(c => c.name === 'phantom_session_id'); return sessionCookie?.value || null; } export async function verifySessionConsistency(page: Page, expectedSessionId: string): Promise { const currentSessionId = await getSessionId(page); return currentSessionId === expectedSessionId; } export async function createFreshSession(page: Page, storeType: 'hotel' | 'airline' = 'hotel'): Promise { await page.context().clearCookies(); await page.goto('/'); await page.waitForLoadState('networkidle'); await page.waitForTimeout(500); const sid = await getSessionId(page); if (!sid) throw new Error('Session not created'); return sid; } interface SearchParams { destination?: string; checkIn?: string; guests?: number; rooms?: number; origin?: string; departure?: string; adults?: number; } export async function performSearch(page: Page, params: SearchParams, storeType: 'hotel' | 'airline' = 'hotel' ): Promise { await page.waitForLoadState('networkidle'); if (storeType === 'hotel') { const destInput = page.locator('input#destination'); await destInput.fill(params.destination || 'New York'); const checkInInput = page.locator('input#checkIn'); const checkInDate = params.checkIn || new Date(Date.now() + 7 * 86400000).toISOString().split('T')[0]; await checkInInput.fill(checkInDate); const searchBtn = page.locator('button:has-text("Search Rooms")'); await searchBtn.click(); } else { const originDropdown = page.locator('button:has-text("Select origin")').or( page.locator('[id="origin"]').locator('button').first() ); await originDropdown.click(); await page.waitForTimeout(200); const originOption = page.locator(`button:has-text("${params.origin || 'JFK'}")`).first(); await originOption.click(); await page.waitForTimeout(200); const destDropdown = page.locator('button:has-text("Select destination")').or( page.locator('[id="destination"]').locator('button').first() ); await destDropdown.click(); await page.waitForTimeout(200); const destOption = page.locator(`button:has-text("${params.destination || 'LAX'}")`).first(); await destOption.click(); await page.waitForTimeout(200); const departInput = page.locator('input#departDate'); const departDate = params.departure || new Date(Date.now() + 7 * 86400000).toISOString().split('T')[0]; await departInput.fill(departDate); const searchBtn = page.locator('button:has-text("Search Flights")'); await searchBtn.click(); } await page.waitForLoadState('networkidle'); } export async function selectRandomProduct(page: Page, storeType: 'hotel' | 'airline' = 'hotel'): Promise { await page.waitForLoadState('networkidle'); const cardClass = storeType === 'hotel' ? '.hotel-card' : '.flight-card'; const productCards = page.locator(cardClass); const count = await productCards.count(); if (count === 0) throw new Error('No products found on listing page'); const randomIdx = Math.floor(Math.random() * count); return randomIdx.toString(); } export async function openProductFromListing(page: Page, productId?: string): Promise { await page.waitForLoadState('networkidle'); const hotelCards = page.locator('.hotel-card'); const flightCards = page.locator('.flight-card'); const hotelCount = await hotelCards.count(); const flightCount = await flightCards.count(); let productCards; if (hotelCount > 0) { productCards = hotelCards; } else if (flightCount > 0) { productCards = flightCards; } else { throw new Error('No products found on listing page'); } const count = await productCards.count(); const randomIdx = productId ? 0 : Math.floor(Math.random() * count); await productCards.nth(randomIdx).click(); await page.waitForLoadState('networkidle'); const url = page.url(); const match = url.match(/\/products\/([^/?]+)/); if (!match) throw new Error('Cannot parse product ID from URL after navigation'); return match[1]; } export async function getPriceFromDOM(page: Page): Promise { await page.waitForLoadState('networkidle'); await page.waitForSelector('.price-amount', { timeout: 15000 }).catch(() => null); const priceSelectors = [ '.price-amount', '.price-display', '[data-testid="price"]', '[data-price]', ]; for (const selector of priceSelectors) { const priceEl = page.locator(selector).first(); if (await priceEl.count() > 0) { const text = await priceEl.textContent(); if (!text) continue; const match = text.match(/[\$]?\s*([\d,]+(?:\.\d{2})?)/); if (match) { const priceStr = match[1].replace(/,/g, ''); return parseFloat(priceStr); } } } const dataPrice = await page.locator('[data-price]').first().getAttribute('data-price').catch(() => null); if (dataPrice) return parseFloat(dataPrice); throw new Error('Cannot extract price from DOM'); } export async function navigateToProduct(page: Page,productId: string,storeType: 'hotel' | 'airline' = 'hotel'): Promise { await page.goto(`/products/${productId}`); await page.waitForLoadState('networkidle'); } export async function viewProductViaFlow(page: Page, storeType: 'hotel' | 'airline' = 'hotel', searchParams?: SearchParams): Promise { const params = new URLSearchParams(); params.set('dateIndex', '7'); if (storeType === 'hotel') { params.set('destination', searchParams?.destination || 'New York'); params.set('adults', '2'); params.set('rooms', '1'); } else { params.set('origin', searchParams?.origin || 'JFK'); params.set('destination', searchParams?.destination || 'LAX'); params.set('adults', '1'); params.set('children', '0'); params.set('infants', '0'); } await page.goto(`/products?${params.toString()}`); await page.waitForLoadState('networkidle'); const productId = await openProductFromListing(page); await page.waitForTimeout(500); return productId; } export async function rapidViewProductViaFlow(page: Page, count: number, delayMs: number = 100, storeType: 'hotel' | 'airline' = 'hotel'): Promise { const productIds: string[] = []; for (let i = 0; i < count; i++) { const productId = await viewProductViaFlow(page, storeType); productIds.push(productId); await page.waitForTimeout(delayMs); } return productIds; } export async function humanLikeViewProduct(page: Page, storeType: 'hotel' | 'airline' = 'hotel' ): Promise { const productId = await viewProductViaFlow(page, storeType); await page.hover('h1'); await page.waitForTimeout(800 + Math.random() * 400); await page.mouse.wheel(0, 200); await page.waitForTimeout(500 + Math.random() * 300); const paragraphs = await page.locator('p').all(); if (paragraphs.length > 0) { await paragraphs[0].hover(); await page.waitForTimeout(600 + Math.random() * 400); } return productId; } export async function addToCart(page: Page): Promise { const addBtn = page.locator('button:has-text("Add to Cart")'); await addBtn.click(); await page.waitForTimeout(500); }