mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-06-22 06:03:49 +08:00
355 lines
10 KiB
TypeScript
355 lines
10 KiB
TypeScript
import { fireEvent, render, screen, waitFor } from "@testing-library/vue";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import App from "@/App.vue";
|
|
import { listFavoriteFolders } from "@/modules/backendApi";
|
|
import { setAuthSession } from "@/global/authState";
|
|
import type { FavoriteFolder, FavoriteItem } from "@/global/typedefinition";
|
|
|
|
const invoke = vi.fn();
|
|
|
|
const favoriteFolders: FavoriteFolder[] = [
|
|
{
|
|
id: 7,
|
|
name: "默认收藏夹",
|
|
itemCount: 1,
|
|
createdAt: "2026-05-18T00:00:00Z",
|
|
updatedAt: "2026-05-18T00:00:00Z",
|
|
},
|
|
];
|
|
|
|
const favoriteItems: FavoriteItem[] = [
|
|
{
|
|
id: 11,
|
|
appKey: "app:office:wps",
|
|
pkgname: "wps",
|
|
name: "WPS",
|
|
category: "office",
|
|
iconUrl: "",
|
|
createdAt: "2026-05-18T00:00:00Z",
|
|
},
|
|
];
|
|
|
|
const createDeferred = <T>() => {
|
|
let resolve!: (value: T) => void;
|
|
const promise = new Promise<T>((promiseResolve) => {
|
|
resolve = promiseResolve;
|
|
});
|
|
|
|
return { promise, resolve };
|
|
};
|
|
|
|
vi.mock("axios", () => {
|
|
const get = vi.fn(async (url: string) => {
|
|
if (url.includes("categories.json")) {
|
|
return { data: { office: { zh: "办公" } } };
|
|
}
|
|
if (url.includes("/office/applist.json")) {
|
|
return {
|
|
data: [
|
|
{
|
|
Name: "WPS",
|
|
Pkgname: "wps",
|
|
Version: "1.0.0",
|
|
Filename: "wps_1.0.0_amd64.deb",
|
|
Torrent_address: "",
|
|
Author: "",
|
|
Contributor: "",
|
|
Website: "",
|
|
Update: "",
|
|
Size: "",
|
|
More: "",
|
|
Tags: "",
|
|
img_urls: [],
|
|
icons: "",
|
|
},
|
|
],
|
|
};
|
|
}
|
|
return { data: [] };
|
|
});
|
|
|
|
return {
|
|
default: {
|
|
create: () => ({ get }),
|
|
},
|
|
};
|
|
});
|
|
|
|
vi.mock("@/modules/updateCenter", () => ({
|
|
createUpdateCenterStore: () => ({
|
|
isOpen: { value: false },
|
|
showCloseConfirm: { value: false },
|
|
showMigrationConfirm: { value: false },
|
|
searchQuery: { value: "" },
|
|
selectedTaskKeys: { value: new Set<string>() },
|
|
snapshot: {
|
|
value: { items: [], tasks: [], warnings: [], hasRunningTasks: false },
|
|
},
|
|
filteredItems: { value: [] },
|
|
allSelected: { value: false },
|
|
someSelected: { value: false },
|
|
bind: vi.fn(),
|
|
unbind: vi.fn(),
|
|
open: vi.fn(),
|
|
refresh: vi.fn(),
|
|
ignoreItem: vi.fn(),
|
|
unignoreItem: vi.fn(),
|
|
toggleSelection: vi.fn(),
|
|
toggleSelectAll: vi.fn(),
|
|
getSelectedItems: vi.fn(() => []),
|
|
closeNow: vi.fn(),
|
|
startSelected: vi.fn(),
|
|
requestClose: vi.fn(),
|
|
}),
|
|
}));
|
|
|
|
vi.mock("@/modules/backendApi", () => ({
|
|
addFavoriteItem: vi.fn(),
|
|
bulkDeleteFavoriteItems: vi.fn(),
|
|
createFavoriteFolder: vi.fn(),
|
|
exchangeFlarumToken: vi.fn(),
|
|
listFavoriteFolders: vi.fn(async () => favoriteFolders),
|
|
listFavoriteItems: vi.fn(async () => favoriteItems),
|
|
setBackendToken: vi.fn(),
|
|
}));
|
|
|
|
describe("App account placeholders", () => {
|
|
beforeEach(() => {
|
|
invoke.mockReset();
|
|
invoke.mockImplementation(async (channel: string) => {
|
|
if (channel === "get-store-filter") return "both";
|
|
if (channel === "check-spark-available") return true;
|
|
if (channel === "check-apm-available") return true;
|
|
if (channel === "get-app-version") return "5.0.0";
|
|
return [];
|
|
});
|
|
|
|
Object.assign(window.ipcRenderer, {
|
|
invoke,
|
|
on: vi.fn(),
|
|
off: vi.fn(),
|
|
send: vi.fn(),
|
|
});
|
|
|
|
window.apm_store.arch = "amd64";
|
|
localStorage.clear();
|
|
setAuthSession({
|
|
accessToken: "backend-token",
|
|
tokenType: "bearer",
|
|
user: {
|
|
id: 1,
|
|
flarumUserId: "42",
|
|
username: "momen",
|
|
displayName: "Momen",
|
|
avatarUrl: "https://bbs.spark-app.store/avatar.png",
|
|
forumLevel: "管理员",
|
|
forumGroups: ["管理员"],
|
|
},
|
|
});
|
|
|
|
vi.stubGlobal(
|
|
"matchMedia",
|
|
vi.fn(() => ({
|
|
matches: false,
|
|
addEventListener: vi.fn(),
|
|
removeEventListener: vi.fn(),
|
|
})),
|
|
);
|
|
vi.stubGlobal("scrollTo", vi.fn());
|
|
class MockIntersectionObserver {
|
|
observe = vi.fn();
|
|
disconnect = vi.fn();
|
|
unobserve = vi.fn();
|
|
}
|
|
vi.stubGlobal("IntersectionObserver", MockIntersectionObserver);
|
|
});
|
|
|
|
it("shows the user management placeholder from the logged-in quick menu", async () => {
|
|
render(App);
|
|
|
|
await fireEvent.click(await screen.findByRole("button", { name: /Momen/ }));
|
|
await fireEvent.click(screen.getByText("用户管理"));
|
|
|
|
expect(
|
|
await screen.findByRole("heading", { name: "用户管理" }),
|
|
).toBeTruthy();
|
|
expect(screen.queryByText("请登录后查看和管理账号信息。")).toBeNull();
|
|
});
|
|
|
|
it("shows the favorites placeholder from the logged-in quick menu", async () => {
|
|
render(App);
|
|
|
|
await fireEvent.click(
|
|
await screen.findByRole("button", { name: /^Momen$/ }),
|
|
);
|
|
await fireEvent.click(screen.getByText("我的收藏"));
|
|
|
|
expect(
|
|
await screen.findByRole("heading", { name: "我的收藏" }),
|
|
).toBeTruthy();
|
|
expect(screen.queryByText("请登录后查看我的收藏。")).toBeNull();
|
|
});
|
|
|
|
it("refreshes installed apps before resolving favorite management state", async () => {
|
|
invoke.mockImplementation(async (channel: string) => {
|
|
if (channel === "get-store-filter") return "both";
|
|
if (channel === "check-spark-available") return true;
|
|
if (channel === "check-apm-available") return true;
|
|
if (channel === "get-app-version") return "5.0.0";
|
|
if (channel === "list-installed") {
|
|
return {
|
|
success: true,
|
|
apps: [
|
|
{
|
|
pkgname: "wps",
|
|
name: "WPS",
|
|
version: "1.0.0",
|
|
arch: "amd64",
|
|
flags: "installed",
|
|
origin: "apm",
|
|
},
|
|
],
|
|
};
|
|
}
|
|
return [];
|
|
});
|
|
render(App);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText("2")).toBeTruthy();
|
|
});
|
|
|
|
await fireEvent.click(await screen.findByRole("button", { name: /Momen/ }));
|
|
await fireEvent.click(screen.getByText("我的收藏"));
|
|
|
|
expect(
|
|
await screen.findByRole("heading", { name: "我的收藏" }),
|
|
).toBeTruthy();
|
|
expect(await screen.findByText("已安装")).toBeTruthy();
|
|
expect(invoke).toHaveBeenCalledWith("list-installed", {
|
|
origin: "apm",
|
|
pkgnameList: undefined,
|
|
});
|
|
});
|
|
|
|
it("refreshes Spark installed state for favorites in both mode", async () => {
|
|
invoke.mockImplementation(async (channel: string, payload?: unknown) => {
|
|
if (channel === "get-store-filter") return "both";
|
|
if (channel === "check-spark-available") return true;
|
|
if (channel === "check-apm-available") return true;
|
|
if (channel === "get-app-version") return "5.0.0";
|
|
if (channel === "list-installed") {
|
|
const request = payload as { origin?: string };
|
|
if (request.origin === "spark") {
|
|
return {
|
|
success: true,
|
|
apps: [
|
|
{
|
|
pkgname: "wps",
|
|
name: "WPS",
|
|
version: "1.0.0",
|
|
arch: "amd64",
|
|
flags: "installed",
|
|
origin: "spark",
|
|
},
|
|
],
|
|
};
|
|
}
|
|
return { success: true, apps: [] };
|
|
}
|
|
return [];
|
|
});
|
|
render(App);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText("2")).toBeTruthy();
|
|
});
|
|
|
|
await fireEvent.click(await screen.findByRole("button", { name: /Momen/ }));
|
|
await fireEvent.click(screen.getByText("我的收藏"));
|
|
|
|
expect(
|
|
await screen.findByRole("heading", { name: "我的收藏" }),
|
|
).toBeTruthy();
|
|
expect(await screen.findByText("已安装")).toBeTruthy();
|
|
expect(invoke).toHaveBeenCalledWith("list-installed", {
|
|
origin: "spark",
|
|
pkgnameList: ["wps"],
|
|
});
|
|
});
|
|
|
|
it("clears favorite data and leaves protected favorites view after logout", async () => {
|
|
render(App);
|
|
|
|
await fireEvent.click(await screen.findByRole("button", { name: /Momen/ }));
|
|
await fireEvent.click(screen.getByText("我的收藏"));
|
|
|
|
expect(
|
|
await screen.findByRole("heading", { name: "我的收藏" }),
|
|
).toBeTruthy();
|
|
expect(await screen.findByText("默认收藏夹 (1)")).toBeTruthy();
|
|
expect(await screen.findByText("wps · office")).toBeTruthy();
|
|
|
|
await fireEvent.click(
|
|
await screen.findByRole("button", { name: /^Momen$/ }),
|
|
);
|
|
if (!screen.queryByText("退出登录")) {
|
|
await fireEvent.click(
|
|
await screen.findByRole("button", { name: /^Momen$/ }),
|
|
);
|
|
}
|
|
await fireEvent.click(screen.getByText("退出登录"));
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByRole("button", { name: "登录 / 注册" })).toBeTruthy();
|
|
});
|
|
expect(screen.queryByText("默认收藏夹 (1)")).toBeNull();
|
|
expect(screen.queryByText("wps · office")).toBeNull();
|
|
expect(screen.queryByRole("heading", { name: "我的收藏" })).toBeNull();
|
|
});
|
|
|
|
it("does not reopen the favorite selector when folder loading resolves after logout", async () => {
|
|
const slowFolders = createDeferred<FavoriteFolder[]>();
|
|
vi.mocked(listFavoriteFolders).mockReturnValueOnce(slowFolders.promise);
|
|
render(App);
|
|
|
|
await fireEvent.click(await screen.findByText("全部应用"));
|
|
await fireEvent.click(await screen.findByText("wps · 1.0.0"));
|
|
expect(await screen.findByRole("heading", { name: "WPS" })).toBeTruthy();
|
|
await fireEvent.click(screen.getByRole("button", { name: "收藏" }));
|
|
|
|
await fireEvent.click(
|
|
await screen.findByRole("button", { name: /^Momen$/ }),
|
|
);
|
|
if (!screen.queryByText("退出登录")) {
|
|
await fireEvent.click(
|
|
await screen.findByRole("button", { name: /^Momen$/ }),
|
|
);
|
|
}
|
|
await fireEvent.click(screen.getByText("退出登录"));
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByRole("button", { name: "登录 / 注册" })).toBeTruthy();
|
|
});
|
|
|
|
slowFolders.resolve([
|
|
{
|
|
id: 42,
|
|
name: "旧账号收藏夹",
|
|
itemCount: 1,
|
|
createdAt: "2026-05-18T00:00:00Z",
|
|
updatedAt: "2026-05-18T00:00:00Z",
|
|
},
|
|
]);
|
|
await slowFolders.promise;
|
|
await Promise.resolve();
|
|
await Promise.resolve();
|
|
|
|
expect(screen.queryByText("旧账号收藏夹 (1)")).toBeNull();
|
|
expect(screen.queryByText("wps · office")).toBeNull();
|
|
expect(screen.queryByText("旧账号收藏夹")).toBeNull();
|
|
expect(screen.queryByRole("dialog", { name: "选择收藏夹" })).toBeNull();
|
|
});
|
|
});
|