/** * ================================================================ * E2E Test Database Reset Global Setup * ================================================================ * Runs reset-db.sh before all E2E tests to ensure clean database state * * Usage: * Add to playwright.config.js: * globalSetup: path.join(__dirname, 'e2e', 'helpers', 'db.js') * ================================================================ */ var path = require('path'); var child_process = require('child_process'); var SCRIPT_PATH = path.join(__dirname, '..', 'reset-db.sh'); /** * Reset database by executing reset-db.sh * This function is called as globalSetup before all E2E tests * @throws {Error} - If script execution fails */ function resetDatabase() { console.log('============================================================'); console.log('E2E Global Setup: Running Database Reset'); console.log('============================================================'); console.log('Script path: ' + SCRIPT_PATH); console.log('============================================================'); try { var mysqlHost = process.env.MYSQL_HOST || '192.168.16.251'; var mysqlUser = process.env.MYSQL_USER || 'zxyj'; var mysqlPass = process.env.MYSQL_PASS || 'zxyj@123'; var mysqlDb = process.env.MYSQL_DB || 'zxyj'; // On Windows, use mysql.exe directly since bash is unavailable if (process.platform === 'win32') { var seedFile = path.join(__dirname, '..', 'seed-data.sql'); console.log('[INFO] Windows detected, using mysql.exe directly'); console.log('[INFO] DB: ' + mysqlDb + ' @ ' + mysqlHost); // Try to seed the main database (may fail if DB doesn't match) try { child_process.execSync( 'mysql -h ' + mysqlHost + ' -u ' + mysqlUser + ' -p"' + mysqlPass + '" ' + mysqlDb + ' < "' + seedFile + '"', { stdio: 'inherit', cwd: __dirname, shell: true, timeout: 15000 } ); } catch (seedErr) { console.log('[WARN] Main seed failed (expected if DB schema differs), continuing...'); } } else { // Execute the reset-db.sh script // Using execSync for synchronous execution in globalSetup child_process.execSync('bash ' + SCRIPT_PATH, { stdio: 'inherit', cwd: __dirname }); } // Always refresh verification codes for test users // Important: Insert MULTIPLE codes per phone because desktop+mobile projects // run in parallel with 2 workers. Each worker consumes a verification code // (single-use: backend sets used=1 on verify), so we need enough codes for // all concurrent login attempts. console.log('[INFO] Refreshing verification codes for test users (5 per phone for parallel workers)...'); var phones = ['13701366188','13701366189','13701366190','13800000001','13800000010','13800000020','13800000030','13800138001','13800138000']; var values = []; // 5 codes per phone to handle up to 5 concurrent workers for (var p = 0; p < phones.length; p++) { for (var i = 0; i < 5; i++) { var type = phones[p] === '13800138000' ? 'admin_login' : 'login'; values.push("('" + phones[p] + "', '123456', '" + type + "', 300, NOW(), '2026-07-28 23:59:59', 0)"); } } child_process.execSync( 'mysql -h ' + mysqlHost + ' -u ' + mysqlUser + ' -p"' + mysqlPass + '" ' + mysqlDb + ' -e "DELETE FROM verification_codes WHERE phone IN (\'13701366188\',\'13701366189\',\'13701366190\',\'13800000001\',\'13800000010\',\'13800000020\',\'13800000030\',\'13800138001\',\'13800138000\'); INSERT INTO verification_codes (phone, code, type, expires_in, created_at, expires_at, used) VALUES ' + values.join(',') + ';"', { stdio: 'inherit', cwd: __dirname, shell: true, timeout: 30000 } ); // Ensure required test data exists (seed-data.sql may not fully execute) try { // Use a single mysql call with multiple statements to ensure all critical data exists var ensureSQL = "UPDATE users SET password='5da27d18ad7ba1228d02ce9c3c5f6c87' WHERE id=1001 AND password IS NULL;" + "UPDATE families SET creator_id=1002 WHERE id=2001 AND creator_id IS NULL;" + "INSERT IGNORE INTO family_members (id, family_id, user_id, nickname, phone, gender, birthday, generation, is_spouse, show_to_family, total_points, system_points, streak_days, created_at, updated_at, relationship_type) VALUES " + "(1000, 2001, 1002, '家长用户', '13701366188', 'male', '1985-01-01', 0, 0, 1, 0, 0, 0, NOW(), NOW(), 'other');" + "INSERT IGNORE INTO family_members (id, family_id, user_id, nickname, phone, gender, birthday, generation, is_spouse, show_to_family, total_points, system_points, streak_days, created_at, updated_at, relationship_type) VALUES " + "(1001, 2001, 1003, '孩子用户A', '13701366189', 'male', '2015-06-15', -1, 0, 1, 0, 0, 0, NOW(), NOW(), 'other');" + "INSERT IGNORE INTO family_members (id, family_id, user_id, nickname, phone, gender, birthday, generation, is_spouse, show_to_family, total_points, system_points, streak_days, created_at, updated_at, relationship_type) VALUES " + "(1002, 2001, 1004, '孩子用户B', '13701366190', 'female', '2018-03-20', -1, 0, 1, 0, 0, 0, NOW(), NOW(), 'other');" + "INSERT IGNORE INTO family_members (id, family_id, user_id, nickname, relationship_type, created_at) VALUES (1003, 2001, NULL, '测试孩子', 'other', NOW());"; child_process.execSync( 'mysql -h "' + mysqlHost + '" -u "' + mysqlUser + '" -p"' + mysqlPass + '" "' + mysqlDb + '" -e "' + ensureSQL.replace(/"/g, '\\"') + '"', { stdio: 'inherit', cwd: __dirname, shell: true, timeout: 15000 } ); } catch (ensureErr) { console.log('[WARN] Data ensure step failed (non-fatal): ' + ensureErr.message); } console.log('============================================================'); console.log('E2E Global Setup: Database Seed Complete'); console.log('============================================================'); } catch (error) { console.error('============================================================'); console.error('E2E Global Setup: Verification code seed FAILED'); console.error('============================================================'); console.error('Error: ' + error.message); console.error('============================================================'); console.error('[WARN] Codes not refreshed — tests may fail 401 if codes expired.'); console.error('============================================================'); } } // Run if executed directly resetDatabase(); // ================================================================ // Module exports (CommonJS) // ================================================================ module.exports = resetDatabase;