在 #544、#545、#546 的原作者 merge commit 之后独立修复:保留上传 Promise、处理重复上传与复制失败、格式对齐,以及易支付网关、订单证据、签名、通知幂等与安全关单校验。同步重建六平台插件产物和包。 验证:前端 1832 tests、build/typecheck、lint、相关格式检查通过;财务 SQLite、支付、插件 RPC 与产物专项通过。后端全量出现一项未改动的素材删除 SQLite 表锁失败,单独复跑 3 次通过,保留全量未通过记录。浏览器与真实商户验收待完成。#543 因迁移历史与能力限制回退暂缓。
44 lines
2.5 KiB
TypeScript
44 lines
2.5 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { registerPlugin, unregisterPlugin } from "../src/lib/plugins/plugin-registry";
|
|
import type { PluginManifest } from "../src/lib/plugins/plugin-types";
|
|
|
|
test("plugin upload caller preserves the installation promise", async () => {
|
|
const page = await Bun.file(new URL("../src/pages/admin/plugins/plugins-page.tsx", import.meta.url)).text();
|
|
expect(page).toContain("onUpload={upload}");
|
|
expect(page).not.toContain("onUpload={(file) => void upload(file)}");
|
|
});
|
|
|
|
test("plugin upload guards concurrent events and exposes installation failures", async () => {
|
|
const modal = await Bun.file(new URL("../src/pages/plugins/plugin-documentation-modals.tsx", import.meta.url)).text();
|
|
expect(modal).toContain("if (uploadInFlight.current) return;");
|
|
expect(modal.indexOf("uploadInFlight.current = true")).toBeLessThan(modal.indexOf("await onUpload(file)"));
|
|
expect(modal).toContain("uploadInFlight.current = false");
|
|
expect(modal).toContain("closable={!uploading}");
|
|
expect(modal).toContain('message.error(error instanceof Error ? error.message : "安装插件失败")');
|
|
expect(modal).toContain('aria-pressed={activeTab === "install"}');
|
|
expect(modal).toContain('aria-pressed={activeTab === "guide"}');
|
|
expect(modal).toContain("if (!navigator.clipboard) throw new Error");
|
|
expect(modal).toContain("clearTimeout(copyTimer.current)");
|
|
});
|
|
|
|
test("copied guide manifest is accepted by the real plugin registry", async () => {
|
|
const guide = await Bun.file(new URL("../src/pages/plugins/plugin-development-guide.md", import.meta.url)).text();
|
|
const example = guide.match(/```json\s*([\s\S]*?)```/)?.[1].trim();
|
|
expect(example).toBeTruthy();
|
|
const manifest = { ...(JSON.parse(example!) as PluginManifest), id: "merge-test-manifest-example" };
|
|
try {
|
|
expect(() => registerPlugin({ manifest })).not.toThrow();
|
|
} finally {
|
|
unregisterPlugin(manifest.id);
|
|
}
|
|
});
|
|
|
|
test("reduced motion preserves modal completion events", async () => {
|
|
const css = await Bun.file(new URL("../src/pages/admin/theme/admin-chrome.css", import.meta.url)).text();
|
|
const reducedMotion = css.slice(css.lastIndexOf("@media (prefers-reduced-motion: reduce)"));
|
|
expect(reducedMotion).toContain("animation-duration: 0.01ms !important");
|
|
expect(reducedMotion).toContain("transition-duration: 0.01ms !important");
|
|
expect(reducedMotion).not.toContain("animation: none");
|
|
expect(reducedMotion).not.toContain("transition: none");
|
|
});
|