mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 08:52:12 +00:00
applyCodeAction now resolves the picked action and executes it (lspResolveCodeAction → lspExecuteCodeAction) instead of calling lspApplyCodeAction, but refactorThis.test.ts and runKind.test.ts still mocked and asserted the old command, so main's frontend tests failed (4 tests). The mocks now follow the new commands; safeDelete.test.ts's negative assertion still holds. Co-authored-by: a-rookie-of-C-language <[email protected]>
88 lines
3.2 KiB
TypeScript
88 lines
3.2 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { EditorState } from "@codemirror/state";
|
|
import { EditorView } from "@codemirror/view";
|
|
import type { CodeAction } from "@/bindings";
|
|
|
|
let answer: () => unknown = () => ({ status: "ok", data: [] });
|
|
const lspCodeActions = vi.fn(async () => answer());
|
|
// applyCodeAction resolves the picked action, then executes it (interactive command support).
|
|
const lspResolveCodeAction = vi.fn(async (_doc: number, action: CodeAction) => ({ status: "ok", data: action }));
|
|
const lspExecuteCodeAction = vi.fn(async () => ({ status: "ok", data: [] }));
|
|
|
|
vi.mock("@/platform/ipc", async (orig) => {
|
|
const actual = await orig<typeof import("@/platform/ipc")>();
|
|
return {
|
|
...actual,
|
|
isTauri: () => true,
|
|
commands: { ...actual.commands, lspCodeActions, lspResolveCodeAction, lspExecuteCodeAction },
|
|
};
|
|
});
|
|
const showHint = vi.fn();
|
|
vi.mock("@/editor/lsp/hint", () => ({ showHint }));
|
|
|
|
const { runKindAction } = await import("@/editor/lsp/intentions");
|
|
const { lspDoc } = await import("@/editor/lsp/lsp");
|
|
|
|
const action = (title: string, disabledReason: string | null = null): CodeAction => ({
|
|
title,
|
|
kind: "refactor.extract.constant",
|
|
isPreferred: false,
|
|
disabledReason,
|
|
edit: null,
|
|
command: null,
|
|
data: null,
|
|
server: 1,
|
|
});
|
|
|
|
let view: EditorView | null = null;
|
|
afterEach(() => {
|
|
view?.destroy();
|
|
showHint.mockClear();
|
|
lspResolveCodeAction.mockClear();
|
|
lspExecuteCodeAction.mockClear();
|
|
});
|
|
|
|
function run(fallback: (reason: "notReady" | "error" | "empty") => Promise<boolean>) {
|
|
view = new EditorView({
|
|
state: EditorState.create({
|
|
doc: "const a = 1;",
|
|
extensions: [lspDoc.of({ doc: 1, path: "/a.ts", language: "typescript", uiMode: null, readOnly: false })],
|
|
}),
|
|
});
|
|
return runKindAction(view, "refactor.extract", {
|
|
title: /constant/i,
|
|
none: "Nothing",
|
|
label: "Introduce Constant",
|
|
fallback,
|
|
});
|
|
}
|
|
|
|
describe("runKindAction fallback", () => {
|
|
it("uses the server's action when there is one", async () => {
|
|
answer = () => ({ status: "ok", data: [action("Extract to constant")] });
|
|
const fallback = vi.fn(async () => true);
|
|
await run(fallback);
|
|
expect(fallback).not.toHaveBeenCalled();
|
|
expect(lspExecuteCodeAction).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
it("falls back when the server is not ready or fails", async () => {
|
|
answer = () => ({ status: "error", error: { kind: "unavailable", message: "no server" } });
|
|
const fallback = vi.fn(async () => true);
|
|
await run(fallback);
|
|
expect(fallback).toHaveBeenCalledWith("notReady");
|
|
answer = () => ({ status: "error", error: { kind: "protocol", message: "boom" } });
|
|
await run(fallback);
|
|
expect(fallback).toHaveBeenLastCalledWith("error");
|
|
expect(showHint).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("asks the fallback on an empty answer and keeps the server's reason when it declines", async () => {
|
|
answer = () => ({ status: "ok", data: [action("Extract to constant", "Cannot extract empty range")] });
|
|
const fallback = vi.fn(async () => false);
|
|
await run(fallback);
|
|
expect(fallback).toHaveBeenCalledWith("empty");
|
|
expect(showHint).toHaveBeenCalledWith(expect.anything(), "Cannot extract empty range");
|
|
});
|
|
});
|