numerous improvements
This commit is contained in:
@@ -182,13 +182,13 @@ describe("AboutPage.vue", () => {
|
||||
});
|
||||
mountAboutPage();
|
||||
|
||||
expect(axiosMock.get).toHaveBeenCalledTimes(4); // info, config, health, snapshots
|
||||
expect(axiosMock.get).toHaveBeenCalledTimes(5); // info, config, health, snapshots, backups
|
||||
|
||||
vi.advanceTimersByTime(5000);
|
||||
expect(axiosMock.get).toHaveBeenCalledTimes(5);
|
||||
expect(axiosMock.get).toHaveBeenCalledTimes(6); // +1 from updateInterval
|
||||
|
||||
vi.advanceTimersByTime(5000);
|
||||
expect(axiosMock.get).toHaveBeenCalledTimes(6);
|
||||
expect(axiosMock.get).toHaveBeenCalledTimes(7); // +2 from updateInterval
|
||||
});
|
||||
|
||||
it("handles vacuum database action", async () => {
|
||||
|
||||
86
tests/frontend/AddInterfaceDiscovery.test.js
Normal file
86
tests/frontend/AddInterfaceDiscovery.test.js
Normal file
@@ -0,0 +1,86 @@
|
||||
import { mount } from "@vue/test-utils";
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import AddInterfacePage from "../../meshchatx/src/frontend/components/interfaces/AddInterfacePage.vue";
|
||||
|
||||
// mocks
|
||||
const mockAxios = {
|
||||
get: vi.fn(),
|
||||
post: vi.fn(),
|
||||
};
|
||||
window.axios = mockAxios;
|
||||
|
||||
vi.mock("../../meshchatx/src/frontend/js/DialogUtils", () => ({
|
||||
default: {
|
||||
alert: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../../meshchatx/src/frontend/js/ToastUtils", () => ({
|
||||
default: {
|
||||
success: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe("AddInterfacePage.vue discovery", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockAxios.get.mockResolvedValue({ data: {} });
|
||||
mockAxios.post.mockResolvedValue({ data: { message: "ok" } });
|
||||
});
|
||||
|
||||
it("adds discovery fields when interface is discoverable", async () => {
|
||||
const wrapper = mount(AddInterfacePage, {
|
||||
global: {
|
||||
mocks: {
|
||||
$route: { query: {} },
|
||||
$router: { push: vi.fn() },
|
||||
$t: (msg) => msg,
|
||||
},
|
||||
stubs: ["RouterLink", "MaterialDesignIcon", "Toggle", "ExpandingSection", "FormLabel", "FormSubLabel"],
|
||||
},
|
||||
});
|
||||
|
||||
// required interface fields
|
||||
wrapper.vm.newInterfaceName = "TestIface";
|
||||
wrapper.vm.newInterfaceType = "TCPClientInterface";
|
||||
wrapper.vm.newInterfaceTargetHost = "example.com";
|
||||
wrapper.vm.newInterfaceTargetPort = "4242";
|
||||
|
||||
// discovery fields
|
||||
wrapper.vm.discovery.discoverable = true;
|
||||
wrapper.vm.discovery.discovery_name = "Region A";
|
||||
wrapper.vm.discovery.announce_interval = 720;
|
||||
wrapper.vm.discovery.reachable_on = "/usr/local/bin/ip.sh";
|
||||
wrapper.vm.discovery.discovery_stamp_value = 22;
|
||||
wrapper.vm.discovery.discovery_encrypt = true;
|
||||
wrapper.vm.discovery.publish_ifac = true;
|
||||
wrapper.vm.discovery.latitude = 1.23;
|
||||
wrapper.vm.discovery.longitude = 4.56;
|
||||
wrapper.vm.discovery.height = 7;
|
||||
wrapper.vm.discovery.discovery_frequency = 915000000;
|
||||
wrapper.vm.discovery.discovery_bandwidth = 125000;
|
||||
wrapper.vm.discovery.discovery_modulation = "LoRa";
|
||||
|
||||
await wrapper.vm.addInterface();
|
||||
|
||||
expect(mockAxios.post).toHaveBeenCalledWith(
|
||||
"/api/v1/reticulum/interfaces/add",
|
||||
expect.objectContaining({
|
||||
discoverable: "yes",
|
||||
discovery_name: "Region A",
|
||||
announce_interval: 720,
|
||||
reachable_on: "/usr/local/bin/ip.sh",
|
||||
discovery_stamp_value: 22,
|
||||
discovery_encrypt: true,
|
||||
publish_ifac: true,
|
||||
latitude: 1.23,
|
||||
longitude: 4.56,
|
||||
height: 7,
|
||||
discovery_frequency: 915000000,
|
||||
discovery_bandwidth: 125000,
|
||||
discovery_modulation: "LoRa",
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,7 @@ import GlobalState from "../../meshchatx/src/frontend/js/GlobalState";
|
||||
const mockAxios = {
|
||||
get: vi.fn(),
|
||||
post: vi.fn(),
|
||||
patch: vi.fn(),
|
||||
};
|
||||
window.axios = mockAxios;
|
||||
|
||||
@@ -110,4 +111,85 @@ describe("InterfacesPage.vue", () => {
|
||||
expect(wrapper.vm.modifiedInterfaceNames.size).toBe(0);
|
||||
expect(mockAxios.post).toHaveBeenCalledWith("/api/v1/reticulum/reload");
|
||||
});
|
||||
|
||||
it("loads and saves discovery config", async () => {
|
||||
mockAxios.get.mockImplementation((url) => {
|
||||
if (url === "/api/v1/reticulum/interfaces") {
|
||||
return Promise.resolve({ data: { interfaces: [] } });
|
||||
}
|
||||
if (url === "/api/v1/app/info") {
|
||||
return Promise.resolve({ data: { app_info: { is_reticulum_running: true } } });
|
||||
}
|
||||
if (url === "/api/v1/reticulum/discovery") {
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
discovery: {
|
||||
discover_interfaces: "true",
|
||||
interface_discovery_sources: "abc",
|
||||
required_discovery_value: "16",
|
||||
autoconnect_discovered_interfaces: "3",
|
||||
network_identity: "/tmp/netid",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
return Promise.reject();
|
||||
});
|
||||
|
||||
mockAxios.patch.mockResolvedValue({
|
||||
data: {
|
||||
discovery: {
|
||||
discover_interfaces: false,
|
||||
interface_discovery_sources: null,
|
||||
required_discovery_value: 18,
|
||||
autoconnect_discovered_interfaces: 5,
|
||||
network_identity: "/tmp/new",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const wrapper = mount(InterfacesPage, {
|
||||
global: {
|
||||
mocks: {
|
||||
$route: mockRoute,
|
||||
$router: mockRouter,
|
||||
$t: (msg) => msg,
|
||||
},
|
||||
stubs: [
|
||||
"RouterLink",
|
||||
"MaterialDesignIcon",
|
||||
"IconButton",
|
||||
"Interface",
|
||||
"ImportInterfacesModal",
|
||||
"Toggle",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.discoveryConfig.discover_interfaces).toBe(true);
|
||||
expect(wrapper.vm.discoveryConfig.interface_discovery_sources).toBe("abc");
|
||||
expect(wrapper.vm.discoveryConfig.required_discovery_value).toBe(16);
|
||||
expect(wrapper.vm.discoveryConfig.autoconnect_discovered_interfaces).toBe(3);
|
||||
expect(wrapper.vm.discoveryConfig.network_identity).toBe("/tmp/netid");
|
||||
|
||||
wrapper.vm.discoveryConfig.discover_interfaces = false;
|
||||
wrapper.vm.discoveryConfig.interface_discovery_sources = "";
|
||||
wrapper.vm.discoveryConfig.required_discovery_value = 18;
|
||||
wrapper.vm.discoveryConfig.autoconnect_discovered_interfaces = 5;
|
||||
wrapper.vm.discoveryConfig.network_identity = "/tmp/new";
|
||||
|
||||
await wrapper.vm.saveDiscoveryConfig();
|
||||
|
||||
expect(mockAxios.patch).toHaveBeenCalledWith("/api/v1/reticulum/discovery", {
|
||||
discover_interfaces: false,
|
||||
interface_discovery_sources: null,
|
||||
required_discovery_value: 18,
|
||||
autoconnect_discovered_interfaces: 5,
|
||||
network_identity: "/tmp/new",
|
||||
});
|
||||
expect(wrapper.vm.savingDiscovery).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,6 +45,10 @@ vi.mock("ol/Map", () => ({
|
||||
forEachFeatureAtPixel: vi.fn(),
|
||||
setTarget: vi.fn(),
|
||||
updateSize: vi.fn(),
|
||||
getViewport: vi.fn().mockReturnValue({
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn(),
|
||||
}),
|
||||
})),
|
||||
}));
|
||||
|
||||
@@ -63,6 +67,7 @@ vi.mock("ol/source/Vector", () => ({
|
||||
addFeature: vi.fn(),
|
||||
addFeatures: vi.fn(),
|
||||
getFeatures: vi.fn().mockReturnValue([]),
|
||||
on: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/proj", () => ({
|
||||
@@ -75,11 +80,30 @@ vi.mock("ol/control", () => ({
|
||||
vi.mock("ol/interaction/Draw", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
on: vi.fn(),
|
||||
setActive: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/interaction/Modify", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
on: vi.fn(),
|
||||
setActive: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/interaction/Select", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
on: vi.fn(),
|
||||
setActive: vi.fn(),
|
||||
getFeatures: vi.fn().mockReturnValue({
|
||||
getArray: vi.fn().mockReturnValue([]),
|
||||
clear: vi.fn(),
|
||||
push: vi.fn(),
|
||||
}),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/interaction/Translate", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
on: vi.fn(),
|
||||
setActive: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/interaction/Snap", () => ({
|
||||
@@ -106,6 +130,29 @@ vi.mock("ol/format/GeoJSON", () => ({
|
||||
readFeatures: vi.fn().mockReturnValue([]),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/style", () => ({
|
||||
Style: vi.fn().mockImplementation(() => ({})),
|
||||
Text: vi.fn().mockImplementation(() => ({})),
|
||||
Fill: vi.fn().mockImplementation(() => ({})),
|
||||
Stroke: vi.fn().mockImplementation(() => ({})),
|
||||
Circle: vi.fn().mockImplementation(() => ({})),
|
||||
Icon: vi.fn().mockImplementation(() => ({})),
|
||||
}));
|
||||
vi.mock("ol/sphere", () => ({
|
||||
getArea: vi.fn(),
|
||||
getLength: vi.fn(),
|
||||
}));
|
||||
vi.mock("ol/geom", () => ({
|
||||
LineString: vi.fn(),
|
||||
Polygon: vi.fn(),
|
||||
Circle: vi.fn(),
|
||||
}));
|
||||
vi.mock("ol/geom/Polygon", () => ({
|
||||
fromCircle: vi.fn(),
|
||||
}));
|
||||
vi.mock("ol/Observable", () => ({
|
||||
unByKey: vi.fn(),
|
||||
}));
|
||||
|
||||
describe("MapPage.vue - Drawing and Measurement Tools", () => {
|
||||
let axiosMock;
|
||||
@@ -196,13 +243,18 @@ describe("MapPage.vue - Drawing and Measurement Tools", () => {
|
||||
const wrapper = mountMapPage();
|
||||
await wrapper.vm.$nextTick();
|
||||
await new Promise((resolve) => setTimeout(resolve, 50)); // wait for initMap
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.map).toBeDefined();
|
||||
|
||||
const pointTool = wrapper.find('button[title="map.tool_point"]');
|
||||
await pointTool.trigger("click");
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(wrapper.vm.drawType).toBe("Point");
|
||||
expect(wrapper.vm.draw).not.toBeNull();
|
||||
|
||||
await pointTool.trigger("click");
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(wrapper.vm.drawType).toBeNull();
|
||||
expect(wrapper.vm.draw).toBeNull();
|
||||
});
|
||||
@@ -211,13 +263,18 @@ describe("MapPage.vue - Drawing and Measurement Tools", () => {
|
||||
const wrapper = mountMapPage();
|
||||
await wrapper.vm.$nextTick();
|
||||
await new Promise((resolve) => setTimeout(resolve, 50)); // wait for initMap
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.map).toBeDefined();
|
||||
|
||||
const measureTool = wrapper.find('button[title="map.tool_measure"]');
|
||||
await measureTool.trigger("click");
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(wrapper.vm.isMeasuring).toBe(true);
|
||||
expect(wrapper.vm.drawType).toBe("LineString");
|
||||
|
||||
await measureTool.trigger("click");
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(wrapper.vm.isMeasuring).toBe(false);
|
||||
expect(wrapper.vm.drawType).toBeNull();
|
||||
});
|
||||
|
||||
@@ -45,6 +45,10 @@ vi.mock("ol/Map", () => ({
|
||||
forEachFeatureAtPixel: vi.fn(),
|
||||
setTarget: vi.fn(),
|
||||
updateSize: vi.fn(),
|
||||
getViewport: vi.fn().mockReturnValue({
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn(),
|
||||
}),
|
||||
})),
|
||||
}));
|
||||
|
||||
@@ -63,6 +67,7 @@ vi.mock("ol/source/Vector", () => ({
|
||||
addFeature: vi.fn(),
|
||||
addFeatures: vi.fn(),
|
||||
getFeatures: vi.fn().mockReturnValue([]),
|
||||
on: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/proj", () => ({
|
||||
@@ -75,11 +80,30 @@ vi.mock("ol/control", () => ({
|
||||
vi.mock("ol/interaction/Draw", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
on: vi.fn(),
|
||||
setActive: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/interaction/Modify", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
on: vi.fn(),
|
||||
setActive: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/interaction/Select", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
on: vi.fn(),
|
||||
setActive: vi.fn(),
|
||||
getFeatures: vi.fn().mockReturnValue({
|
||||
getArray: vi.fn().mockReturnValue([]),
|
||||
clear: vi.fn(),
|
||||
push: vi.fn(),
|
||||
}),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/interaction/Translate", () => ({
|
||||
default: vi.fn().mockImplementation(() => ({
|
||||
on: vi.fn(),
|
||||
setActive: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/interaction/Snap", () => ({
|
||||
@@ -106,6 +130,29 @@ vi.mock("ol/format/GeoJSON", () => ({
|
||||
readFeatures: vi.fn().mockReturnValue([]),
|
||||
})),
|
||||
}));
|
||||
vi.mock("ol/style", () => ({
|
||||
Style: vi.fn().mockImplementation(() => ({})),
|
||||
Text: vi.fn().mockImplementation(() => ({})),
|
||||
Fill: vi.fn().mockImplementation(() => ({})),
|
||||
Stroke: vi.fn().mockImplementation(() => ({})),
|
||||
Circle: vi.fn().mockImplementation(() => ({})),
|
||||
Icon: vi.fn().mockImplementation(() => ({})),
|
||||
}));
|
||||
vi.mock("ol/sphere", () => ({
|
||||
getArea: vi.fn(),
|
||||
getLength: vi.fn(),
|
||||
}));
|
||||
vi.mock("ol/geom", () => ({
|
||||
LineString: vi.fn(),
|
||||
Polygon: vi.fn(),
|
||||
Circle: vi.fn(),
|
||||
}));
|
||||
vi.mock("ol/geom/Polygon", () => ({
|
||||
fromCircle: vi.fn(),
|
||||
}));
|
||||
vi.mock("ol/Observable", () => ({
|
||||
unByKey: vi.fn(),
|
||||
}));
|
||||
|
||||
import MapPage from "@/components/map/MapPage.vue";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user