mirror of
https://github.com/Silentely/eSIM-Tools.git
synced 2026-09-03 06:24:20 +08:00
- 修复 loadQRCodeLibrary Promise 永久挂起(Issue #75 根因) - 检测已存在脚本标签,移除失效脚本并重新加载 - 添加 5 秒超时保护,防止 Session 恢复后二维码冻结 - 统一 cleanup 函数清理监听器和定时器 - 修复 XSS 风险 - 使用 DOM API 创建错误提示,避免 innerHTML 注入 - 移除模板字符串 ${t(...)} 直接注入 - 修复 i18n 硬编码 - createQRCodeContainer 接受 labels 参数支持多语言 - generateQRCode* 函数支持 labels 透传 - UIController 传入 tl() 翻译后的可访问性标签 - Schema 验证优化 - qrcode-generate 保留手动验证,确保 405 优先级 - 添加注释说明设计意图 - 代码规范 - tests/security/qrcode-generate.test.js 添加 'use strict' ✅ 测试: 8 passed, 0 failed
107 lines
3.1 KiB
JavaScript
107 lines
3.1 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* qrcode-generate Function 单元测试
|
|
*/
|
|
|
|
describe('qrcode-generate Function', () => {
|
|
const originalEnv = process.env;
|
|
|
|
function loadFunction(toDataURLImpl) {
|
|
jest.resetModules();
|
|
process.env = {
|
|
...originalEnv,
|
|
ACCESS_KEY: 'test-access-key',
|
|
ALLOWED_ORIGIN: 'https://esim.cosr.eu.org'
|
|
};
|
|
|
|
jest.doMock('qrcode', () => ({
|
|
toDataURL: jest.fn(toDataURLImpl)
|
|
}), { virtual: true });
|
|
|
|
return {
|
|
QRCode: require('qrcode'),
|
|
qrcodeGenerate: require('../../netlify/functions/qrcode-generate')
|
|
};
|
|
}
|
|
|
|
afterEach(() => {
|
|
process.env = originalEnv;
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
it('有效请求应该返回 base64 PNG data URL', async () => {
|
|
const { QRCode, qrcodeGenerate } = loadFunction(() => Promise.resolve('data:image/png;base64,qrcode'));
|
|
|
|
const result = await qrcodeGenerate.handler({
|
|
httpMethod: 'POST',
|
|
headers: {
|
|
origin: 'https://esim.cosr.eu.org',
|
|
'x-esim-key': 'test-access-key'
|
|
},
|
|
body: JSON.stringify({ data: 'LPA:1$example', size: 300 }),
|
|
queryStringParameters: {}
|
|
}, { functionName: 'qrcode-generate' });
|
|
|
|
expect(result.statusCode).toBe(200);
|
|
expect(JSON.parse(result.body)).toEqual({
|
|
success: true,
|
|
qrcode: 'data:image/png;base64,qrcode'
|
|
});
|
|
expect(QRCode.toDataURL).toHaveBeenCalledWith('LPA:1$example', expect.objectContaining({
|
|
type: 'image/png',
|
|
width: 300
|
|
}));
|
|
});
|
|
|
|
it('缺少 data 时应该返回 400', async () => {
|
|
const { qrcodeGenerate } = loadFunction(() => Promise.resolve('data:image/png;base64,qrcode'));
|
|
|
|
const result = await qrcodeGenerate.handler({
|
|
httpMethod: 'POST',
|
|
headers: {
|
|
origin: 'https://esim.cosr.eu.org',
|
|
'x-esim-key': 'test-access-key'
|
|
},
|
|
body: JSON.stringify({ size: 300 }),
|
|
queryStringParameters: {}
|
|
}, { functionName: 'qrcode-generate' });
|
|
|
|
expect(result.statusCode).toBe(400);
|
|
expect(result.body).toContain('data is required');
|
|
});
|
|
|
|
it('size 超出范围时应该返回 400', async () => {
|
|
const { qrcodeGenerate } = loadFunction(() => Promise.resolve('data:image/png;base64,qrcode'));
|
|
|
|
const result = await qrcodeGenerate.handler({
|
|
httpMethod: 'POST',
|
|
headers: {
|
|
origin: 'https://esim.cosr.eu.org',
|
|
'x-esim-key': 'test-access-key'
|
|
},
|
|
body: JSON.stringify({ data: 'LPA:1$example', size: 601 }),
|
|
queryStringParameters: {}
|
|
}, { functionName: 'qrcode-generate' });
|
|
|
|
expect(result.statusCode).toBe(400);
|
|
expect(result.body).toContain('size must be between 200 and 600');
|
|
});
|
|
|
|
it('非 POST 请求应该返回 405', async () => {
|
|
const { qrcodeGenerate } = loadFunction(() => Promise.resolve('data:image/png;base64,qrcode'));
|
|
|
|
const result = await qrcodeGenerate.handler({
|
|
httpMethod: 'GET',
|
|
headers: {
|
|
origin: 'https://esim.cosr.eu.org',
|
|
'x-esim-key': 'test-access-key'
|
|
},
|
|
body: '{}',
|
|
queryStringParameters: {}
|
|
}, { functionName: 'qrcode-generate' });
|
|
|
|
expect(result.statusCode).toBe(405);
|
|
});
|
|
});
|