Files
MeshChatX/tests/frontend/Interface.test.js
Sudo-Ivan f776bad9c4 Add unit tests for various frontend components
- Introduced new test files for BlockedPage, DropDownMenu, and Interface components to ensure proper rendering and functionality.
- Enhanced existing tests for ConfirmDialog, MessagesSidebar, and NotificationBell, improving coverage and verifying UI behavior.
- Added performance tests for LoadTimePerformance to measure loading times for large datasets in the PropagationNodesPage and MessagesSidebar.
- Removed the deprecated InterfacesPage test file to streamline the test suite.
2026-02-17 17:48:40 -06:00

132 lines
4.9 KiB
JavaScript

import { mount } from "@vue/test-utils";
import { describe, it, expect, vi, beforeEach } from "vitest";
import Interface from "../../meshchatx/src/frontend/components/interfaces/Interface.vue";
vi.mock("../../meshchatx/src/frontend/js/DialogUtils", () => ({
default: { alert: vi.fn() },
}));
const defaultIface = {
_name: "Default Interface",
type: "AutoInterface",
enabled: true,
discoverable: true,
};
function mountInterface(props = {}, options = {}) {
return mount(Interface, {
props: { iface: { ...defaultIface, ...props }, isReticulumRunning: true },
global: {
mocks: { $t: (key) => key },
stubs: ["MaterialDesignIcon", "IconButton", "DropDownMenu", "DropDownMenuItem"],
},
...options,
});
}
describe("Interface.vue", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("renders interface name and type", () => {
const wrapper = mountInterface();
expect(wrapper.text()).toContain("Default Interface");
expect(wrapper.text()).toContain("AutoInterface");
});
it("emits disable when Disable button is clicked", async () => {
const wrapper = mountInterface();
const disableBtn = wrapper.find("button.secondary-chip");
await disableBtn.trigger("click");
expect(wrapper.emitted("disable")).toHaveLength(1);
});
it("emits enable when Enable button is clicked for disabled interface", async () => {
const wrapper = mountInterface({ enabled: false });
const enableBtn = wrapper.find("button.primary-chip");
await enableBtn.trigger("click");
expect(wrapper.emitted("enable")).toHaveLength(1);
});
it("has overflow containment classes on card and content", () => {
const wrapper = mountInterface();
const card = wrapper.find(".interface-card");
expect(card.classes()).toContain("min-w-0");
const contentArea = wrapper.find(".min-w-0.overflow-hidden");
expect(contentArea.exists()).toBe(true);
});
it("has break-words on description for long host:port", () => {
const wrapper = mountInterface({
_name: "RNS Testnet Amsterdam",
type: "TCPClientInterface",
target_host: "amsterdam.connect.reticulum.network",
target_port: 4965,
});
const desc = wrapper.find(".text-sm.text-gray-600");
expect(desc.classes()).toContain("break-words");
expect(desc.classes()).toContain("min-w-0");
});
it("has responsive layout classes for stacking on small screens", () => {
const wrapper = mountInterface();
const outer = wrapper.find(".flex.flex-col.sm\\:flex-row");
expect(outer.exists()).toBe(true);
});
it("renders without overflow when given very long name and description", () => {
const longName = "A".repeat(120);
const wrapper = mountInterface({
_name: longName,
type: "TCPClientInterface",
target_host: "very-long-hostname-that-could-overflow-on-mobile.example.reticulum.network",
target_port: 4242,
});
const card = wrapper.find(".interface-card");
expect(card.exists()).toBe(true);
const contentWrapper = wrapper.find(".flex-1.min-w-0.space-y-2");
expect(contentWrapper.exists()).toBe(true);
const nameEl = wrapper.find(".truncate.min-w-0");
expect(nameEl.exists()).toBe(true);
});
it("action buttons and dropdown have shrink-0 to prevent squashing", () => {
const wrapper = mountInterface();
const actionsCol = wrapper.find(".flex.flex-col.sm\\:flex-row.gap-2");
expect(actionsCol.classes()).toContain("sm:shrink-0");
const btn = wrapper.find("button.secondary-chip");
expect(btn.classes()).toContain("shrink-0");
});
it("detail-value has break-all for long addresses", () => {
const wrapper = mountInterface({
_name: "UDP Test",
type: "UDPInterface",
listen_ip: "0.0.0.0",
listen_port: 4242,
forward_ip: "192.168.1.100",
forward_port: 4242,
});
const detailValues = wrapper.findAll(".detail-value");
expect(detailValues.length).toBeGreaterThan(0);
detailValues.forEach((el) => {
expect(el.classes()).toContain("break-all");
expect(el.classes()).toContain("min-w-0");
});
});
});
describe("Interface.vue overflow at different viewports", () => {
it("card has min-w-0 so it can shrink in grid", () => {
const wrapper = mountInterface();
expect(wrapper.find(".interface-card").classes()).toContain("min-w-0");
});
it("icon and chips have shrink-0 so they do not collapse", () => {
const wrapper = mountInterface();
expect(wrapper.find(".interface-card__icon").classes()).toContain("shrink-0");
expect(wrapper.find(".type-chip").classes()).toContain("shrink-0");
});
});