Files
xianyan/scripts/signin_api_test.dart
Developer 228095f80a chore: 完成v6.7.0版本迭代更新
本次更新涵盖多个功能模块的优化与新增:
1. 新增Wi-Fi直连配对方式与协作画布模块
2. 完成设备管理重命名API与前端适配
3. 优化日签卡片空数据保护与UI细节
4. 新增剪贴板工具与每日运势会话
5. 修复应用锁恢复、语音消息录制等已知问题
6. 完善文件传输统计与配对逻辑
7. 更新安卓权限配置与iOS隐私描述
8. 新增自动化测试脚本与文档
9. 清理旧版审计报告与测试文件
2026-05-14 05:35:18 +08:00

357 lines
11 KiB
Dart
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.
// ============================================================
// 闲言APP — 签到接口测试脚本
// 创建时间: 2026-05-14
// 更新时间: 2026-05-14
// 作用: 测试签到系统HTTP接口
// - 签到日历数据获取
// - 签到状态验证
// - 补签接口测试
// - API基础URL: https://tools.wktyl.com
// 上次更新: 初始版本
// 运行: dart run Scripts/signin_api_test.dart
// ============================================================
import 'dart:convert';
import 'dart:io';
const String kApiBase = 'https://tools.wktyl.com';
const String kSigninBase = '/api/user_center';
const Duration kTimeout = Duration(seconds: 15);
int _passCount = 0;
int _failCount = 0;
void _result(String name, bool pass, {String? detail}) {
final icon = pass ? '' : '';
final status = pass ? 'PASS' : 'FAIL';
_passCount += pass ? 1 : 0;
_failCount += pass ? 0 : 1;
print('$icon [$status] $name${detail != null ? '$detail' : ''}');
}
Future<Map<String, dynamic>?> _httpGet(
String path, {
Map<String, dynamic>? queryParameters,
String? token,
}) async {
try {
final uri = Uri.parse('$kApiBase$path').replace(
queryParameters: queryParameters?.map(
(k, v) => MapEntry(k, v.toString()),
),
);
final client = HttpClient();
client.connectionTimeout = kTimeout;
final request = await client.getUrl(uri);
request.headers.set('Accept', 'application/json');
request.headers.set('Content-Type', 'application/x-www-form-urlencoded');
if (token != null && token.isNotEmpty) {
request.headers.set('Authorization', 'Bearer $token');
}
final response = await request.close();
final body = await response.transform(utf8.decoder).join();
client.close();
return jsonDecode(body) as Map<String, dynamic>;
} catch (e) {
print(' ⚠️ HTTP GET $path 失败: $e');
return null;
}
}
Future<Map<String, dynamic>?> _httpPost(
String path, {
Map<String, dynamic>? data,
String? token,
}) async {
try {
final uri = Uri.parse('$kApiBase$path');
final client = HttpClient();
client.connectionTimeout = kTimeout;
final request = await client.postUrl(uri);
request.headers.set('Accept', 'application/json');
request.headers.set('Content-Type', 'application/x-www-form-urlencoded');
if (token != null && token.isNotEmpty) {
request.headers.set('Authorization', 'Bearer $token');
}
if (data != null && data.isNotEmpty) {
final formData = data.entries
.map((e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value.toString())}')
.join('&');
request.write(formData);
}
final response = await request.close();
final body = await response.transform(utf8.decoder).join();
client.close();
return jsonDecode(body) as Map<String, dynamic>;
} catch (e) {
print(' ⚠️ HTTP POST $path 失败: $e');
return null;
}
}
String? _testToken;
Future<void> main(List<String> args) async {
print('╔══════════════════════════════════════════════════════════╗');
print('║ 闲言APP — 签到接口测试 ║');
print('║ API Base: $kApiBase');
print('╚══════════════════════════════════════════════════════════╝\n');
if (args.isNotEmpty) {
_testToken = args[0];
print('🔑 使用提供的Token: ${_testToken!.substring(0, 10)}...\n');
} else {
print('⚠️ 未提供Token, 部分需要登录的接口可能返回401');
print(' 用法: dart run Scripts/signin_api_test.dart <token>\n');
}
await testSigninCalendar();
await testSigninStatus();
await testSigninAction();
await testSigninMakeup();
print('\n╔══════════════════════════════════════════════════════════╗');
print('║ 测试结果汇总 ║');
print('╠══════════════════════════════════════════════════════════╣');
print('║ ✅ 通过: $_passCount');
print('║ ❌ 失败: $_failCount');
print('║ 📊 总计: ${_passCount + _failCount}');
print('╚══════════════════════════════════════════════════════════╝');
exit(_failCount > 0 ? 1 : 0);
}
Future<void> testSigninCalendar() async {
print('\n━━━ 1. 签到日历数据获取 ━━━');
final result = await _httpGet(
'$kSigninBase/signin_calendar',
token: _testToken,
);
_result(
'签到日历接口响应',
result != null,
detail: result != null ? 'code=${result['code']}' : '请求失败',
);
if (result != null) {
final code = result['code'] as int? ?? 0;
_result(
'接口返回成功(code=1)',
code == 1,
detail: 'code=$code, msg=${result['msg']}',
);
if (code == 1) {
final data = result['data'] as Map<String, dynamic>? ?? {};
_result(
'日历数据非空',
data.isNotEmpty,
detail: 'keys=${data.keys.join(', ')}',
);
final calendar = data['calendar'];
_result(
'包含calendar字段',
calendar != null,
detail: calendar != null
? '类型=${calendar.runtimeType}, 数据摘要=${_truncate(calendar.toString(), 120)}'
: '缺失calendar字段',
);
final continuous = data['current_continuous'] as int?;
_result(
'包含连续签到天数',
continuous != null,
detail: 'current_continuous=$continuous',
);
final totalSignins = data['total_signins'] as int?;
_result(
'包含累计签到天数',
totalSignins != null,
detail: 'total_signins=$totalSignins',
);
}
}
final now = DateTime.now();
final monthStr =
'${now.year}-${now.month.toString().padLeft(2, '0')}';
final resultWithMonth = await _httpGet(
'$kSigninBase/signin_calendar',
queryParameters: {'month': monthStr},
token: _testToken,
);
_result(
'指定月份查询日历',
resultWithMonth != null,
detail: resultWithMonth != null
? 'month=$monthStr, code=${resultWithMonth['code']}'
: '请求失败',
);
}
Future<void> testSigninStatus() async {
print('\n━━━ 2. 签到状态验证 ━━━');
final calendarResult = await _httpGet(
'$kSigninBase/signin_calendar',
token: _testToken,
);
if (calendarResult == null) {
_result('签到状态验证(依赖日历接口)', false, detail: '日历接口请求失败');
return;
}
final code = calendarResult['code'] as int? ?? 0;
if (code != 1) {
_result(
'签到状态验证',
false,
detail: '日历接口返回code=$code, msg=${calendarResult['msg']}',
);
return;
}
final data = calendarResult['data'] as Map<String, dynamic>? ?? {};
final calendar = data['calendar'];
final now = DateTime.now();
final todayStr =
'${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}';
bool todaySigned = false;
if (calendar is Map<String, dynamic>) {
todaySigned = calendar[todayStr] == true ||
calendar[todayStr] == 1;
} else if (calendar is List) {
for (final item in calendar) {
if (item is Map<String, dynamic>) {
final date = item['date']?.toString() ?? '';
final signed = item['signed'] == true || item['signed'] == 1;
if (date == todayStr && signed) {
todaySigned = true;
break;
}
} else if (item?.toString() == todayStr) {
todaySigned = true;
break;
}
}
}
_result(
'今日签到状态可解析',
true,
detail: 'today=$todayStr, todaySigned=$todaySigned',
);
final continuous = data['current_continuous'] as int? ?? 0;
_result(
'连续签到天数有效',
continuous >= 0,
detail: 'current_continuous=$continuous',
);
}
Future<void> testSigninAction() async {
print('\n━━━ 3. 签到接口测试 ━━━');
if (_testToken == null) {
_result('签到接口(需登录)', false, detail: '未提供Token, 跳过');
return;
}
final result = await _httpPost(
'$kSigninBase/signin',
token: _testToken,
);
_result(
'签到接口响应',
result != null,
detail: result != null ? 'code=${result['code']}' : '请求失败',
);
if (result != null) {
final code = result['code'] as int? ?? 0;
final msg = result['msg'] as String? ?? '';
if (code == 1) {
final data = result['data'] as Map<String, dynamic>? ?? {};
final continuous = data['continuous'] as int? ?? 0;
final coinReward = data['coin_reward'] as int? ?? 0;
final todaySigned = data['today_signed'] as bool? ?? true;
_result('签到成功', true, detail: '连续$continuous天, +$coinReward积分');
_result(
'返回today_signed',
data.containsKey('today_signed'),
detail: 'today_signed=$todaySigned',
);
_result(
'返回coin_reward',
data.containsKey('coin_reward'),
detail: 'coin_reward=$coinReward',
);
} else if (msg.contains('已签到')) {
_result('今日已签到', true, detail: 'msg=$msg');
} else {
_result('签到接口返回', false, detail: 'code=$code, msg=$msg');
}
}
}
Future<void> testSigninMakeup() async {
print('\n━━━ 4. 补签接口测试 ━━━');
if (_testToken == null) {
_result('补签接口(需登录)', false, detail: '未提供Token, 跳过');
return;
}
final now = DateTime.now();
final yesterday = now.subtract(const Duration(days: 1));
final yesterdayStr =
'${yesterday.year}-${yesterday.month.toString().padLeft(2, '0')}-${yesterday.day.toString().padLeft(2, '0')}';
print(' 尝试补签日期: $yesterdayStr (注意: 如已签到或积分不足会失败)');
final result = await _httpPost(
'$kSigninBase/signin_makeup',
data: {'date': yesterdayStr},
token: _testToken,
);
_result(
'补签接口响应',
result != null,
detail: result != null ? 'code=${result['code']}' : '请求失败',
);
if (result != null) {
final code = result['code'] as int? ?? 0;
final msg = result['msg'] as String? ?? '';
if (code == 1) {
_result('补签成功', true, detail: 'date=$yesterdayStr');
} else {
_result(
'补签接口返回',
false,
detail: 'code=$code, msg=$msg (可能已签到/积分不足/每日限1次)',
);
}
}
}
String _truncate(String s, int maxLen) {
if (s.length <= maxLen) return s;
return '${s.substring(0, maxLen)}...';
}