File size: 2,936 Bytes
f778c12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import { Command } from "commander";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { registerNodesLocationCommands } from "./register.location.js";

const mocks = vi.hoisted(() => ({
  resolveCliNodeId: vi.fn(async () => "node-1"),
  callNodesGatewayCli: vi.fn(async () => ({ payload: { lat: 48.2, lon: 16.3 } })),
}));

vi.mock("./cli-utils.js", () => ({
  runNodesCommand: async (_label: string, action: () => Promise<void>) => action(),
}));

vi.mock("./rpc.js", async () => {
  const actual = await vi.importActual<typeof import("./rpc.js")>("./rpc.js");
  return {
    ...actual,
    resolveCliNodeId: mocks.resolveCliNodeId,
    callNodesGatewayCli: mocks.callNodesGatewayCli,
  };
});

vi.mock("../../gateway/call.js", () => ({
  randomIdempotencyKey: () => "location-test-key",
}));

vi.mock("../../runtime.js", () => ({
  defaultRuntime: {
    writeJson: vi.fn(),
    log: vi.fn(),
  },
}));

function createNodesCommand(): Command {
  const nodes = new Command("nodes");
  registerNodesLocationCommands(nodes);
  return nodes.exitOverride().configureOutput({ writeErr: () => {}, writeOut: () => {} });
}

describe("nodes location get validation", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("rejects unsupported accuracy values before resolving or invoking a node", async () => {
    const nodes = createNodesCommand();

    await expect(
      nodes.parseAsync([
        "node",
        "nodes",
        "location",
        "get",
        "--node",
        "node-1",
        "--accuracy",
        "approximate",
      ]),
    ).rejects.toThrow("invalid --accuracy (use coarse|balanced|precise)");

    expect(mocks.resolveCliNodeId).not.toHaveBeenCalled();
    expect(mocks.callNodesGatewayCli).not.toHaveBeenCalled();
  });

  it("normalizes and forwards supported accuracy values", async () => {
    const nodes = createNodesCommand();

    await nodes.parseAsync([
      "node",
      "nodes",
      "location",
      "get",
      "--node",
      "node-1",
      "--accuracy",
      "PRECISE",
    ]);

    expect(mocks.callNodesGatewayCli).toHaveBeenCalledWith(
      "node.invoke",
      expect.anything(),
      expect.objectContaining({
        params: expect.objectContaining({ desiredAccuracy: "precise" }),
      }),
    );
  });

  it.each(["", " \t "])(
    "rejects explicit blank --location-timeout %j before resolving or invoking a node",
    async (locationTimeout) => {
      const nodes = createNodesCommand();

      await expect(
        nodes.parseAsync([
          "node",
          "nodes",
          "location",
          "get",
          "--node",
          "node-1",
          "--location-timeout",
          locationTimeout,
        ]),
      ).rejects.toThrow("--location-timeout must be a positive integer");

      expect(mocks.resolveCliNodeId).not.toHaveBeenCalled();
      expect(mocks.callNodesGatewayCli).not.toHaveBeenCalled();
    },
  );
});