feat: add extension update check
This commit is contained in:
@@ -48,6 +48,50 @@ describe("background-index", () => {
|
||||
expect(sendResponse).toHaveBeenCalledWith({ ok: true });
|
||||
});
|
||||
|
||||
test("downloads extension update assets", async () => {
|
||||
const listeners: Array<
|
||||
(message: unknown, sender: unknown, sendResponse: (response: unknown) => void) => boolean | void
|
||||
> = [];
|
||||
const download = vi.fn(async () => undefined);
|
||||
const sendResponse = vi.fn();
|
||||
|
||||
registerBackgroundMessageHandler({
|
||||
downloads: {
|
||||
download
|
||||
},
|
||||
runtime: {
|
||||
onMessage: {
|
||||
addListener(listener) {
|
||||
listeners.push(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const result = listeners[0](
|
||||
{
|
||||
filename: "star-chart-search-enhancer-internal.zip",
|
||||
type: "update:download",
|
||||
url: "https://cos.example.com/star-chart-search-enhancer/releases/0.2.0421.3/star-chart-search-enhancer-internal.zip"
|
||||
},
|
||||
{},
|
||||
sendResponse
|
||||
);
|
||||
|
||||
expect(result).toBe(true);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
expect(download).toHaveBeenCalledWith({
|
||||
filename: "star-chart-search-enhancer-internal.zip",
|
||||
saveAs: true,
|
||||
url: "https://cos.example.com/star-chart-search-enhancer/releases/0.2.0421.3/star-chart-search-enhancer-internal.zip"
|
||||
});
|
||||
expect(sendResponse).toHaveBeenCalledWith({
|
||||
ok: true,
|
||||
type: "update:download-ack"
|
||||
});
|
||||
});
|
||||
|
||||
test("responds to auth:get-state with auth status", async () => {
|
||||
const listeners: Array<
|
||||
(message: unknown, sender: unknown, sendResponse: (response: unknown) => void) => boolean | void
|
||||
|
||||
@@ -43,10 +43,11 @@ describe("manifest", () => {
|
||||
"https://*.xingtu.cn/ad/creator/market*",
|
||||
"https://login-api.intelligrow.cn/*",
|
||||
"https://talent-search.intelligrow.cn/*",
|
||||
"http://192.168.31.21:8083/*"
|
||||
"http://192.168.31.21:8083/*",
|
||||
"https://*/*"
|
||||
]);
|
||||
expect(releaseManifest.host_permissions).not.toEqual(
|
||||
expect.arrayContaining(["http://*/*", "https://*/*", "http://127.0.0.1:4319/*"])
|
||||
expect.arrayContaining(["http://*/*", "http://127.0.0.1:4319/*"])
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -51,6 +51,101 @@ describe("popup-entry", () => {
|
||||
expect(dom.window.document.body.textContent).toContain("token");
|
||||
});
|
||||
|
||||
test("shows available extension updates in the popup", async () => {
|
||||
const fetchUpdateManifest = vi.fn(async () => ({
|
||||
guideUrl: "https://cos.example.com/guide.pdf",
|
||||
latestVersion: "0.2.0421.3",
|
||||
minSupportedVersion: "0.2.0421.2",
|
||||
publishedAt: "2026-05-19",
|
||||
releaseNotes: ["支持检查更新"],
|
||||
zipUrl: "https://cos.example.com/plugin.zip"
|
||||
}));
|
||||
|
||||
dom.window.document.body.innerHTML = "<main id='app'></main>";
|
||||
|
||||
await bootPopup({
|
||||
currentVersion: "0.2.0421.2",
|
||||
document: dom.window.document,
|
||||
fetchUpdateManifest,
|
||||
sendMessage: vi.fn(async () => ({
|
||||
ok: true,
|
||||
type: "auth:state",
|
||||
value: {
|
||||
isAuthenticated: true,
|
||||
userInfo: { name: "Dev" }
|
||||
}
|
||||
}))
|
||||
});
|
||||
await Promise.resolve();
|
||||
|
||||
expect(fetchUpdateManifest).toHaveBeenCalledTimes(1);
|
||||
expect(dom.window.document.body.textContent).toContain("当前版本:0.2.0421.2");
|
||||
expect(dom.window.document.body.textContent).toContain("发现新版本:0.2.0421.3");
|
||||
expect(dom.window.document.body.textContent).toContain("支持检查更新");
|
||||
expect(
|
||||
dom.window.document.querySelector('[data-popup-download-update="button"]')
|
||||
).not.toBeNull();
|
||||
expect(
|
||||
dom.window.document.querySelector('[data-popup-download-guide="button"]')
|
||||
).not.toBeNull();
|
||||
});
|
||||
|
||||
test("downloads update assets from popup buttons", async () => {
|
||||
const sendMessage = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
type: "auth:state",
|
||||
value: {
|
||||
isAuthenticated: true,
|
||||
userInfo: { name: "Dev" }
|
||||
}
|
||||
})
|
||||
.mockResolvedValue({ ok: true, type: "update:download-ack" });
|
||||
|
||||
dom.window.document.body.innerHTML = "<main id='app'></main>";
|
||||
|
||||
await bootPopup({
|
||||
currentVersion: "0.2.0421.2",
|
||||
document: dom.window.document,
|
||||
fetchUpdateManifest: vi.fn(async () => ({
|
||||
guideUrl: "https://cos.example.com/guide.pdf",
|
||||
latestVersion: "0.2.0421.3",
|
||||
minSupportedVersion: "0.2.0421.2",
|
||||
publishedAt: "2026-05-19",
|
||||
releaseNotes: [],
|
||||
zipUrl: "https://cos.example.com/plugin.zip"
|
||||
})),
|
||||
sendMessage
|
||||
});
|
||||
await Promise.resolve();
|
||||
|
||||
(
|
||||
dom.window.document.querySelector(
|
||||
'[data-popup-download-update="button"]'
|
||||
) as HTMLButtonElement | null
|
||||
)?.click();
|
||||
(
|
||||
dom.window.document.querySelector(
|
||||
'[data-popup-download-guide="button"]'
|
||||
) as HTMLButtonElement | null
|
||||
)?.click();
|
||||
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
|
||||
expect(sendMessage).toHaveBeenCalledWith({
|
||||
filename: "star-chart-search-enhancer-internal.zip",
|
||||
type: "update:download",
|
||||
url: "https://cos.example.com/plugin.zip"
|
||||
});
|
||||
expect(sendMessage).toHaveBeenCalledWith({
|
||||
filename: "星图增强插件-超简单安装使用指南.pdf",
|
||||
type: "update:download",
|
||||
url: "https://cos.example.com/guide.pdf"
|
||||
});
|
||||
});
|
||||
|
||||
test("renders a protected api test button in the dev panel", async () => {
|
||||
dom.window.document.body.innerHTML = "<main id='app'></main>";
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import {
|
||||
compareExtensionVersions,
|
||||
parseUpdateManifest
|
||||
} from "../src/shared/update-check";
|
||||
|
||||
describe("update-check", () => {
|
||||
test("compares dotted extension versions numerically", () => {
|
||||
expect(compareExtensionVersions("0.2.0421.3", "0.2.0421.2")).toBeGreaterThan(0);
|
||||
expect(compareExtensionVersions("0.2.10.0", "0.2.9.9")).toBeGreaterThan(0);
|
||||
expect(compareExtensionVersions("0.2.0421.2", "0.2.0421.2")).toBe(0);
|
||||
expect(compareExtensionVersions("0.2.0421.1", "0.2.0421.2")).toBeLessThan(0);
|
||||
});
|
||||
|
||||
test("parses a valid update manifest", () => {
|
||||
expect(
|
||||
parseUpdateManifest({
|
||||
guideUrl: "https://cos.example.com/guide.pdf",
|
||||
latestVersion: "0.2.0421.3",
|
||||
minSupportedVersion: "0.2.0421.2",
|
||||
publishedAt: "2026-05-19",
|
||||
releaseNotes: ["支持检查更新"],
|
||||
zipUrl: "https://cos.example.com/plugin.zip"
|
||||
})
|
||||
).toEqual({
|
||||
guideUrl: "https://cos.example.com/guide.pdf",
|
||||
latestVersion: "0.2.0421.3",
|
||||
minSupportedVersion: "0.2.0421.2",
|
||||
publishedAt: "2026-05-19",
|
||||
releaseNotes: ["支持检查更新"],
|
||||
zipUrl: "https://cos.example.com/plugin.zip"
|
||||
});
|
||||
});
|
||||
|
||||
test("rejects invalid update manifests", () => {
|
||||
expect(parseUpdateManifest({ latestVersion: "0.2.0421.3" })).toBeNull();
|
||||
expect(
|
||||
parseUpdateManifest({
|
||||
guideUrl: "javascript:alert(1)",
|
||||
latestVersion: "0.2.0421.3",
|
||||
minSupportedVersion: "0.2.0421.2",
|
||||
publishedAt: "2026-05-19",
|
||||
releaseNotes: [],
|
||||
zipUrl: "https://cos.example.com/plugin.zip"
|
||||
})
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user