feat(tests): add comprehensive unit tests for various components including AboutPage, CallPage, and MessagesPage
This commit is contained in:
198
tests/frontend/MapPage.test.js
Normal file
198
tests/frontend/MapPage.test.js
Normal file
@@ -0,0 +1,198 @@
|
||||
import { mount } from "@vue/test-utils";
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
|
||||
// Mock TileCache BEFORE importing MapPage
|
||||
vi.mock("@/js/TileCache", () => ({
|
||||
default: {
|
||||
getTile: vi.fn(),
|
||||
setTile: vi.fn(),
|
||||
clear: vi.fn(),
|
||||
initPromise: Promise.resolve(),
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock OpenLayers
|
||||
vi.mock("ol/Map", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
on: vi.fn(),
|
||||
addLayer: vi.fn(),
|
||||
addInteraction: vi.fn(),
|
||||
getView: vi.fn().mockReturnValue({
|
||||
on: vi.fn(),
|
||||
setCenter: vi.fn(),
|
||||
setZoom: vi.fn(),
|
||||
getCenter: vi.fn().mockReturnValue([0, 0]),
|
||||
getZoom: vi.fn().mockReturnValue(2),
|
||||
fit: vi.fn(),
|
||||
animate: vi.fn(),
|
||||
}),
|
||||
getLayers: vi.fn().mockReturnValue({
|
||||
clear: vi.fn(),
|
||||
push: vi.fn(),
|
||||
getArray: vi.fn().mockReturnValue([]),
|
||||
}),
|
||||
forEachFeatureAtPixel: vi.fn(),
|
||||
setTarget: vi.fn(),
|
||||
updateSize: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock("ol/View", () => ({ default: vi.fn() }));
|
||||
vi.mock("ol/layer/Tile", () => ({ default: vi.fn() }));
|
||||
vi.mock("ol/layer/Vector", () => ({ default: vi.fn() }));
|
||||
vi.mock("ol/source/XYZ", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
getTileLoadFunction: vi.fn().mockReturnValue(vi.fn()),
|
||||
setTileLoadFunction: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/source/Vector", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
clear: vi.fn(),
|
||||
addFeature: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/proj", () => ({
|
||||
fromLonLat: vi.fn((coords) => coords),
|
||||
toLonLat: vi.fn((coords) => coords),
|
||||
}));
|
||||
vi.mock("ol/control", () => ({
|
||||
defaults: vi.fn().mockReturnValue([]),
|
||||
}));
|
||||
vi.mock("ol/interaction/DragBox", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
on: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
import MapPage from "@/components/map/MapPage.vue";
|
||||
|
||||
describe("MapPage.vue", () => {
|
||||
let axiosMock;
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock localStorage on window correctly
|
||||
const localStorageMock = {
|
||||
getItem: vi.fn().mockReturnValue("true"),
|
||||
setItem: vi.fn(),
|
||||
removeItem: vi.fn(),
|
||||
clear: vi.fn(),
|
||||
};
|
||||
Object.defineProperty(window, "localStorage", { value: localStorageMock, writable: true });
|
||||
|
||||
axiosMock = {
|
||||
get: vi.fn().mockImplementation((url) => {
|
||||
const defaultData = {
|
||||
config: { map_offline_enabled: false },
|
||||
mbtiles: [],
|
||||
conversations: [],
|
||||
telemetry: [],
|
||||
markers: [],
|
||||
history: [],
|
||||
announces: [],
|
||||
};
|
||||
if (url.includes("/api/v1/config"))
|
||||
return Promise.resolve({ data: { config: { map_offline_enabled: false } } });
|
||||
if (url.includes("/api/v1/map/mbtiles")) return Promise.resolve({ data: [] });
|
||||
if (url.includes("/api/v1/lxmf/conversations")) return Promise.resolve({ data: { conversations: [] } });
|
||||
if (url.includes("/api/v1/telemetry/peers")) return Promise.resolve({ data: { telemetry: [] } });
|
||||
if (url.includes("/api/v1/telemetry/markers")) return Promise.resolve({ data: { markers: [] } });
|
||||
if (url.includes("/api/v1/map/offline")) return Promise.resolve({ data: {} });
|
||||
if (url.includes("nominatim")) return Promise.resolve({ data: [] });
|
||||
return Promise.resolve({ data: defaultData });
|
||||
}),
|
||||
post: vi.fn().mockResolvedValue({ data: {} }),
|
||||
patch: vi.fn().mockResolvedValue({ data: {} }),
|
||||
delete: vi.fn().mockResolvedValue({ data: {} }),
|
||||
};
|
||||
window.axios = axiosMock;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete window.axios;
|
||||
});
|
||||
|
||||
const mountMapPage = () => {
|
||||
return mount(MapPage, {
|
||||
global: {
|
||||
mocks: {
|
||||
$t: (key) => key,
|
||||
$route: { query: {} },
|
||||
$filters: {
|
||||
formatDestinationHash: (h) => h,
|
||||
},
|
||||
},
|
||||
stubs: {
|
||||
MaterialDesignIcon: {
|
||||
template: '<div class="mdi-stub" :data-icon-name="iconName"></div>',
|
||||
props: ["iconName"],
|
||||
},
|
||||
Toggle: {
|
||||
template: '<div class="toggle-stub"></div>',
|
||||
props: ["modelValue", "id"],
|
||||
},
|
||||
LoadingSpinner: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
it("renders the map title", async () => {
|
||||
const wrapper = mountMapPage();
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(wrapper.text()).toContain("map.title");
|
||||
});
|
||||
|
||||
it("toggles settings dropdown", async () => {
|
||||
const wrapper = mountMapPage();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.isSettingsOpen).toBe(false);
|
||||
|
||||
// Find settings button by icon name
|
||||
const settingsButton = wrapper.find('.mdi-stub[data-icon-name="cog"]').element.parentElement;
|
||||
await settingsButton.click();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.isSettingsOpen).toBe(true);
|
||||
});
|
||||
|
||||
it("performs search and displays results", async () => {
|
||||
// Mock fetch for search
|
||||
global.fetch = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: () => Promise.resolve([{ place_id: 1, display_name: "Result 1", type: "city", lat: "0", lon: "0" }]),
|
||||
});
|
||||
|
||||
const wrapper = mountMapPage();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
const searchInput = wrapper.find('input[type="text"]');
|
||||
await searchInput.trigger("focus");
|
||||
await searchInput.setValue("test search");
|
||||
|
||||
// Trigger search by enter key
|
||||
await searchInput.trigger("keydown.enter");
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick(); // Wait for fetch
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.text()).toContain("Result 1");
|
||||
expect(wrapper.text()).toContain("city");
|
||||
|
||||
delete global.fetch;
|
||||
});
|
||||
|
||||
it("toggles export mode", async () => {
|
||||
const wrapper = mountMapPage();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
const exportButton = wrapper.find('button[title="map.export_area"]');
|
||||
if (exportButton.exists()) {
|
||||
await exportButton.trigger("click");
|
||||
expect(wrapper.vm.isExportMode).toBe(true);
|
||||
expect(wrapper.text()).toContain("map.export_instructions");
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user