- Rename 132 *.vitest.mjs -> *.vitest.ts - Rename vitest.setup.mjs -> vitest.setup.ts - Rename helpers/vitestEnvironment.mjs -> vitestEnvironment.ts - Delete settings_store.test.mjs (Node test runner, superseded by .vitest.ts) - Fix .mjs imports in vitest.setup.ts and grid_loader_adaptive_paging.vitest.ts Config updates: - vitest.config.mjs: setupFiles, include, coverage.include -> .ts - tsconfig.test.json: new dedicated config for test files (strict:false) - knip.json: update project pattern for tests - package.json: add typecheck:tests script (audit-only)
152 lines
4.8 KiB
TypeScript
152 lines
4.8 KiB
TypeScript
// @vitest-environment happy-dom
|
|
|
|
import { mount } from "@vue/test-utils";
|
|
import { reactive, nextTick } from "vue";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const panelStore = reactive({
|
|
sort: "mtime_desc",
|
|
scope: "output",
|
|
viewScope: "output",
|
|
similarResults: [],
|
|
similarTitle: "",
|
|
});
|
|
|
|
vi.mock("../stores/usePanelStore.js", () => ({
|
|
usePanelStore: () => panelStore,
|
|
}));
|
|
|
|
vi.mock("../api/client.js", () => ({
|
|
get: vi.fn(async () => ({ ok: false })),
|
|
getWatcherStatus: vi.fn(async () => ({ ok: true, data: { enabled: true } })),
|
|
toggleWatcher: vi.fn(async () => ({ ok: true })),
|
|
}));
|
|
|
|
vi.mock("../app/i18n.js", () => ({
|
|
t: (key, fallback) => fallback || key,
|
|
}));
|
|
|
|
vi.mock("../app/versionCheck.js", () => ({
|
|
VERSION_UPDATE_EVENT: "mjr:version-update",
|
|
getStoredVersionUpdateState: () => ({ available: false }),
|
|
}));
|
|
|
|
vi.mock("../app/events.js", () => ({
|
|
EVENTS: {
|
|
MFV_TOGGLE: "mjr:mfv-toggle",
|
|
MFV_VISIBILITY_CHANGED: "mjr:mfv-visibility-changed",
|
|
},
|
|
}));
|
|
|
|
const openMajoorSettingsMock = vi.fn();
|
|
|
|
vi.mock("../app/openMajoorSettings.js", () => ({
|
|
openMajoorSettings: openMajoorSettingsMock,
|
|
}));
|
|
|
|
vi.mock("../utils/tooltipShortcuts.js", () => ({
|
|
setTooltipHint: (el, label, hint) => {
|
|
if (!el) return;
|
|
const full = hint ? `${label} (${hint})` : label;
|
|
el.setAttribute("title", full);
|
|
el.setAttribute("aria-label", full);
|
|
},
|
|
}));
|
|
|
|
const MButtonStub = {
|
|
props: {
|
|
severity: String,
|
|
text: Boolean,
|
|
rounded: Boolean,
|
|
},
|
|
inheritAttrs: false,
|
|
template: '<button v-bind="$attrs"><slot /></button>',
|
|
};
|
|
|
|
const STUB_COMPONENTS = {
|
|
MButton: MButtonStub,
|
|
SearchBar: { template: "<div><slot /></div>" },
|
|
SortPopover: { template: "<div />" },
|
|
FilterPopover: { template: "<div />" },
|
|
CollectionsPopover: { template: "<div />" },
|
|
PinnedFoldersPopover: { template: "<div />" },
|
|
CustomRootsPopover: { template: "<div />" },
|
|
MessagePopover: { template: "<div />" },
|
|
};
|
|
|
|
async function flushMountedState() {
|
|
await nextTick();
|
|
await Promise.resolve();
|
|
await nextTick();
|
|
}
|
|
|
|
describe("HeaderSection MFV button", () => {
|
|
beforeEach(() => {
|
|
document.body.innerHTML = "";
|
|
});
|
|
|
|
afterEach(() => {
|
|
document.body.innerHTML = "";
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("applies the active class when MFV visibility changes", async () => {
|
|
const mod = await import("../vue/components/panel/HeaderSection.vue");
|
|
const wrapper = mount(mod.default, {
|
|
global: { stubs: STUB_COMPONENTS },
|
|
});
|
|
await flushMountedState();
|
|
|
|
const button = wrapper.element.querySelector(".mjr-am-header-tools > button.mjr-icon-btn");
|
|
const icon = button?.querySelector("i");
|
|
expect(button).toBeTruthy();
|
|
expect(icon?.className).toBe("pi pi-eye");
|
|
expect(button.getAttribute("title")).toContain("Majoor Floating Viewer");
|
|
expect(button.classList.contains("mjr-mfv-btn-active")).toBe(false);
|
|
|
|
window.dispatchEvent(
|
|
new CustomEvent("mjr:mfv-visibility-changed", { detail: { visible: true } }),
|
|
);
|
|
await flushMountedState();
|
|
|
|
expect(button.classList.contains("mjr-mfv-btn-active")).toBe(true);
|
|
wrapper.unmount();
|
|
});
|
|
|
|
it("starts active when the floating viewer is already visible in the DOM", async () => {
|
|
const liveViewer = document.createElement("div");
|
|
liveViewer.className = "mjr-mfv is-visible";
|
|
document.body.appendChild(liveViewer);
|
|
|
|
const mod = await import("../vue/components/panel/HeaderSection.vue");
|
|
const wrapper = mount(mod.default, {
|
|
global: { stubs: STUB_COMPONENTS },
|
|
});
|
|
await flushMountedState();
|
|
|
|
const button = wrapper.element.querySelector(".mjr-am-header-tools > button.mjr-icon-btn");
|
|
const icon = button?.querySelector("i");
|
|
expect(button).toBeTruthy();
|
|
expect(icon?.className).toBe("pi pi-eye");
|
|
expect(button.classList.contains("mjr-mfv-btn-active")).toBe(true);
|
|
wrapper.unmount();
|
|
});
|
|
|
|
it("opens Majoor settings from the header gear button", async () => {
|
|
const mod = await import("../vue/components/panel/HeaderSection.vue");
|
|
const wrapper = mount(mod.default, {
|
|
global: { stubs: STUB_COMPONENTS },
|
|
});
|
|
await flushMountedState();
|
|
|
|
const button = wrapper.element.querySelector(".mjr-settings-shortcut-btn");
|
|
expect(button).toBeTruthy();
|
|
expect(button?.querySelector("i")?.className).toBe("pi pi-cog");
|
|
|
|
await button.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
expect(openMajoorSettingsMock).toHaveBeenCalledTimes(1);
|
|
wrapper.unmount();
|
|
});
|
|
});
|