diff options
-rw-r--r-- | .vscode/launch.json | 36 | ||||
-rw-r--r-- | .vscode/settings.json | 4 | ||||
-rw-r--r-- | .vscode/tasks.json | 41 | ||||
-rw-r--r-- | extension/esbuild.mjs | 4 | ||||
-rw-r--r-- | extension/esbuild.test.mjs | 61 | ||||
-rw-r--r-- | extension/jest.config.js | 4 | ||||
-rw-r--r-- | extension/package.json | 7 | ||||
-rw-r--r-- | extension/src/__mocks__/vscode.ts | 7 | ||||
-rw-r--r-- | extension/src/activation/test/environmentSetup.test.ts | 70 | ||||
-rw-r--r-- | extension/src/continueIdeClient.ts | 4 | ||||
-rw-r--r-- | extension/src/terminal/terminalEmulator.ts | 2 | ||||
-rw-r--r-- | extension/src/test-runner/mochaRunner.ts | 39 | ||||
-rw-r--r-- | extension/src/test-runner/runTestOnVSCodeHost.ts (renamed from extension/src/test/runTest.ts) | 9 | ||||
-rw-r--r-- | extension/src/test-suite/environmentSetup.test.ts | 20 | ||||
-rw-r--r-- | extension/src/test-suite/extension.test.ts (renamed from extension/src/test/suite/extension.test.ts) | 0 | ||||
-rw-r--r-- | extension/src/test-suite/util.test.ts (renamed from extension/src/test/suite/util.test.ts) | 4 | ||||
-rw-r--r-- | extension/src/test/suite/index.ts | 38 | ||||
-rw-r--r-- | extension/tsconfig.json | 18 |
18 files changed, 224 insertions, 144 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index c598750f..75ee1f7a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,6 +11,14 @@ "Server", "Extension (VSCode)" ] + }, + { + "name": "Server + Tests (VSCode)", + "stopAll": true, + "configurations": [ + "Server", + "Tests (VSCode)" + ] } ], "configurations": [ @@ -34,6 +42,7 @@ "request": "launch", "cwd": "${workspaceFolder}/extension", "args": [ + // Pass a directory to manually test in "${workspaceFolder}/extension/manual-testing-sandbox", "--extensionDevelopmentPath=${workspaceFolder}/extension", ], @@ -45,5 +54,32 @@ "CONTINUE_SERVER_URL": "http://localhost:8001" } }, + // Has to be run after starting the server (separately or using the compound configuration) + { + "name": "Tests (VSCode)", + "type": "extensionHost", + "request": "launch", + "cwd": "${workspaceFolder}/extension", + "runtimeExecutable": "${execPath}", + "args": [ + // Pass a directory to run tests in + "${workspaceFolder}/extension/manual-testing-sandbox", + "--extensionDevelopmentPath=${workspaceFolder}/extension", + "--extensionTestsPath=${workspaceFolder}/extension/out/test-runner/mochaRunner" + ], + "outFiles": [ + // Allows setting breakpoints in test suites across the /src folder + "${workspaceFolder}/extension/out/test-suites/**/*.js", + // Allows setting breakpoints in mocha test runner file + "${workspaceFolder}/extension/out/test-runner/**/*.js" + ], + "internalConsoleOptions": "openOnSessionStart", + "preLaunchTask": "vscode-extension:tests:build", + "env": { + "CONTINUE_SERVER_URL": "http://localhost:8001", + // Avoid timing out when stopping on breakpoints during debugging in VSCode + "MOCHA_TIMEOUT": "0", + }, + } ] }
\ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 2195200a..856240e5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "python.defaultInterpreterPath": "${workspaceFolder}/continuedev/.venv/bin/python", -}
\ No newline at end of file + "python.defaultInterpreterPath": "${workspaceFolder}/continuedev/.venv/bin/python3" +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 64e18f28..c15edf0d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,6 +1,7 @@ { "version": "2.0.0", "tasks": [ + // Compile and bundle the extension { "label": "vscode-extension:build", "dependsOn": [ @@ -38,10 +39,9 @@ // This will be useful for preventing debugging if there are compile errors { "label": "vscode-extension:tsc", - "type": "shell", - "command": "echo lol", - // "script": "tsc", - // "path": "extension", + "type": "npm", + "script": "tsc", + "path": "extension", "problemMatcher": [ "$tsc" ], @@ -50,6 +50,39 @@ "clear": true, }, }, + // + // Compile and bundle tests + { + "label": "vscode-extension:tests:build", + "dependsOn": [ + // Build the extension + "vscode-extension:build", + // To detect compile errors - this type checks both the extension and the tests + "vscode-extension:tsc", + "vscode-extension:tests:esbuild" + ], + }, + { + "label": "vscode-extension:tests:esbuild", + "type": "npm", + "script": "build-test", + "path": "extension", + "problemMatcher": [ + { + "pattern": [ + { + "regexp": "> (.*?):([0-9]+):([0-9]+): (warning|error): (.+)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + ] + } + ] + }, + // // Install or update all dependencies for all projects in the monrepo { "label": "install-all-dependencies", diff --git a/extension/esbuild.mjs b/extension/esbuild.mjs index bc1b3e5f..58ea0c28 100644 --- a/extension/esbuild.mjs +++ b/extension/esbuild.mjs @@ -1,5 +1,6 @@ import * as esbuild from "esbuild"; -// esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --format=cjs --platform=node + +// Bundles the extension into one file await esbuild.build({ entryPoints: ["src/extension.ts"], bundle: true, @@ -9,6 +10,7 @@ await esbuild.build({ platform: "node", sourcemap: true, loader: { + // eslint-disable-next-line @typescript-eslint/naming-convention ".node": "file", }, }); diff --git a/extension/esbuild.test.mjs b/extension/esbuild.test.mjs new file mode 100644 index 00000000..fdffd3da --- /dev/null +++ b/extension/esbuild.test.mjs @@ -0,0 +1,61 @@ +import * as esbuild from "esbuild"; +import glob from "glob"; + +/** + * Bundles tests into multiple files, runTestOnVSCodeHost is then run using node runTestOnVSCodeHost.js + * It downloads vscode, starts it and passes test file to run - mochaRunner.js + * mochaRunner.js then runs tests using Mocha class +*/ + +// Bundles script to run tests on VSCode host + mocha runner that will be invoked from within VSCode host +await esbuild.build({ + entryPoints: [ + // Runs mocha runner on VSCode host usig runTests from @vscode/test-electron + "src/test-runner/runTestOnVSCodeHost.ts", + + // Runs the bundled tests using Mocha class + "src/test-runner/mochaRunner.ts", + ], + bundle: true, + outdir: "out/test-runner", + + external: [ + "vscode", + + // Its important to externalize mocha, otherwise mocha seems to be not initialized properly when running tests + // Example warning by esbuild when mocha is not externalized: + // [WARNING] "./reporters/parallel-buffered" should be marked as external for use with "require.resolve" [require-resolve-not-external] + "mocha", + ], + format: "cjs", + platform: "node", + sourcemap: true, + loader: { + // eslint-disable-next-line @typescript-eslint/naming-convention + ".node": "file", + }, +}); + +/** + * Note: Bundling is done to work around import issues, for example with fkill that does not provide cjs module. + * Rather than figuring out a combination of tsconfig.json that would work, I decided to bundle tests instead. + */ +await esbuild.build({ + // Tests can be added anywhere in src folder + entryPoints: glob.sync("src/**/*.test.ts"), + bundle: true, + outdir: "out/test-suites", + external: [ + "vscode", + + // Its important to externalize mocha, otherwise mocha seems to be not initialized properly when running tests + "mocha", + ], + format: "cjs", + platform: "node", + sourcemap: true, + loader: { + // eslint-disable-next-line @typescript-eslint/naming-convention + ".node": "file", + }, +}); diff --git a/extension/jest.config.js b/extension/jest.config.js deleted file mode 100644 index d5393251..00000000 --- a/extension/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - testEnvironment: "node", - preset: "ts-jest", -}; diff --git a/extension/package.json b/extension/package.json index 38aef247..8fc7c315 100644 --- a/extension/package.json +++ b/extension/package.json @@ -192,17 +192,15 @@ "typegen": "node scripts/typegen.js", "clientgen": "rm -rf src/client/ && npx @openapitools/openapi-generator-cli generate -i ../schema/openapi.json -g typescript-fetch -o src/client/ --additional-properties=supportsES6=true,npmVersion=8.19.2,typescriptThreePlus=true", "rebuild": "electron-rebuild -v 19.1.8 node-pty", - "pretest": "npm run tsc && npm run lint", "lint": "eslint src --ext ts", - "test": "node ./out/test/runTest.js", - "jest": "jest --config ./jest.config.js", + "build-test": "tsc && node esbuild.test.mjs", + "test": "npm run build-test && node ./out/test-runner/runTestOnVSCodeHost.js", "package": "npm install && npm run typegen && npm run clientgen && cd react-app && npm install && npm run build && cd .. && mkdir -p ./build && vsce package --out ./build" }, "devDependencies": { "@nestjs/common": "^8.4.7", "@openapitools/openapi-generator-cli": "^2.5.2", "@types/glob": "^8.0.0", - "@types/jest": "^29.5.2", "@types/mocha": "^10.0.1", "@types/node": "16.x", "@types/node-fetch": "^2.6.2", @@ -216,7 +214,6 @@ "esbuild": "^0.17.19", "eslint": "^8.28.0", "glob": "^8.0.3", - "jest": "^29.5.0", "json-schema-to-typescript": "^12.0.0", "mocha": "^10.1.0", "ts-jest": "^29.1.1", diff --git a/extension/src/__mocks__/vscode.ts b/extension/src/__mocks__/vscode.ts deleted file mode 100644 index d415b5a0..00000000 --- a/extension/src/__mocks__/vscode.ts +++ /dev/null @@ -1,7 +0,0 @@ -const vscode = { - window: { - onDidChangeVisibleTextEditors: jest.fn(), - }, -}; - -module.exports = vscode; diff --git a/extension/src/activation/test/environmentSetup.test.ts b/extension/src/activation/test/environmentSetup.test.ts deleted file mode 100644 index ca487416..00000000 --- a/extension/src/activation/test/environmentSetup.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -const child_process = require("child_process"); -import { platform } from "os"; -import { getPythonPipCommands } from "../environmentSetup"; - -jest.mock("os"); -jest.mock("child_process"); - -function mockPythonVersionMappings(mappings: { [pythonCmd: string]: string }) { - (child_process.exec as jest.Mock).mockImplementation( - (command: string, options: any) => { - const pythonCmd = command.split(" ")[0]; - if (pythonCmd in mappings) { - return Promise.resolve([mappings[pythonCmd], ""]); - } else { - return Promise.resolve(["", stubStderr]); - } - } - ); -} - -const stubStderr = - "This is a stub stderr, but will be checked only for existence."; -describe("getPythonPipCommands", () => { - describe("on Windows", () => { - it("should return the correct Python and Pip commands", async () => { - (platform as jest.Mock).mockReturnValue("win32"); - mockPythonVersionMappings({ - python: "Python 3.8.0", - }); - - const [pythonCmd, pipCmd] = await getPythonPipCommands(); - - expect(pythonCmd).toBe("python"); - expect(pipCmd).toBe("pip"); - - jest.restoreAllMocks(); - }); - describe("on MacOS", () => { - (platform as jest.Mock).mockReturnValue("darwin"); - it("should check through all python versions after finding 3.7", async () => { - mockPythonVersionMappings({ - python: "", - python3: "Python 3.7.0", - "python3.11": "Python 3.11.0", - }); - - const [pythonCmd, pipCmd] = await getPythonPipCommands(); - - expect(pythonCmd).toBe("python3.11"); - expect(pipCmd).toBe("pip3.11"); - - jest.restoreAllMocks(); - }); - - it("should use python3 if that maps to valid version", async () => { - mockPythonVersionMappings({ - python: "", - python3: "Python 3.8.0", - }); - - const [pythonCmd, pipCmd] = await getPythonPipCommands(); - - expect(pythonCmd).toBe("python3"); - expect(pipCmd).toBe("pip3"); - - jest.restoreAllMocks(); - }); - }); - }); -}); diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index cb7baaa6..d89093ca 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -12,7 +12,7 @@ import { rejectSuggestionCommand, } from "./suggestions"; import { FileEditWithFullContents } from "../schema/FileEditWithFullContents"; -import fs = require("fs"); +import * as fs from 'fs'; import { WebsocketMessenger } from "./util/messenger"; import { diffManager } from "./diffs"; const os = require("os"); @@ -383,7 +383,7 @@ class IdeProtocolClient { async getUserSecret(key: string) { // Check if secret already exists in VS Code settings (global) let secret = vscode.workspace.getConfiguration("continue").get(key); - if (typeof secret !== "undefined" && secret !== null) return secret; + if (typeof secret !== "undefined" && secret !== null) {return secret;} // If not, ask user for secret secret = await vscode.window.showInputBox({ diff --git a/extension/src/terminal/terminalEmulator.ts b/extension/src/terminal/terminalEmulator.ts index bab59c78..3b90f9f8 100644 --- a/extension/src/terminal/terminalEmulator.ts +++ b/extension/src/terminal/terminalEmulator.ts @@ -1,7 +1,7 @@ /* Terminal emulator - commented because node-pty is causing problems. */ import * as vscode from "vscode"; -import os = require("os"); +import * as os from 'os'; import stripAnsi from "strip-ansi"; import { longestCommonSubsequence } from "../util/lcs"; diff --git a/extension/src/test-runner/mochaRunner.ts b/extension/src/test-runner/mochaRunner.ts new file mode 100644 index 00000000..95fcbc5e --- /dev/null +++ b/extension/src/test-runner/mochaRunner.ts @@ -0,0 +1,39 @@ +import * as path from "path"; +import Mocha from "mocha"; +import * as glob from "glob"; + +export function run() { + // Avoid timing out when stopping on breakpoints during debugging in VSCode + const timeoutOption = process.env.MOCHA_TIMEOUT ? parseInt(process.env.MOCHA_TIMEOUT) : undefined; + + // Create the mocha test + const mocha = new Mocha({ + ui: "tdd", + color: true, + timeout: timeoutOption, + }); + + // See esbuild.test.mjs for more details + // Assumes this file is in out/test-runner/mochaRunner.js + const compiledTestSuitesDirectory = path.resolve(__dirname, "../test-suites"); + + glob.sync("**/**.test.js", { cwd: compiledTestSuitesDirectory }).forEach((file) => { + mocha.addFile(path.resolve(compiledTestSuitesDirectory, file)); + }); + + return new Promise<void>((c, e) => { + try { + // Run the mocha test + mocha.run((failures) => { + if (failures > 0) { + e(new Error(`${failures} tests failed.`)); + } else { + c(); + } + }); + } catch (err) { + console.error(err); + e(err); + } + }); +} diff --git a/extension/src/test/runTest.ts b/extension/src/test-runner/runTestOnVSCodeHost.ts index e810ed5b..2a542ffc 100644 --- a/extension/src/test/runTest.ts +++ b/extension/src/test-runner/runTestOnVSCodeHost.ts @@ -1,21 +1,22 @@ -import * as path from "path"; - import { runTests } from "@vscode/test-electron"; +import * as path from "path"; async function main() { try { // The folder containing the Extension Manifest package.json // Passed to `--extensionDevelopmentPath` + + // Assumes this file is in out/test-runner/runTestOnVSCodeHost.js const extensionDevelopmentPath = path.resolve(__dirname, "../../"); // The path to test runner // Passed to --extensionTestsPath - const extensionTestsPath = path.resolve(__dirname, "./suite/index"); + const extensionTestsPath = path.resolve(extensionDevelopmentPath, "out/test-runner/mochaRunner"); // Download VS Code, unzip it and run the integration test await runTests({ extensionDevelopmentPath, extensionTestsPath }); } catch (err) { - console.error("Failed to run tests"); + console.error("Failed to run tests", err); process.exit(1); } } diff --git a/extension/src/test-suite/environmentSetup.test.ts b/extension/src/test-suite/environmentSetup.test.ts new file mode 100644 index 00000000..9a478522 --- /dev/null +++ b/extension/src/test-suite/environmentSetup.test.ts @@ -0,0 +1,20 @@ +import { test, describe } from "mocha"; +import * as assert from "assert"; + +import { getContinueServerUrl } from "../bridge"; +import { startContinuePythonServer } from "../activation/environmentSetup"; +import fetch from "node-fetch"; + +describe("Can start python server", () => { + test("Can start python server in under 10 seconds", async function () { + this.timeout(17_000); + await startContinuePythonServer(); + + await new Promise((resolve) => setTimeout(resolve, 15_000)); + + // Check if server is running + const serverUrl = getContinueServerUrl(); + const response = await fetch(`${serverUrl}/health`); + assert.equal(response.status, 200); + }); +}); diff --git a/extension/src/test/suite/extension.test.ts b/extension/src/test-suite/extension.test.ts index 890820b2..890820b2 100644 --- a/extension/src/test/suite/extension.test.ts +++ b/extension/src/test-suite/extension.test.ts diff --git a/extension/src/test/suite/util.test.ts b/extension/src/test-suite/util.test.ts index 0ba1473b..2b301b0c 100644 --- a/extension/src/test/suite/util.test.ts +++ b/extension/src/test-suite/util.test.ts @@ -1,6 +1,6 @@ import { test, describe } from "mocha"; -import * as assert from "assert"; -import { convertSingleToDoubleQuoteJSON } from "../../util/util"; +import assert from "assert"; +import { convertSingleToDoubleQuoteJSON } from "../util/util"; describe("utils.ts", () => { test("convertSingleToDoubleQuoteJson", () => { diff --git a/extension/src/test/suite/index.ts b/extension/src/test/suite/index.ts deleted file mode 100644 index 772a0152..00000000 --- a/extension/src/test/suite/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as path from "path"; -import * as Mocha from "mocha"; -import * as glob from "glob"; - -export function run(): Promise<void> { - // Create the mocha test - const mocha = new Mocha({ - ui: "tdd", - color: true, - }); - - const testsRoot = path.resolve(__dirname, ".."); - - return new Promise((c, e) => { - glob("**/**.test.js", { cwd: testsRoot }, (err, files) => { - if (err) { - return e(err); - } - - // Add files to the test suite - files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); - - try { - // Run the mocha test - mocha.run((failures: any) => { - if (failures > 0) { - e(new Error(`${failures} tests failed.`)); - } else { - c(); - } - }); - } catch (err) { - console.error(err); - e(err); - } - }); - }); -} diff --git a/extension/tsconfig.json b/extension/tsconfig.json index 766b21cc..847e53a0 100644 --- a/extension/tsconfig.json +++ b/extension/tsconfig.json @@ -2,8 +2,15 @@ "compilerOptions": { "module": "commonjs", "target": "ES2020", - "outDir": "out", - "lib": ["ES2020", "dom", "es6", "es5", "dom.iterable", "scripthost"], + "outDir": "out/tsc/src", + "lib": [ + "ES2020", + "dom", + "es6", + "es5", + "dom.iterable", + "scripthost" + ], "sourceMap": true, "rootDir": "src", "strict": true /* enable all strict type-checking options */, @@ -11,7 +18,10 @@ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, "resolveJsonModule": true /* Enable importing .json files */ }, - "include": ["src/**/*"] -} + "include": [ + "src/**/*", + ] +}
\ No newline at end of file |