diff --git a/src/tests/lsp.test.ts b/src/tests/lsp.test.ts index e60a893..202c2c2 100644 --- a/src/tests/lsp.test.ts +++ b/src/tests/lsp.test.ts @@ -1,8 +1,20 @@ import { afterAll, beforeAll, expect, test } from "bun:test"; +import { execSync } from "node:child_process"; import { lspManager } from "../lsp/manager"; +// Check if typescript-language-server is available (precompute to avoid async in skipIf) +let tsServerAvailable = false; +try { + execSync("typescript-language-server --version", { stdio: "ignore" }); + tsServerAvailable = true; +} catch { + // Not available +} + // Enable LSP for tests process.env.LETTA_ENABLE_LSP = "true"; +// Disable auto-download to avoid hanging in CI +process.env.LETTA_DISABLE_LSP_DOWNLOAD = "true"; beforeAll(async () => { // Initialize LSP for the project @@ -19,67 +31,76 @@ test("LSP Manager: initializes successfully", () => { expect(true).toBe(true); }); -test("LSP Manager: touchFile opens a TypeScript file", async () => { - const filePath = "./src/lsp/types.ts"; +test.skipIf(!tsServerAvailable)( + "LSP Manager: touchFile opens a TypeScript file", + async () => { + const filePath = "./src/lsp/types.ts"; - // Touch the file (should open it in LSP) - await lspManager.touchFile(filePath, false); + // Touch the file (should open it in LSP) + await lspManager.touchFile(filePath, false); - // Wait for LSP to process - await new Promise((resolve) => setTimeout(resolve, 200)); + // Wait for LSP to process + await new Promise((resolve) => setTimeout(resolve, 200)); - // File should be opened (no error thrown) - expect(true).toBe(true); -}); + // File should be opened (no error thrown) + expect(true).toBe(true); + }, +); -test("LSP Manager: getDiagnostics returns empty for valid file", async () => { - const filePath = "./src/lsp/types.ts"; +test.skipIf(!tsServerAvailable)( + "LSP Manager: getDiagnostics returns empty for valid file", + async () => { + const filePath = "./src/lsp/types.ts"; - // Touch the file - await lspManager.touchFile(filePath, false); + // Touch the file + await lspManager.touchFile(filePath, false); - // Wait for diagnostics - await new Promise((resolve) => setTimeout(resolve, 200)); + // Wait for diagnostics + await new Promise((resolve) => setTimeout(resolve, 200)); - // Get diagnostics - should be empty for a valid file - const diagnostics = lspManager.getDiagnostics(filePath); + // Get diagnostics - should be empty for a valid file + const diagnostics = lspManager.getDiagnostics(filePath); - // types.ts should have no errors - expect(diagnostics.length).toBe(0); -}); + // types.ts should have no errors + expect(diagnostics.length).toBe(0); + }, +); -test("LSP Manager: handles file changes", async () => { - const { promises: fs } = await import("node:fs"); - const testFile = "./test-lsp-file.ts"; +test.skipIf(!tsServerAvailable)( + "LSP Manager: handles file changes", + async () => { + const { promises: fs } = await import("node:fs"); + const testFile = "./test-lsp-file.ts"; - try { - // Create a valid file - await fs.writeFile(testFile, "const x: number = 42;"); - - // Touch file - await lspManager.touchFile(testFile, false); - await new Promise((resolve) => setTimeout(resolve, 300)); - - const diagnostics1 = lspManager.getDiagnostics(testFile); - expect(diagnostics1.length).toBe(0); - - // Modify file with an error - await fs.writeFile(testFile, "const x: number = 'string';"); // Type error! - - // Notify LSP of change - await lspManager.touchFile(testFile, true); - await new Promise((resolve) => setTimeout(resolve, 500)); - - // LSP should process the change (diagnostics may or may not arrive depending on timing) - // Just verify getDiagnostics doesn't crash - const diagnostics2 = lspManager.getDiagnostics(testFile); - expect(diagnostics2).toBeDefined(); - } finally { - // Cleanup try { - await fs.unlink(testFile); - } catch { - // Ignore + // Create a valid file + await fs.writeFile(testFile, "const x: number = 42;"); + + // Touch file + await lspManager.touchFile(testFile, false); + await new Promise((resolve) => setTimeout(resolve, 300)); + + const diagnostics1 = lspManager.getDiagnostics(testFile); + expect(diagnostics1.length).toBe(0); + + // Modify file with an error + await fs.writeFile(testFile, "const x: number = 'string';"); // Type error! + + // Notify LSP of change + await lspManager.touchFile(testFile, true); + await new Promise((resolve) => setTimeout(resolve, 500)); + + // LSP should process the change (diagnostics may or may not arrive depending on timing) + // Just verify getDiagnostics doesn't crash + const diagnostics2 = lspManager.getDiagnostics(testFile); + expect(diagnostics2).toBeDefined(); + } finally { + // Cleanup + try { + await fs.unlink(testFile); + } catch { + // Ignore + } } - } -}); + }, +); diff --git a/src/tests/tools/overflow-integration.test.ts b/src/tests/tools/overflow-integration.test.ts index 1ecaa98..7d817cf 100644 --- a/src/tests/tools/overflow-integration.test.ts +++ b/src/tests/tools/overflow-integration.test.ts @@ -25,9 +25,9 @@ describe("overflow integration tests", () => { // Set USER_CWD for the test process.env.USER_CWD = testWorkingDir; - // Generate a large output (more than 30K characters) + // Generate a large output (more than 30K characters) using node (cross-platform) const command = - 'for i in {1..2000}; do echo "Line $i with some padding text to make it longer"; done'; + "node -e \"for(let i=1;i<=2000;i++) console.log('Line '+i+' with some padding text to make it longer')\""; const result = await bash({ command }); @@ -100,9 +100,9 @@ describe("overflow integration tests", () => { test("shows beginning and end of output", async () => { process.env.USER_CWD = testWorkingDir; - // Generate output with distinctive beginning and end + // Generate output with distinctive beginning and end using node (cross-platform) const command = - 'echo "START_MARKER"; for i in {1..1000}; do echo "Middle line $i"; done; echo "END_MARKER"'; + "node -e \"console.log('START_MARKER'); for(let i=1;i<=1000;i++) console.log('Middle line '+i); console.log('END_MARKER')\""; const result = await bash({ command }); diff --git a/src/tests/tools/overflow.test.ts b/src/tests/tools/overflow.test.ts index f39562d..3c6959d 100644 --- a/src/tests/tools/overflow.test.ts +++ b/src/tests/tools/overflow.test.ts @@ -60,9 +60,12 @@ describe("overflow utilities", () => { test("sanitizes working directory path", () => { const dir = getOverflowDirectory("/path/with spaces/and:colons"); - expect(dir).not.toContain(" "); - expect(dir).not.toContain(":"); - expect(dir).toContain("path_with_spaces_and_colons"); + // The sanitized segment (derived from input path) should have no spaces/colons + // On Windows, the full path contains C:\ so we check the segment, not full path + const sanitizedSegment = "path_with_spaces_and_colons"; + expect(dir).toContain(sanitizedSegment); + expect(sanitizedSegment).not.toContain(" "); + expect(sanitizedSegment).not.toContain(":"); }); });