/** * Cucumber hooks for EuchreCamp E2E tests */ import { Before, After, BeforeAll, AfterAll } from '@cucumber/cucumber'; import { chromium, Browser } from '@playwright/test'; import { world } from './world'; import path from 'path'; import fs from 'fs'; // Global browser instance let browser: Browser; // Load environment files const envPath = path.resolve(process.cwd(), '.env'); const envDevPath = path.resolve(process.cwd(), '.env.development'); if (fs.existsSync(envPath)) { require('dotenv').config({ path: envPath }); } if (fs.existsSync(envDevPath)) { require('dotenv').config({ path: envDevPath, override: true }); } // Database safety check - prevent tests from running against production function isProductionDatabase(): boolean { const dbUrl = process.env.DATABASE_URL || ''; return dbUrl.includes('euchre_camp') && !dbUrl.includes('_dev') && !dbUrl.includes('test'); } if (isProductionDatabase()) { console.error(''); console.error('='.repeat(80)); console.error('CRITICAL ERROR: Cucumber tests are attempting to run against PRODUCTION database!'); console.error('='.repeat(80)); console.error(''); console.error('Current DATABASE_URL:', process.env.DATABASE_URL); console.error(''); console.error('Tests MUST run against a development/test database.'); console.error(''); console.error('To fix this:'); console.error(' 1. Set DATABASE_URL to a dev/test database'); console.error(' 2. Or run: npm run test:acceptance (which uses Playwright tests)'); console.error(''); console.error('Aborting test execution to prevent data corruption.'); console.error(''); process.exit(1); } /** * Before all scenarios: Launch browser */ BeforeAll(async function () { console.log('🌍 Launching browser for Cucumber tests...'); browser = await chromium.launch(); }); /** * After all scenarios: Close browser and cleanup */ AfterAll(async function () { console.log('🌍 Closing browser...'); await browser.close(); console.log('🌍 Disconnecting from database...'); if (world.prisma) { await world.prisma.$disconnect(); } }); /** * Before each scenario: Create new page context */ Before(async function () { // Create new context and page world.context = await browser.newContext(); world.page = await world.context.newPage(); // Log console messages for debugging world.page.on('console', msg => { if (msg.type() === 'error') { console.log('❌ PAGE ERROR:', msg.text()); } }); // Log network errors world.page.on('requestfailed', request => { console.log('❌ REQUEST FAILED:', request.url()); }); console.log('🌍 Created new page context'); }); /** * After each scenario: Close page */ After(async function () { console.log('🌍 Cleaning up after scenario...'); // Close page and context if (world.page) { await world.page.close(); } if (world.context) { await world.context.close(); } }); /** * Custom hook for navigating to a page */ Before({ tags: '@navigation' }, async function () { console.log('🌍 Navigation hook triggered'); }); /** * Custom hook for authenticated scenarios */ Before({ tags: '@authenticated' }, async function () { console.log('🌍 Authenticated hook triggered'); }); /** * Tag hooks for specific scenarios */ Before({ tags: '@slow' }, async function () { console.log('🌍 Slow test - extending timeout'); }); Before({ tags: '@flaky' }, async function () { console.log('🌍 Flaky test - retry enabled'); });