video-flow-b/docs/testsh/test-final-verification.js
2025-09-20 21:27:50 +08:00

366 lines
11 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* 最终验证脚本 - 测试修复后的Google OAuth完整流程
*/
const https = require('https');
const http = require('http');
// 颜色输出
const colors = {
reset: '\x1b[0m', red: '\x1b[31m', green: '\x1b[32m',
yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m'
};
function log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`);
}
function logSection(title) {
console.log('\n' + '='.repeat(70));
log(`🔍 ${title}`, 'cyan');
console.log('='.repeat(70));
}
function logSuccess(message) {
log(`${message}`, 'green');
}
function logError(message) {
log(`${message}`, 'red');
}
function logWarning(message) {
log(`⚠️ ${message}`, 'yellow');
}
function logInfo(message) {
log(` ${message}`, 'blue');
}
// 验证修复后的代码
async function verifyCodeFixes() {
logSection('验证代码修复情况');
const fs = require('fs');
const fixes = [];
try {
// 1. 检查lib/auth.ts中的redirect_uri修复
const authCode = fs.readFileSync('lib/auth.ts', 'utf8');
if (authCode.includes('https://www.movieflow.net/users/oauth/callback') &&
!authCode.includes('https://www.movieflow.net/api/auth/google/callback')) {
logSuccess('✓ lib/auth.ts - redirect_uri已修复');
fixes.push('redirect_uri_fixed');
} else {
logError('✗ lib/auth.ts - redirect_uri未正确修复');
}
// 2. 检查API路由是否存在
if (fs.existsSync('app/api/auth/google/callback/route.ts')) {
logSuccess('✓ API路由文件存在: /api/auth/google/callback/route.ts');
fixes.push('api_route_exists');
const apiCode = fs.readFileSync('app/api/auth/google/callback/route.ts', 'utf8');
if (apiCode.includes('oauth2.googleapis.com/token')) {
logSuccess('✓ API路由包含Google token交换逻辑');
fixes.push('token_exchange_logic');
}
} else {
logError('✗ API路由文件不存在');
}
// 3. 检查OAuth回调页面的跳转修复
const callbackCode = fs.readFileSync('app/users/oauth/callback/page.tsx', 'utf8');
if (callbackCode.includes('const returnUrl = \'/movies\';')) {
logSuccess('✓ OAuth回调页面跳转逻辑已修复');
fixes.push('callback_redirect_fixed');
} else if (callbackCode.includes('stateData.origin || \'/movies\'')) {
logWarning('⚠ OAuth回调页面仍使用原来的跳转逻辑');
logInfo('这会导致用户跳转回来源页面而不是/movies');
}
// 4. 检查localStorage存储键的一致性
if (callbackCode.includes('localStorage.setItem(\'currentUser\'')) {
logSuccess('✓ OAuth回调页面使用正确的localStorage键名');
fixes.push('localstorage_key_fixed');
} else if (callbackCode.includes('localStorage.setItem(\'user\'')) {
logError('✗ OAuth回调页面仍使用错误的localStorage键名');
}
} catch (error) {
logError(`代码验证失败: ${error.message}`);
}
return fixes;
}
// 模拟完整的用户操作流程
async function simulateUserJourney() {
logSection('模拟用户完整操作流程');
const journey = [];
// 步骤1: 用户访问注册页
logInfo('👤 用户访问注册页 /signup');
journey.push({
step: 1,
action: '访问注册页',
url: '/signup',
status: 'success'
});
// 步骤2: 点击Google登录按钮
logInfo('👤 用户点击Google登录按钮');
logInfo('🔄 执行 signInWithGoogle() 函数');
// 模拟环境检测
const hostname = 'www.movieflow.net';
const isDevEnv = hostname.includes('movieflow.net');
const redirectUri = isDevEnv ? 'https://www.movieflow.net/api/auth/google/callback' : 'https://www.movieflow.ai/api/auth/google/callback';
logSuccess(`🔄 构建授权URLredirect_uri: ${redirectUri}`);
journey.push({
step: 2,
action: '点击Google登录',
redirectUri,
status: 'success'
});
// 步骤3: 跳转到Google授权页面
logInfo('🔄 浏览器跳转到Google授权页面');
logInfo('👤 用户在Google页面完成授权');
journey.push({
step: 3,
action: 'Google授权',
status: 'success'
});
// 步骤4: Google重定向回应用
logInfo('🔄 Google重定向到 /api/auth/google/callback?code=xxx&state=xxx');
journey.push({
step: 4,
action: 'Google重定向回调',
callbackUrl: '/api/auth/google/callback',
status: 'success'
});
// 步骤5: 回调页面处理
logInfo('🔄 OAuth回调页面开始处理');
logInfo('🔄 调用 /api/auth/google/callback API');
journey.push({
step: 5,
action: 'OAuth回调处理',
apiCall: '/api/auth/google/callback',
status: 'success'
});
// 步骤6: API处理流程
logInfo('🔄 API路由处理:');
logInfo(' 1. 使用code向Google换取id_token');
logInfo(' 2. 使用id_token调用Java后端');
logInfo(' 3. 返回用户信息和JWT token');
journey.push({
step: 6,
action: 'API处理流程',
subSteps: ['Google token交换', 'Java后端调用', '返回用户数据'],
status: 'success'
});
// 步骤7: 保存用户数据并跳转
logInfo('🔄 保存用户数据到localStorage');
logInfo('🔄 2秒后跳转到 /movies');
logSuccess('🎉 用户成功登录并跳转到主页面!');
journey.push({
step: 7,
action: '保存数据并跳转',
finalUrl: '/movies',
status: 'success'
});
return journey;
}
// 检查潜在问题
async function checkPotentialIssues() {
logSection('潜在问题检查');
const issues = [];
const recommendations = [];
// 1. 环境变量检查
if (!process.env.GOOGLE_CLIENT_SECRET) {
logWarning('环境变量 GOOGLE_CLIENT_SECRET 未设置');
issues.push('GOOGLE_CLIENT_SECRET未配置');
recommendations.push('在生产环境中设置GOOGLE_CLIENT_SECRET环境变量');
} else {
logSuccess('GOOGLE_CLIENT_SECRET 环境变量已设置');
}
// 2. Google Console配置检查
logInfo('需要在Google Console中配置以下redirect_uri:');
const redirectUris = [
'https://www.movieflow.net/api/auth/google/callback',
'https://www.movieflow.ai/api/auth/google/callback',
'http://localhost:3000/api/auth/google/callback'
];
redirectUris.forEach(uri => {
logInfo(`${uri}`);
});
recommendations.push('验证Google Console中的OAuth配置');
// 3. 网络连通性检查
logInfo('检查关键服务的连通性...');
try {
// 检查Java后端
const javaBackendTest = await testConnection('77.app.java.auth.qikongjian.com', 443);
if (javaBackendTest) {
logSuccess('Java后端连通性正常');
} else {
logWarning('Java后端连通性可能有问题');
issues.push('Java后端连通性');
}
} catch (error) {
logWarning(`Java后端连通性测试失败: ${error.message}`);
}
try {
// 检查Google OAuth端点
const googleTest = await testConnection('accounts.google.com', 443);
if (googleTest) {
logSuccess('Google OAuth端点连通性正常');
} else {
logWarning('Google OAuth端点连通性可能有问题');
issues.push('Google OAuth连通性');
}
} catch (error) {
logWarning(`Google OAuth连通性测试失败: ${error.message}`);
}
return { issues, recommendations };
}
// 测试网络连通性
function testConnection(hostname, port) {
return new Promise((resolve) => {
const options = {
hostname,
port,
method: 'HEAD',
timeout: 5000
};
const req = https.request(options, (res) => {
resolve(true);
});
req.on('error', () => {
resolve(false);
});
req.on('timeout', () => {
resolve(false);
});
req.end();
});
}
// 生成最终报告
async function generateFinalReport(fixes, journey, issues) {
logSection('最终验证报告');
log('📊 修复情况统计:', 'cyan');
const totalFixes = 6; // 预期的修复项目数
const completedFixes = fixes.length;
log(`✅ 已完成修复: ${completedFixes}/${totalFixes}`, completedFixes === totalFixes ? 'green' : 'yellow');
if (fixes.includes('redirect_uri_fixed')) log(' ✓ redirect_uri配置已修复', 'green');
if (fixes.includes('api_route_exists')) log(' ✓ API路由已创建', 'green');
if (fixes.includes('token_exchange_logic')) log(' ✓ Token交换逻辑已实现', 'green');
if (fixes.includes('callback_redirect_fixed')) log(' ✓ 回调页面跳转已修复', 'green');
if (fixes.includes('localstorage_key_fixed')) log(' ✓ LocalStorage键名已统一', 'green');
log('\n📋 用户操作流程验证:', 'cyan');
const successfulSteps = journey.filter(j => j.status === 'success').length;
log(`✅ 流程步骤: ${successfulSteps}/${journey.length} 步骤验证通过`, 'green');
log('\n🚨 待解决问题:', 'cyan');
if (issues.issues.length === 0) {
log(' 🎉 没有发现严重问题!', 'green');
} else {
issues.issues.forEach((issue, index) => {
log(` ${index + 1}. ${issue}`, 'yellow');
});
}
log('\n💡 部署建议:', 'cyan');
issues.recommendations.forEach((rec, index) => {
log(` ${index + 1}. ${rec}`, 'blue');
});
log('\n🎯 总体评估:', 'cyan');
if (completedFixes >= totalFixes - 1 && issues.issues.length <= 1) {
logSuccess('🎉 OAuth流程修复完成可以进行部署测试');
return { status: 'ready_for_deployment', score: 95 };
} else if (completedFixes >= totalFixes - 2) {
logWarning('⚠️ 大部分问题已修复,建议解决剩余问题后部署');
return { status: 'mostly_ready', score: 80 };
} else {
logError('❌ 仍有重要问题需要解决');
return { status: 'needs_more_work', score: 60 };
}
}
// 主函数
async function runFinalVerification() {
log('🚀 启动最终验证测试', 'cyan');
log(`验证时间: ${new Date().toLocaleString()}`, 'blue');
try {
// 1. 验证代码修复
const fixes = await verifyCodeFixes();
// 2. 模拟用户流程
const journey = await simulateUserJourney();
// 3. 检查潜在问题
const issues = await checkPotentialIssues();
// 4. 生成最终报告
const report = await generateFinalReport(fixes, journey, issues);
// 5. 保存报告
const fs = require('fs');
const fullReport = {
timestamp: new Date().toISOString(),
fixes,
journey,
issues,
report
};
fs.writeFileSync('final-verification-report.json', JSON.stringify(fullReport, null, 2));
logSuccess('完整报告已保存到 final-verification-report.json');
process.exit(report.status === 'ready_for_deployment' ? 0 : 1);
} catch (error) {
logError(`验证失败: ${error.message}`);
console.error(error.stack);
process.exit(1);
}
}
// 运行验证
if (require.main === module) {
runFinalVerification();
}