fix(watcher): close deleted opened documents
This commit is contained in:
114
test/integration/watcher-typescript.test.ts
Normal file
114
test/integration/watcher-typescript.test.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { describe, it, before, after } from "node:test";
|
||||
import * as assert from "node:assert/strict";
|
||||
import * as fs from "node:fs";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import {
|
||||
setTestSocket,
|
||||
stopTestDaemon,
|
||||
runCliJson,
|
||||
requireServer,
|
||||
} from "../helpers.ts";
|
||||
|
||||
const skip = requireServer("typescript-language-server");
|
||||
|
||||
async function pollUntil<T>(
|
||||
fn: () => Promise<T>,
|
||||
predicate: (v: T) => boolean,
|
||||
timeoutMs: number,
|
||||
intervalMs = 250,
|
||||
): Promise<T> {
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
let last: T = await fn();
|
||||
while (Date.now() < deadline) {
|
||||
if (predicate(last)) return last;
|
||||
await new Promise((r) => setTimeout(r, intervalMs));
|
||||
last = await fn();
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
interface DiagResult {
|
||||
[serverId: string]: { diagnostics?: { message: string }[] };
|
||||
}
|
||||
|
||||
describe("watcher: typescript handles deleted opened files", { skip: skip ?? undefined }, () => {
|
||||
let tmpDir: string;
|
||||
let mainFile: string;
|
||||
let helperFile: string;
|
||||
const env = { ...process.env };
|
||||
let cleanup: () => void;
|
||||
|
||||
before(async () => {
|
||||
delete env.NODE_OPTIONS;
|
||||
cleanup = setTestSocket(env);
|
||||
await stopTestDaemon(env);
|
||||
|
||||
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-lsp-ts-watch-"));
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, ".pi-lsp.json"),
|
||||
JSON.stringify({ disable: ["oxlint"] }),
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, "tsconfig.json"),
|
||||
JSON.stringify(
|
||||
{
|
||||
compilerOptions: {
|
||||
target: "ES2022",
|
||||
module: "ESNext",
|
||||
moduleResolution: "Bundler",
|
||||
strict: true,
|
||||
noEmit: true,
|
||||
},
|
||||
include: ["*.ts"],
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
mainFile = path.join(tmpDir, "main.ts");
|
||||
helperFile = path.join(tmpDir, "helper.ts");
|
||||
fs.writeFileSync(
|
||||
mainFile,
|
||||
'import { helper } from "./helper";\n\nconsole.log(helper());\n',
|
||||
);
|
||||
fs.writeFileSync(helperFile, "export function helper(): number {\n return 1;\n}\n");
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await stopTestDaemon(env);
|
||||
cleanup();
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("reports missing module after an opened imported file is deleted", async () => {
|
||||
const initial = (await runCliJson(
|
||||
[mainFile, "diagnostics", '{"timeoutMs":5000}'],
|
||||
env,
|
||||
)) as DiagResult;
|
||||
assert.deepEqual(initial["typescript-language-server"]?.diagnostics ?? [], []);
|
||||
|
||||
await runCliJson([helperFile, "diagnostics", '{"timeoutMs":5000}'], env);
|
||||
fs.rmSync(helperFile);
|
||||
|
||||
const result = await pollUntil(
|
||||
async () =>
|
||||
(await runCliJson(
|
||||
[mainFile, "diagnostics", '{"timeoutMs":3000}'],
|
||||
env,
|
||||
)) as DiagResult,
|
||||
(r) => {
|
||||
const diags = r["typescript-language-server"]?.diagnostics ?? [];
|
||||
return diags.some((d) => d.message.includes("Cannot find module './helper'"));
|
||||
},
|
||||
15000,
|
||||
500,
|
||||
);
|
||||
|
||||
const diags = result["typescript-language-server"]?.diagnostics ?? [];
|
||||
assert.ok(
|
||||
diags.some((d) => d.message.includes("Cannot find module './helper'")),
|
||||
`Expected missing-module diagnostic after deleting opened helper.ts, got: ${JSON.stringify(diags)}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user