- Remove legacy dashboard Capacitor config, scripts, and package dependencies now managed by @fusion/mobile - Rewrite network, splash-screen, and status-bar plugin managers to use guarded global Capacitor plugin adapters without direct @capacitor imports - Update plugin tests to stub Capacitor globals and drop obsolete capacitor config test coverage - Simplify dashboard mobile README guidance and add a @gsxdsm/fusion patch changeset documenting the migration
163 lines
4.9 KiB
TypeScript
163 lines
4.9 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { NetworkManager } from "../plugins/network.js";
|
|
|
|
const getStatusMock = vi.fn();
|
|
const addListenerMock = vi.fn();
|
|
const removeListenerMock = vi.fn();
|
|
|
|
let networkStatusChangeHandler:
|
|
| ((status: { connected: boolean; connectionType: "wifi" | "cellular" | "none" | "unknown" }) => void)
|
|
| null = null;
|
|
|
|
describe("NetworkManager", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
networkStatusChangeHandler = null;
|
|
|
|
getStatusMock.mockResolvedValue({
|
|
connected: true,
|
|
connectionType: "wifi",
|
|
});
|
|
|
|
removeListenerMock.mockResolvedValue(undefined);
|
|
|
|
addListenerMock.mockImplementation(async (
|
|
eventName: string,
|
|
callback: (status: { connected: boolean; connectionType: "wifi" | "cellular" | "none" | "unknown" }) => void,
|
|
) => {
|
|
if (eventName === "networkStatusChange") {
|
|
networkStatusChangeHandler = callback;
|
|
}
|
|
return { remove: removeListenerMock };
|
|
});
|
|
|
|
vi.stubGlobal("Capacitor", {
|
|
Plugins: {
|
|
Network: {
|
|
getStatus: getStatusMock,
|
|
addListener: addListenerMock,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
it("initialize() queries current network status", async () => {
|
|
const manager = new NetworkManager();
|
|
|
|
await manager.initialize();
|
|
|
|
expect(getStatusMock).toHaveBeenCalledTimes(1);
|
|
expect(manager.getStatus()).toEqual({ connected: true, connectionType: "wifi" });
|
|
});
|
|
|
|
it("startMonitoring() registers network listener", async () => {
|
|
const manager = new NetworkManager();
|
|
|
|
await manager.startMonitoring();
|
|
|
|
expect(addListenerMock).toHaveBeenCalledTimes(1);
|
|
expect(addListenerMock).toHaveBeenCalledWith("networkStatusChange", expect.any(Function));
|
|
expect(manager.isMonitoring).toBe(true);
|
|
});
|
|
|
|
it("status change callback fires on network change", async () => {
|
|
const manager = new NetworkManager();
|
|
const callback = vi.fn();
|
|
|
|
manager.onStatusChange(callback);
|
|
await manager.initialize();
|
|
|
|
networkStatusChangeHandler?.({ connected: false, connectionType: "none" });
|
|
|
|
expect(callback).toHaveBeenCalled();
|
|
expect(callback).toHaveBeenLastCalledWith({ connected: false, connectionType: "none" });
|
|
});
|
|
|
|
it("going offline triggers callback with connected=false", async () => {
|
|
const manager = new NetworkManager();
|
|
const callback = vi.fn();
|
|
|
|
manager.onStatusChange(callback);
|
|
await manager.initialize();
|
|
|
|
networkStatusChangeHandler?.({ connected: false, connectionType: "none" });
|
|
|
|
expect(callback).toHaveBeenCalledWith({ connected: false, connectionType: "none" });
|
|
expect(manager.isOnline).toBe(false);
|
|
});
|
|
|
|
it("going online triggers callback with connected=true", async () => {
|
|
getStatusMock.mockResolvedValue({ connected: false, connectionType: "none" });
|
|
const manager = new NetworkManager();
|
|
const callback = vi.fn();
|
|
|
|
manager.onStatusChange(callback);
|
|
await manager.initialize();
|
|
|
|
networkStatusChangeHandler?.({ connected: true, connectionType: "wifi" });
|
|
|
|
expect(callback).toHaveBeenCalledWith({ connected: true, connectionType: "wifi" });
|
|
expect(manager.isOnline).toBe(true);
|
|
});
|
|
|
|
it("stopMonitoring() removes listener handle", async () => {
|
|
const manager = new NetworkManager();
|
|
|
|
await manager.initialize();
|
|
await manager.stopMonitoring();
|
|
|
|
expect(removeListenerMock).toHaveBeenCalledTimes(1);
|
|
expect(manager.isMonitoring).toBe(false);
|
|
});
|
|
|
|
it("getStatus() returns copy (not reference)", async () => {
|
|
const manager = new NetworkManager();
|
|
|
|
await manager.initialize();
|
|
|
|
const status = manager.getStatus();
|
|
status.connected = false;
|
|
status.connectionType = "none";
|
|
|
|
expect(manager.getStatus()).toEqual({ connected: true, connectionType: "wifi" });
|
|
});
|
|
|
|
it("onStatusChange unsubscribe works", async () => {
|
|
const manager = new NetworkManager();
|
|
const callback = vi.fn();
|
|
|
|
const unsubscribe = manager.onStatusChange(callback);
|
|
await manager.initialize();
|
|
unsubscribe();
|
|
|
|
networkStatusChangeHandler?.({ connected: false, connectionType: "none" });
|
|
|
|
expect(callback).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("initialize() swallows errors", async () => {
|
|
getStatusMock.mockRejectedValue(new Error("network unavailable"));
|
|
const manager = new NetworkManager();
|
|
|
|
await expect(manager.initialize()).resolves.toBeUndefined();
|
|
|
|
expect(manager.getStatus()).toEqual({ connected: true, connectionType: "unknown" });
|
|
});
|
|
|
|
it("destroy() stops monitoring and clears listeners", async () => {
|
|
const manager = new NetworkManager();
|
|
const callback = vi.fn();
|
|
|
|
manager.onStatusChange(callback);
|
|
await manager.initialize();
|
|
await manager.destroy();
|
|
|
|
networkStatusChangeHandler?.({ connected: false, connectionType: "none" });
|
|
|
|
expect(removeListenerMock).toHaveBeenCalledTimes(1);
|
|
expect(callback).not.toHaveBeenCalled();
|
|
expect(manager.isMonitoring).toBe(false);
|
|
expect(manager.isInitialized).toBe(false);
|
|
});
|
|
});
|