mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-06-22 14:13:49 +08:00
42046caf2c
为更新中心添加加载状态管理,包括: - 在打开和刷新操作时显示加载状态 - 禁用刷新按钮防止重复操作 - 添加加载中的动画效果和提示文本 - 优化加载时的UI显示
273 lines
6.9 KiB
TypeScript
273 lines
6.9 KiB
TypeScript
import { computed, ref } from "vue";
|
|
import { fireEvent, render, screen } from "@testing-library/vue";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import UpdateCenterModal from "@/components/UpdateCenterModal.vue";
|
|
import type {
|
|
UpdateCenterItem,
|
|
UpdateCenterSnapshot,
|
|
UpdateCenterTaskState,
|
|
} from "@/global/typedefinition";
|
|
import type { UpdateCenterStore } from "@/modules/updateCenter";
|
|
|
|
const createItem = (
|
|
overrides: Partial<UpdateCenterItem> = {},
|
|
): UpdateCenterItem => ({
|
|
taskKey: "aptss:spark-weather",
|
|
packageName: "spark-weather",
|
|
displayName: "Spark Weather",
|
|
currentVersion: "1.0.0",
|
|
newVersion: "2.0.0",
|
|
source: "aptss",
|
|
...overrides,
|
|
});
|
|
|
|
const createTask = (
|
|
overrides: Partial<UpdateCenterTaskState> = {},
|
|
): UpdateCenterTaskState => ({
|
|
taskKey: "aptss:spark-weather",
|
|
packageName: "spark-weather",
|
|
source: "aptss",
|
|
status: "downloading",
|
|
progress: 42,
|
|
logs: [],
|
|
errorMessage: "",
|
|
...overrides,
|
|
});
|
|
|
|
const createStore = (
|
|
overrides: Partial<UpdateCenterSnapshot> = {},
|
|
): UpdateCenterStore => {
|
|
const snapshot = ref<UpdateCenterSnapshot>({
|
|
items: [
|
|
createItem({
|
|
taskKey: "aptss:spark-weather",
|
|
source: "aptss",
|
|
}),
|
|
createItem({
|
|
taskKey: "apm:spark-clock",
|
|
packageName: "spark-clock",
|
|
displayName: "Spark Clock",
|
|
source: "apm",
|
|
isMigration: true,
|
|
migrationTarget: "apm",
|
|
}),
|
|
],
|
|
tasks: [createTask()],
|
|
warnings: ["更新过程中请勿关闭商店"],
|
|
hasRunningTasks: true,
|
|
...overrides,
|
|
});
|
|
|
|
const selectedTaskKeys = ref(new Set<string>(["aptss:spark-weather"]));
|
|
|
|
return {
|
|
isOpen: ref(true),
|
|
loading: ref(false),
|
|
showCloseConfirm: ref(true),
|
|
showMigrationConfirm: ref(false),
|
|
searchQuery: ref(""),
|
|
selectedTaskKeys,
|
|
snapshot,
|
|
filteredItems: computed(() => snapshot.value.items),
|
|
allSelected: computed(() => false),
|
|
someSelected: computed(() => selectedTaskKeys.value.size > 0),
|
|
bind: vi.fn(),
|
|
unbind: vi.fn(),
|
|
open: vi.fn(),
|
|
refresh: vi.fn(),
|
|
ignoreItem: vi.fn(),
|
|
unignoreItem: vi.fn(),
|
|
toggleSelection: vi.fn(),
|
|
getSelectedItems: vi.fn(() =>
|
|
snapshot.value.items.filter(
|
|
(item) =>
|
|
selectedTaskKeys.value.has(item.taskKey) && item.ignored !== true,
|
|
),
|
|
),
|
|
closeNow: vi.fn(),
|
|
startSelected: vi.fn(),
|
|
requestClose: vi.fn(),
|
|
};
|
|
};
|
|
|
|
describe("UpdateCenterModal", () => {
|
|
it("constrains the update list so it can scroll with a visible scrollbar", () => {
|
|
const store = createStore({
|
|
items: Array.from({ length: 20 }, (_, index) =>
|
|
createItem({
|
|
taskKey: `aptss:spark-item-${index}`,
|
|
packageName: `spark-item-${index}`,
|
|
displayName: `Spark Item ${index}`,
|
|
}),
|
|
),
|
|
tasks: [],
|
|
warnings: [],
|
|
hasRunningTasks: false,
|
|
});
|
|
|
|
const { container } = render(UpdateCenterModal, {
|
|
props: {
|
|
show: true,
|
|
store,
|
|
},
|
|
});
|
|
|
|
const scrollContainer = container.querySelector(".scrollbar-muted");
|
|
|
|
expect(scrollContainer?.className).toContain("overflow-y-auto");
|
|
expect(scrollContainer?.className).toContain("flex-1");
|
|
expect(scrollContainer?.className).toContain("overscroll-contain");
|
|
});
|
|
|
|
it("renders source tags, running state, warnings, and migration marker", () => {
|
|
const store = createStore();
|
|
|
|
render(UpdateCenterModal, {
|
|
props: {
|
|
show: true,
|
|
store,
|
|
},
|
|
});
|
|
|
|
expect(screen.getByText("软件更新")).toBeTruthy();
|
|
expect(screen.getByText("传统deb")).toBeTruthy();
|
|
expect(screen.getByText("APM")).toBeTruthy();
|
|
expect(screen.getByText("将迁移到 APM")).toBeTruthy();
|
|
expect(screen.getByText("更新过程中请勿关闭商店")).toBeTruthy();
|
|
expect(screen.getByText("下载中")).toBeTruthy();
|
|
expect(screen.getByText("42%")).toBeTruthy();
|
|
});
|
|
|
|
it("renders ignored items as disabled instead of normal selectable actions", () => {
|
|
const store = createStore({
|
|
items: [
|
|
createItem({
|
|
taskKey: "aptss:spark-weather",
|
|
packageName: "spark-weather",
|
|
displayName: "Spark Weather",
|
|
source: "aptss",
|
|
ignored: true,
|
|
}),
|
|
],
|
|
tasks: [],
|
|
warnings: [],
|
|
hasRunningTasks: false,
|
|
});
|
|
|
|
render(UpdateCenterModal, {
|
|
props: {
|
|
show: true,
|
|
store,
|
|
},
|
|
});
|
|
|
|
expect(screen.getByText("已忽略")).toBeTruthy();
|
|
expect(screen.getAllByRole("checkbox").at(-1)).toBeDisabled();
|
|
expect(screen.getByRole("button", { name: "取消忽略" })).toBeTruthy();
|
|
});
|
|
|
|
it("renders ignore action for normal items", () => {
|
|
const store = createStore({
|
|
items: [
|
|
createItem({
|
|
taskKey: "aptss:spark-weather",
|
|
packageName: "spark-weather",
|
|
displayName: "Spark Weather",
|
|
source: "aptss",
|
|
ignored: false,
|
|
}),
|
|
],
|
|
tasks: [],
|
|
warnings: [],
|
|
hasRunningTasks: false,
|
|
});
|
|
|
|
render(UpdateCenterModal, {
|
|
props: {
|
|
show: true,
|
|
store,
|
|
},
|
|
});
|
|
|
|
expect(screen.getByRole("button", { name: "忽略更新" })).toBeTruthy();
|
|
});
|
|
|
|
it("renders migration confirmation when requested", () => {
|
|
const store = createStore({ hasRunningTasks: false });
|
|
store.showMigrationConfirm.value = true;
|
|
|
|
render(UpdateCenterModal, {
|
|
props: {
|
|
show: true,
|
|
store,
|
|
},
|
|
});
|
|
|
|
expect(screen.getByText("迁移确认")).toBeTruthy();
|
|
});
|
|
|
|
it("close button triggers request-close flow", async () => {
|
|
const store = createStore({ hasRunningTasks: false });
|
|
|
|
render(UpdateCenterModal, {
|
|
props: {
|
|
show: true,
|
|
store,
|
|
},
|
|
});
|
|
|
|
await fireEvent.click(screen.getByRole("button", { name: "关闭" }));
|
|
|
|
expect(store.requestClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("shows loading panel when loading with no items", () => {
|
|
const store = createStore({
|
|
items: [],
|
|
tasks: [],
|
|
warnings: [],
|
|
hasRunningTasks: false,
|
|
});
|
|
store.loading.value = true;
|
|
|
|
render(UpdateCenterModal, {
|
|
props: {
|
|
show: true,
|
|
store,
|
|
},
|
|
});
|
|
|
|
expect(screen.getByText("正在检查更新…")).toBeTruthy();
|
|
});
|
|
|
|
it("shows refresh hint while loading with existing items", () => {
|
|
const store = createStore({ hasRunningTasks: false });
|
|
store.loading.value = true;
|
|
|
|
render(UpdateCenterModal, {
|
|
props: {
|
|
show: true,
|
|
store,
|
|
},
|
|
});
|
|
|
|
expect(screen.getByText("Spark Weather")).toBeTruthy();
|
|
expect(screen.getByText("正在刷新更新列表…")).toBeTruthy();
|
|
});
|
|
|
|
it("disables refresh button while loading", () => {
|
|
const store = createStore({ hasRunningTasks: false });
|
|
store.loading.value = true;
|
|
|
|
render(UpdateCenterModal, {
|
|
props: {
|
|
show: true,
|
|
store,
|
|
},
|
|
});
|
|
|
|
expect(screen.getByRole("button", { name: /刷新/ })).toBeDisabled();
|
|
});
|
|
});
|