tauri-android-tax/tests/qrscan.test.js
2026-07-09 20:03:35 +08:00

72 lines
2.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

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.

import { describe, it, expect } from "vitest";
import QRCode from "qrcode";
import {
extractUrl,
decodeQrFromImageData,
} from "../src/qrscan.js";
/**
* 用 qrcode 库把文本渲染成 RGBA 像素数据(放大每个模块以贴近真实拍摄清晰度)。
* @param {string} text 待编码文本。
* @param {number} scale 每个二维码模块放大的像素倍数。
* @param {number} quiet 静区(模块数)。
* @returns {{data:Uint8ClampedArray,width:number,height:number}} 画布像素数据。
*/
function renderQrImageData(text, scale = 8, quiet = 4) {
const qr = QRCode.create(text, { errorCorrectionLevel: "M" });
const size = qr.modules.size;
const modules = qr.modules.data;
const dim = (size + quiet * 2) * scale;
const data = new Uint8ClampedArray(dim * dim * 4);
// 先整体填白(含静区)。
data.fill(255);
for (let row = 0; row < size; row += 1) {
for (let col = 0; col < size; col += 1) {
if (!modules[row * size + col]) continue; // 0 = 浅色,跳过
const x0 = (col + quiet) * scale;
const y0 = (row + quiet) * scale;
for (let dy = 0; dy < scale; dy += 1) {
for (let dx = 0; dx < scale; dx += 1) {
const idx = ((y0 + dy) * dim + (x0 + dx)) * 4;
data[idx] = 0;
data[idx + 1] = 0;
data[idx + 2] = 0;
data[idx + 3] = 255;
}
}
}
}
return { data, width: dim, height: dim };
}
describe("qrscan", () => {
// 4-1 网址校验:接受 http/https拒绝其它内容。
it("4-1 extractUrl 仅接受 http/https 网址", () => {
expect(extractUrl("https://example.com/inv?id=1")).toBe(
"https://example.com/inv?id=1"
);
expect(extractUrl(" http://a.b/c ")).toBe("http://a.b/c");
expect(extractUrl("ftp://x")).toBe("");
expect(extractUrl("hello")).toBe("");
expect(extractUrl(null)).toBe("");
});
// 4-2 从生成的清晰二维码像素中解码,验证扫描核心逻辑正确。
it("4-2 decodeQrFromImageData 能识别清晰二维码", () => {
const url = "https://fapiao.example.com/open?id=20240701";
const imageData = renderQrImageData(url);
expect(decodeQrFromImageData(imageData)).toBe(url);
});
// 4-3 无法识别时返回 null而不是抛错。
it("4-3 无二维码时返回 null", () => {
const blank = {
data: new Uint8ClampedArray(64 * 64 * 4).fill(255),
width: 64,
height: 64,
};
expect(decodeQrFromImageData(blank)).toBeNull();
expect(decodeQrFromImageData(null)).toBeNull();
});
});