import { describe, expect, test } from "bun:test"; import type { PaneTemplateDef } from "../../../../types/plugin"; import { orderListResults, type ResultItem } from "../../list/model"; import { buildRootResultModel, type RootResultModelOptions } from "./results"; function rootOptions(overrides: Partial): RootResultModelOptions { const empty = () => [] as ResultItem[]; return { activeCollectionId: null, activeTickerData: null, activeTickerSymbol: null, assist: null, availableCommands: [], buildLayoutItems: empty, buildPaneSettingItems: empty, buildWindowModeItems: empty, createPaneTemplateItem: () => ({ id: "template", label: "Template", detail: "", category: "Panes", kind: "action", action: () => {}, }), createPluginCommandItem: () => ({ id: "plugin-command", label: "Plugin Command", detail: "", category: "Commands", kind: "command", action: () => {}, }), currentRoute: null, executeCollectionCommand: () => {}, getAvailablePaneShortcutTemplates: () => [], hasPaneSettings: () => false, localTickerSearchResultItems: empty, nonShortcutPaneTemplateItems: empty, openModeRoute: () => {}, paneShortcutItems: empty, pluginCommandItems: empty, pluginCommandResultItems: empty, rootQuery: "", rootShortcutIntent: { kind: "none" }, runDirectCommand: () => {}, runSecurityDescriptionShortcut: () => {}, state: { config: { watchlists: [], portfolios: [] }, focusedPaneId: null, } as unknown as RootResultModelOptions["state"], tickerActionItems: empty, ...overrides, }; } const paneRow: ResultItem = { id: "pane-template:margin-monitor", label: "Margin Monitor", detail: "Track account margin", category: "Panes", kind: "action", action: () => {}, }; const documentRow: ResultItem = { id: "search-provider:research-search:documents:hit-1", label: "Q3 earnings call", detail: "CALL", category: "Documents", kind: "action", lines: [{ segments: [{ text: "margin pressure", emphasis: "match" }] }], action: () => {}, }; describe("provider rows in the root result model", () => { test("land after the local matches instead of displacing them", () => { const { items } = buildRootResultModel(rootOptions({ rootQuery: "margin", paneShortcutItems: () => [paneRow], providerResultItems: [documentRow], })); expect(orderListResults(items).map((item) => item.id)).toEqual([paneRow.id, documentRow.id]); }); test("leave the local matches alone when a provider contributes nothing", () => { const { items } = buildRootResultModel(rootOptions({ rootQuery: "margin", paneShortcutItems: () => [paneRow], providerResultItems: [], })); expect(items.map((item) => item.id)).toEqual([paneRow.id]); }); test("stay out of the way once a prefix claims the query", () => { const { items } = buildRootResultModel(rootOptions({ rootQuery: "SEC AAPL", providerResultItems: [documentRow], rootShortcutIntent: { kind: "complete", source: "pane-template", prefix: "SEC", label: "SEC", description: "", argKind: "ticker", argText: "AAPL", completionQuery: null, template: { id: "sec-pane" } as unknown as PaneTemplateDef, }, })); expect(items.map((item) => item.id)).not.toContain(documentRow.id); }); }); describe("assist rows in the root result model", () => { const assist = { enabled: true, auto: true, state: { status: "idle" as const }, onAsk: () => {}, onSignUp: () => {}, onRunCandidate: () => {}, }; test("lead the list ahead of provider rows and keep the Thinking placeholder", () => { const { items } = buildRootResultModel(rootOptions({ rootQuery: "margin", assist, paneShortcutItems: () => [paneRow], providerResultItems: [documentRow], })); expect(orderListResults(items, { categoryPriorities: new Map([["Documents", 200]]) }).map((item) => item.id)) .toEqual(["assist:pending", paneRow.id, documentRow.id]); }); test("the local matcher no longer drags in panes whose keywords scatter the letters", () => { const optionsRow: ResultItem = { id: "pane-template:options-calculator", label: "Options Calculator", detail: "Price options with the Black-Scholes model and view the Greeks", searchText: "options greeks implied volatility derivatives pricing", category: "Panes", kind: "action", action: () => {}, }; const { items } = buildRootResultModel(rootOptions({ rootQuery: "nvidia", paneShortcutItems: () => [optionsRow], })); expect(items).toEqual([]); const { items: abbreviated } = buildRootResultModel(rootOptions({ rootQuery: "opt calc", paneShortcutItems: () => [optionsRow], })); expect(abbreviated.map((item) => item.id)).toEqual([optionsRow.id]); }); });