test(FN-4750): complete Step 2 — cover local-only diff keys

Fusion-Task-Id: FN-4750
Fusion-Task-Lineage: 54b3e35f-ef34-469a-aa9f-6d7fe9e79f27
This commit is contained in:
Fusion (runfusion.ai)
2026-05-16 10:13:52 -07:00
committed by gsxdsm
parent 61e14fd230
commit 56b23b271c

View File

@@ -435,6 +435,38 @@ describe("Node settings sync routes", () => {
expect(mockApplyRemoteSettings).not.toHaveBeenCalled();
});
it("manual diff includes local-only keys that are absent from remote", async () => {
const remoteNode = createMockRemoteNode();
mockGetNode.mockResolvedValue(remoteNode);
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({
global: { defaultProvider: "openai" },
project: { maxConcurrent: 3 },
}),
});
vi.spyOn(store, "getSettingsByScope").mockResolvedValue({
global: {},
project: { worktreesDir: "/tmp/wt" },
});
vi.spyOn(store, "getGlobalSettingsStore").mockReturnValue({
getSettings: vi.fn().mockResolvedValue({ defaultModelId: "gpt-5" }),
} as ReturnType<MockStore["getGlobalSettingsStore"]>);
const res = await request(
app,
"POST",
"/api/nodes/node-remote-001/settings/pull",
JSON.stringify({ conflictResolution: "manual" }),
{ "content-type": "application/json" },
);
expect(res.status).toBe(200);
expect(res.body.diff.global).toEqual(expect.arrayContaining(["defaultProvider", "defaultModelId"]));
expect(res.body.diff.project).toEqual(expect.arrayContaining(["maxConcurrent", "worktreesDir"]));
expect(mockApplyRemoteSettings).not.toHaveBeenCalled();
});
it("returns 404 for unknown node", async () => {
mockGetNode.mockResolvedValue(null);
@@ -524,6 +556,54 @@ describe("Node settings sync routes", () => {
expect(res.body.diff.project).toEqual([]);
});
it("diff includes local-only keys when remote reachable", async () => {
const remoteNode = createMockRemoteNode();
mockGetNode.mockResolvedValue(remoteNode);
mockGetSettingsSyncState.mockResolvedValue(null);
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({
global: { defaultProvider: "openai" },
project: { maxConcurrent: 3 },
}),
});
vi.spyOn(store, "getSettingsByScope").mockResolvedValue({
global: {},
project: { worktreesDir: "/tmp/wt" },
});
vi.spyOn(store, "getGlobalSettingsStore").mockReturnValue({
getSettings: vi.fn().mockResolvedValue({ defaultModelId: "gpt-5" }),
} as ReturnType<MockStore["getGlobalSettingsStore"]>);
const res = await get(app, "/api/nodes/node-remote-001/settings/sync-status");
expect(res.status).toBe(200);
expect(res.body.remoteReachable).toBe(true);
expect(res.body.diff.global).toEqual(expect.arrayContaining(["defaultProvider", "defaultModelId"]));
expect(res.body.diff.project).toEqual(expect.arrayContaining(["maxConcurrent", "worktreesDir"]));
});
it("diff stays empty when remote unreachable even if local has unique keys", async () => {
const remoteNode = createMockRemoteNode();
mockGetNode.mockResolvedValue(remoteNode);
mockGetSettingsSyncState.mockResolvedValue(null);
mockFetch.mockRejectedValue(new Error("Network error"));
vi.spyOn(store, "getSettingsByScope").mockResolvedValue({
global: {},
project: { worktreesDir: "/tmp/wt" },
});
vi.spyOn(store, "getGlobalSettingsStore").mockReturnValue({
getSettings: vi.fn().mockResolvedValue({ defaultModelId: "gpt-5" }),
} as ReturnType<MockStore["getGlobalSettingsStore"]>);
const res = await get(app, "/api/nodes/node-remote-001/settings/sync-status");
expect(res.status).toBe(200);
expect(res.body.remoteReachable).toBe(false);
expect(res.body.diff.global).toEqual([]);
expect(res.body.diff.project).toEqual([]);
});
it("returns 404 for unknown node", async () => {
mockGetNode.mockResolvedValue(null);