Files
Sudo-Ivan 51d705ffa4
Some checks failed
CI / test-backend (push) Successful in 4s
CI / build-frontend (push) Successful in 56s
Tests / test (push) Successful in 1m35s
CI / lint (push) Failing after 4m56s
feat(tests): add fuzzing tests for telemetry unpacking, interface configuration parsing, and LXMF message handling
2026-01-02 20:06:18 -06:00

111 lines
3.6 KiB
JavaScript

import { mount } from "@vue/test-utils";
import { describe, it, expect, vi, beforeEach } from "vitest";
import InterfacesPage from "../../meshchatx/src/frontend/components/interfaces/InterfacesPage.vue";
// Mock global objects
const mockAxios = {
get: vi.fn(),
post: vi.fn(),
};
window.axios = mockAxios;
const mockToast = {
success: vi.fn(),
error: vi.fn(),
};
// We need to handle how ToastUtils is imported in the component
// If it's a global or imported, we might need a different approach.
// Let's assume it's available via window or we can mock the import if using vitest aliases.
vi.mock("../../js/ToastUtils", () => ({
default: {
success: vi.fn(),
error: vi.fn(),
},
}));
// Mock router/route
const mockRoute = {
query: {},
};
const mockRouter = {
push: vi.fn(),
};
describe("InterfacesPage.vue", () => {
beforeEach(() => {
vi.clearAllMocks();
mockAxios.get.mockResolvedValue({ data: { interfaces: [], app_info: { is_reticulum_running: true } } });
});
it("loads interfaces on mount", async () => {
mockAxios.get.mockImplementation((url) => {
if (url.includes("interfaces")) {
return Promise.resolve({ data: { interfaces: [{ name: "Test Iface", type: "TCP" }] } });
}
if (url.includes("app/info")) {
return Promise.resolve({ data: { app_info: { is_reticulum_running: true } } });
}
return Promise.reject();
});
const wrapper = mount(InterfacesPage, {
global: {
mocks: {
$route: mockRoute,
$router: mockRouter,
$t: (msg) => msg,
},
stubs: ["RouterLink", "MaterialDesignIcon", "IconButton", "Interface", "ImportInterfacesModal"],
},
});
await wrapper.vm.$nextTick();
await wrapper.vm.$nextTick(); // wait for multiple awaits
expect(mockAxios.get).toHaveBeenCalledWith("/api/v1/reticulum/interfaces");
expect(wrapper.vm.interfaces.length).toBe(1);
});
it("tracks changes when an interface is enabled", async () => {
const wrapper = mount(InterfacesPage, {
global: {
mocks: {
$route: mockRoute,
$router: mockRouter,
$t: (msg) => msg,
},
stubs: ["RouterLink", "MaterialDesignIcon", "IconButton", "Interface", "ImportInterfacesModal"],
},
});
await wrapper.vm.enableInterface("test-iface");
expect(wrapper.vm.hasPendingInterfaceChanges).toBe(true);
expect(wrapper.vm.modifiedInterfaceNames.has("test-iface")).toBe(true);
});
it("clears pending changes after RNS reload", async () => {
mockAxios.post.mockResolvedValue({ data: { message: "Reloaded" } });
const wrapper = mount(InterfacesPage, {
global: {
mocks: {
$route: mockRoute,
$router: mockRouter,
$t: (msg) => msg,
},
stubs: ["RouterLink", "MaterialDesignIcon", "IconButton", "Interface", "ImportInterfacesModal"],
},
});
wrapper.vm.hasPendingInterfaceChanges = true;
wrapper.vm.modifiedInterfaceNames.add("test-iface");
await wrapper.vm.reloadRns();
expect(wrapper.vm.hasPendingInterfaceChanges).toBe(false);
expect(wrapper.vm.modifiedInterfaceNames.size).toBe(0);
expect(mockAxios.post).toHaveBeenCalledWith("/api/v1/reticulum/reload");
});
});