Some checks failed
Deploy / deploy (push) Has been cancelled
Full-stack web application for Telegram management - Frontend: Vue 3 + Vben Admin - Backend: NestJS - Features: User management, group broadcast, statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
283 lines
8.6 KiB
JavaScript
283 lines
8.6 KiB
JavaScript
import { chromium } from 'playwright';
|
||
|
||
async function completeAuthTest() {
|
||
const browser = await chromium.launch({ headless: false, slowMo: 1000 });
|
||
const context = await browser.newContext();
|
||
const page = await context.newPage();
|
||
|
||
const apiCalls = [];
|
||
|
||
// 监听所有API调用,特别关注/auth和/base接口
|
||
page.on('request', (request) => {
|
||
const url = request.url();
|
||
|
||
// 监听所有后端API调用
|
||
if (
|
||
url.includes('localhost:3000') ||
|
||
url.includes('/auth/') ||
|
||
url.includes('/base') ||
|
||
url.includes('/api/')
|
||
) {
|
||
const headers = request.headers();
|
||
apiCalls.push({
|
||
method: request.method(),
|
||
url: request.url(),
|
||
headers: headers,
|
||
timestamp: new Date().toISOString(),
|
||
});
|
||
|
||
console.log(`🔵 API请求: ${request.method()} ${request.url()}`);
|
||
|
||
// 检查Authorization头
|
||
if (headers['authorization']) {
|
||
console.log(
|
||
`🔑 包含Authorization头: ${headers['authorization'].substring(0, 30)}...`,
|
||
);
|
||
} else {
|
||
console.log(`⚠️ 未包含Authorization头`);
|
||
}
|
||
}
|
||
});
|
||
|
||
page.on('response', async (response) => {
|
||
const url = response.url();
|
||
|
||
if (
|
||
url.includes('localhost:3000') ||
|
||
url.includes('/auth/') ||
|
||
url.includes('/base') ||
|
||
url.includes('/api/')
|
||
) {
|
||
const status = response.status();
|
||
console.log(`🟢 API响应: ${status} ${response.url()}`);
|
||
|
||
if (status === 200) {
|
||
try {
|
||
const responseText = await response.text();
|
||
console.log(`📋 响应内容: ${responseText.substring(0, 200)}...`);
|
||
} catch (e) {
|
||
console.log('获取响应内容失败');
|
||
}
|
||
} else if (status === 401) {
|
||
console.log(`❌ 401认证失败: ${response.url()}`);
|
||
try {
|
||
const errorText = await response.text();
|
||
console.log(`📋 错误响应: ${errorText}`);
|
||
} catch (e) {
|
||
console.log('无法获取错误响应内容');
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// 监听控制台
|
||
page.on('console', (msg) => {
|
||
if (msg.type() === 'error') {
|
||
console.log(`❌ 页面错误: ${msg.text()}`);
|
||
}
|
||
});
|
||
|
||
try {
|
||
console.log('🚀 开始完整认证测试...');
|
||
|
||
// 1. 访问登录页面
|
||
await page.goto('http://localhost:5173/auth/login');
|
||
console.log('✅ 已访问登录页面');
|
||
|
||
// 等待页面完全加载
|
||
await page.waitForLoadState('networkidle');
|
||
await page.waitForTimeout(3000);
|
||
|
||
// 2. 等待并填写表单
|
||
console.log('📝 等待表单元素...');
|
||
|
||
try {
|
||
await page.waitForSelector('input[name="username"]', { timeout: 15000 });
|
||
await page.waitForSelector('input[name="password"]', { timeout: 15000 });
|
||
console.log('✅ 表单元素已找到');
|
||
} catch (e) {
|
||
console.log('❌ 表单元素查找超时,尝试其他选择器...');
|
||
|
||
// 尝试其他选择器
|
||
const inputs = await page.$$('input');
|
||
console.log(`发现 ${inputs.length} 个输入框`);
|
||
|
||
if (inputs.length >= 2) {
|
||
console.log('✅ 使用通用输入框选择器');
|
||
await inputs[0].fill('admin');
|
||
await inputs[1].fill('111111');
|
||
} else {
|
||
throw new Error('未找到足够的输入框');
|
||
}
|
||
}
|
||
|
||
// 填写表单
|
||
if (await page.$('input[name="username"]')) {
|
||
await page.fill('input[name="username"]', 'admin');
|
||
await page.fill('input[name="password"]', '111111');
|
||
console.log('✅ 表单已填写');
|
||
}
|
||
|
||
// 3. 提交表单
|
||
console.log('🖱️ 寻找并点击登录按钮...');
|
||
|
||
// 尝试多种登录按钮选择器
|
||
const buttonSelectors = [
|
||
'button:has-text("登录")',
|
||
'button[type="submit"]',
|
||
'.ant-btn-primary',
|
||
'button.login-btn',
|
||
];
|
||
|
||
let buttonClicked = false;
|
||
for (const selector of buttonSelectors) {
|
||
try {
|
||
const button = await page.$(selector);
|
||
if (button) {
|
||
await button.click();
|
||
console.log(`✅ 使用选择器 ${selector} 点击了登录按钮`);
|
||
buttonClicked = true;
|
||
break;
|
||
}
|
||
} catch (e) {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
if (!buttonClicked) {
|
||
console.log('⚠️ 未找到登录按钮,尝试按Enter键');
|
||
await page.keyboard.press('Enter');
|
||
}
|
||
|
||
// 4. 等待认证处理
|
||
console.log('⏳ 等待认证处理...');
|
||
await page.waitForTimeout(5000);
|
||
|
||
// 5. 检查结果
|
||
const currentUrl = page.url();
|
||
console.log(`📍 当前URL: ${currentUrl}`);
|
||
|
||
if (currentUrl.includes('/dashboard')) {
|
||
console.log('🎉 登录成功!成功跳转到dashboard');
|
||
|
||
// 检查token
|
||
const token = await page.evaluate(() => {
|
||
return (
|
||
localStorage.getItem('accessToken') ||
|
||
localStorage.getItem('token') ||
|
||
localStorage.getItem('authToken')
|
||
);
|
||
});
|
||
|
||
if (token) {
|
||
console.log(`✅ Token已存储: ${token.substring(0, 20)}...`);
|
||
} else {
|
||
console.log('⚠️ 未找到token,但页面已跳转');
|
||
}
|
||
|
||
// 等待dashboard加载并检查数据
|
||
await page.waitForTimeout(5000);
|
||
console.log('📊 检查dashboard数据和API调用...');
|
||
|
||
// 检查页面内容
|
||
const hasData = await page.evaluate(() => {
|
||
const bodyText = document.body.textContent || '';
|
||
return (
|
||
bodyText.includes('数据') ||
|
||
bodyText.includes('统计') ||
|
||
bodyText.includes('总数') ||
|
||
bodyText.includes('Dashboard') ||
|
||
bodyText.includes('仪表板')
|
||
);
|
||
});
|
||
|
||
if (hasData) {
|
||
console.log('✅ Dashboard显示数据内容');
|
||
} else {
|
||
console.log('⚠️ Dashboard可能没有显示预期数据');
|
||
}
|
||
|
||
// 检查是否有/base接口调用(用户特别要求的)
|
||
const baseApiCalls = apiCalls.filter((call) =>
|
||
call.url.includes('/base'),
|
||
);
|
||
if (baseApiCalls.length > 0) {
|
||
console.log(`✅ 发现 ${baseApiCalls.length} 个/base接口调用:`);
|
||
baseApiCalls.forEach((call) => {
|
||
console.log(` - ${call.method} ${call.url}`);
|
||
if (call.headers['authorization']) {
|
||
console.log(
|
||
` Authorization: ${call.headers['authorization'].substring(0, 30)}...`,
|
||
);
|
||
}
|
||
});
|
||
} else {
|
||
console.log('⚠️ 未发现/base接口调用');
|
||
}
|
||
|
||
// 再等待一段时间,确保所有异步数据加载完成
|
||
console.log('⏳ 等待更多API调用...');
|
||
await page.waitForTimeout(5000);
|
||
} else {
|
||
console.log('❌ 登录失败,仍在登录页面');
|
||
|
||
// 检查是否有错误消息
|
||
const errorMessage = await page.textContent('body');
|
||
if (errorMessage.includes('失败') || errorMessage.includes('错误')) {
|
||
console.log('⚠️ 页面显示错误信息');
|
||
}
|
||
}
|
||
|
||
// 6. 详细API调用分析
|
||
console.log(`\n📊 详细API调用分析:`);
|
||
console.log(`总共发起了 ${apiCalls.length} 个API调用`);
|
||
|
||
if (apiCalls.length > 0) {
|
||
console.log('\n🔍 所有API调用详情:');
|
||
apiCalls.forEach((call, index) => {
|
||
console.log(`${index + 1}. ${call.method} ${call.url}`);
|
||
if (call.headers['authorization']) {
|
||
console.log(
|
||
` 🔑 Authorization: ${call.headers['authorization'].substring(0, 40)}...`,
|
||
);
|
||
} else {
|
||
console.log(` ⚠️ 无Authorization头`);
|
||
}
|
||
console.log(` ⏰ 时间: ${call.timestamp}`);
|
||
console.log('');
|
||
});
|
||
|
||
// 分类统计
|
||
const authCalls = apiCalls.filter((call) => call.url.includes('/auth/'));
|
||
const baseCalls = apiCalls.filter((call) => call.url.includes('/base'));
|
||
const apiRoutes = apiCalls.filter((call) => call.url.includes('/api/'));
|
||
|
||
console.log('\n📈 分类统计:');
|
||
console.log(`- 认证接口(/auth/): ${authCalls.length} 个`);
|
||
console.log(`- 基础接口(/base): ${baseCalls.length} 个`);
|
||
console.log(`- API路由(/api/): ${apiRoutes.length} 个`);
|
||
|
||
// 检查401错误
|
||
const has401 = apiCalls.some(
|
||
(call) => call.url.includes('401') || call.status === 401,
|
||
);
|
||
if (has401) {
|
||
console.log('\n❌ 发现401认证错误');
|
||
} else {
|
||
console.log('\n✅ 未发现401认证错误');
|
||
}
|
||
} else {
|
||
console.log('❌ 没有发现任何API调用');
|
||
}
|
||
|
||
console.log('\n⏰ 保持浏览器打开15秒供手动检查...');
|
||
await page.waitForTimeout(15000);
|
||
} catch (error) {
|
||
console.error('❌ 测试失败:', error.message);
|
||
}
|
||
|
||
await browser.close();
|
||
}
|
||
|
||
completeAuthTest().catch(console.error);
|