/** * Copyright (c) 2026, Salesforce, Inc., * All rights reserved. * For full license text, see the LICENSE.txt file */ import { describe, expect, it } from "vitest"; import { TEST_SCHEMA, makeSession } from "../../__tests__/helpers/schema.js"; import { captureStdout } from "../../__tests__/helpers/stdout.js"; import { createSession, loadSession, saveSession } from "../../lib/session.js"; import { clearSchemaCache, primeSchemaCache } from "../../lib/walker.js"; import { dispatchQueryCommand, getSessionSchema, resolveDirectoryPathInSession, selectLeafInSession, } from "../query.js"; describe("commands/query", () => { describe("dispatchQueryCommand", () => { it("routes help correctly", async () => { const session = makeSession(); saveSession(session); const output = await captureStdout(async () => { await dispatchQueryCommand(session.id, "help", [], {}); }); expect(output.includes("pwd") || output.includes("select")).toBe(true); }); it("routes unknown commands with an error message", async () => { const session = makeSession(); saveSession(session); await expect(dispatchQueryCommand(session.id, "zzz_unknown", [], {})).rejects.toThrow( /Unknown subcommand/, ); }); it("cd updates session navigation path", async () => { const session = makeSession(); session.navigationPath = []; saveSession(session); await captureStdout(async () => { await dispatchQueryCommand(session.id, "cd", ["query/viewer"], {}); }); const updated = loadSession(session.id); expect(updated.navigationPath).toEqual(["query", "viewer"]); }); it("select adds leaf to projection", async () => { const session = makeSession(); session.navigationPath = ["query", "viewer"]; saveSession(session); await captureStdout(async () => { await dispatchQueryCommand(session.id, "select", ["id"], {}); }); const updated = loadSession(session.id); expect(updated.nodes.some((n) => n.kind === "field" && n.fieldName === "id")).toBe(true); }); }); describe("resolveDirectoryPathInSession (cd)", () => { it("resolves query/ prefix paths", () => { const session = makeSession(); session.navigationPath = ["query"]; const resolved = resolveDirectoryPathInSession(session, "accounts"); expect(resolved).toEqual(["query", "accounts"]); }); it("handles @args navigation", () => { const session = makeSession(); session.navigationPath = ["query", "accounts"]; const resolved = resolveDirectoryPathInSession(session, "@args"); expect(resolved).toEqual(["query", "accounts", "@args"]); }); it("cd into @args input object fields", () => { const session = makeSession(); session.navigationPath = ["query", "accounts", "@args"]; const resolved = resolveDirectoryPathInSession(session, "where"); expect(resolved).toEqual(["query", "accounts", "@args", "where"]); }); it("rejects scalar args as leaf", () => { const session = makeSession(); session.navigationPath = ["query", "accounts", "@args"]; expect(() => resolveDirectoryPathInSession(session, "first")).toThrow( /Cannot cd into "first" — it is a scalar/, ); }); }); describe("selectLeafInSession", () => { it("leaf-only selection rejects non-leaf fields", () => { const session = makeSession(); session.navigationPath = ["query"]; expect(() => selectLeafInSession(session, "viewer")).toThrow(/Cannot select "viewer"/); session.navigationPath = ["query", "viewer"]; selectLeafInSession(session, "id"); }); it("select through union without brackets gives a helpful error", () => { const session = makeSession(); session.navigationPath = ["query", "search"]; expect(() => selectLeafInSession(session, "name")).toThrow( /Use inline fragment syntax: on:Account\/name/, ); }); }); describe("getSessionSchema", () => { it("resolves by session.instanceUrl", () => { clearSchemaCache(); primeSchemaCache("https://o.my.salesforce.com", TEST_SCHEMA); const session = createSession("o", "query", "https://o.my.salesforce.com"); expect(getSessionSchema(session)).toBe(TEST_SCHEMA); }); it("throws when session has no instanceUrl", () => { const session = createSession("o", "query"); expect(() => getSessionSchema(session)).toThrow(/instanceUrl/); }); }); });