- Notifications
You must be signed in to change notification settings - Fork24
Add package scripts and cli library, enable integration testing#536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Changes fromall commits
7e1bce9
c693a46
240b649
0e58a31
872b7e8
01c2d80
8ddbf26
9b74df4
adec211
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
vitest.config.ts |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -18,7 +18,7 @@ jobs: | ||
-uses:actions/setup-node@v4 | ||
with: | ||
node-version:"22" | ||
-run:yarn | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import{defineConfig}from"@vscode/test-cli"; | ||
exportdefaultdefineConfig({ | ||
files:"out/test/**/*.test.js", | ||
extensionDevelopmentPath:".", | ||
extensionTestsPath:"./out/test", | ||
launchArgs:["--enable-proposed-api","coder.coder-remote"], | ||
mocha:{ | ||
ui:"tdd", | ||
timeout:20000, | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -12,4 +12,4 @@ node_modules/** | ||
**/.editorconfig | ||
**/*.map | ||
**/*.ts | ||
*.gif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -21,25 +21,36 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> { | ||
// | ||
// Cursor and VSCode are covered by ms remote, and the only other is windsurf for now | ||
// Means that vscodium is not supported by this for now | ||
constisTestMode= | ||
process.env.NODE_ENV==="test"|| | ||
ctx.extensionMode===vscode.ExtensionMode.Test; | ||
constremoteSSHExtension= | ||
vscode.extensions.getExtension("jeanp413.open-remote-ssh")|| | ||
vscode.extensions.getExtension("codeium.windsurf-remote-openssh")|| | ||
vscode.extensions.getExtension("anysphere.remote-ssh")|| | ||
vscode.extensions.getExtension("ms-vscode-remote.remote-ssh"); | ||
letvscodeProposed:typeofvscode=vscode; | ||
if(!remoteSSHExtension){ | ||
if(!isTestMode){ | ||
vscode.window.showErrorMessage( | ||
"Remote SSH extension not found, cannot activate Coder extension", | ||
); | ||
thrownewError("Remote SSH extension not found"); | ||
} | ||
// In test mode, use regular vscode API | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Nice! I wonder if we can avoid the special testing behavior. Maybe we should always try to activate, but if we are unable to get this special API we skip the remote registration (and possibly log a warning)? Similar to what you already have except we always do it, not just in testing. That would make it nicer for use cases where you have not installed the remote extension yet, for whatever reason, while reducing drift between production and testing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Yeah I suspect this is the kind of behavior we want, so 👍 to logging a warning and handling it gracefully | ||
}else{ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
vscodeProposed=(moduleasany)._load( | ||
"vscode", | ||
{ | ||
filename:remoteSSHExtension.extensionPath, | ||
}, | ||
false, | ||
); | ||
} | ||
constoutput=vscode.window.createOutputChannel("Coder"); | ||
conststorage=newStorage( | ||
@@ -278,7 +289,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> { | ||
// Since the "onResolveRemoteAuthority:ssh-remote" activation event exists | ||
// in package.json we're able to perform actions before the authority is | ||
// resolved by the remote SSH extension. | ||
if(!isTestMode&&vscodeProposed.env.remoteAuthority){ | ||
constremote=newRemote( | ||
vscodeProposed, | ||
storage, | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -6,7 +6,9 @@ import * as fs from "fs/promises"; | ||
import * as jsonc from "jsonc-parser"; | ||
import * as os from "os"; | ||
import * as path from "path"; | ||
// Dynamic import for ESM module | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
let prettyBytes: any; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I know you said this was temporary, just leaving a note here to acknowledge we need to update this and other references before merge. 😄 | ||
import * as semver from "semver"; | ||
import * as vscode from "vscode"; | ||
import { | ||
@@ -841,7 +843,7 @@ export class Remote { | ||
`${sshPid}.json`, | ||
); | ||
const updateStatus =async(network: { | ||
p2p: boolean; | ||
latency: number; | ||
preferred_derp: string; | ||
@@ -850,6 +852,10 @@ export class Remote { | ||
download_bytes_sec: number; | ||
using_coder_connect: boolean; | ||
}) => { | ||
// Load ESM module if not already loaded | ||
if (!prettyBytes) { | ||
prettyBytes = (await import("pretty-bytes")).default; | ||
jaggederest marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
} | ||
let statusText = "$(globe) "; | ||
// Coder Connect doesn't populate any other stats | ||
@@ -910,9 +916,9 @@ export class Remote { | ||
.then((content) => { | ||
return JSON.parse(content); | ||
}) | ||
.then(async(parsed) => { | ||
try { | ||
awaitupdateStatus(parsed); | ||
} catch (ex) { | ||
// Ignore | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -3,7 +3,9 @@ import { createWriteStream } from "fs"; | ||
importfsfrom"fs/promises"; | ||
import{IncomingMessage}from"http"; | ||
importpathfrom"path"; | ||
// Dynamic import for ESM module | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
jaggederest marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
letprettyBytes:any; | ||
import*asvscodefrom"vscode"; | ||
import{errToStr}from"./api-helper"; | ||
import*asclifrom"./cliManager"; | ||
@@ -122,6 +124,10 @@ export class Storage { | ||
* downloads being disabled. | ||
*/ | ||
publicasyncfetchBinary(restClient:Api,label:string):Promise<string>{ | ||
// Load ESM module if not already loaded | ||
if(!prettyBytes){ | ||
prettyBytes=(awaitimport("pretty-bytes")).default; | ||
} | ||
jaggederest marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
constbaseUrl=restClient.getAxiosInstance().defaults.baseURL; | ||
// Settings can be undefined when set to their defaults (true in this case), | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import*asassertfrom"assert"; | ||
import*asvscodefrom"vscode"; | ||
suite("Extension Test Suite",()=>{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Exciting to have this working!! | ||
vscode.window.showInformationMessage("Start all tests."); | ||
test("Extension should be present",()=>{ | ||
assert.ok(vscode.extensions.getExtension("coder.coder-remote")); | ||
}); | ||
test("Extension should activate",async()=>{ | ||
constextension=vscode.extensions.getExtension("coder.coder-remote"); | ||
assert.ok(extension); | ||
if(!extension.isActive){ | ||
awaitextension.activate(); | ||
} | ||
assert.ok(extension.isActive); | ||
}); | ||
test("Extension should export activate function",async()=>{ | ||
constextension=vscode.extensions.getExtension("coder.coder-remote"); | ||
assert.ok(extension); | ||
awaitextension.activate(); | ||
// The extension doesn't export anything, which is fine | ||
// The test was expecting exports.activate but the extension | ||
// itself is the activate function | ||
assert.ok(extension.isActive); | ||
}); | ||
test("Commands should be registered",async()=>{ | ||
constextension=vscode.extensions.getExtension("coder.coder-remote"); | ||
assert.ok(extension); | ||
if(!extension.isActive){ | ||
awaitextension.activate(); | ||
} | ||
// Give a small delay for commands to register | ||
awaitnewPromise((resolve)=>setTimeout(resolve,100)); | ||
constcommands=awaitvscode.commands.getCommands(true); | ||
constcoderCommands=commands.filter((cmd)=>cmd.startsWith("coder.")); | ||
assert.ok( | ||
coderCommands.length>0, | ||
"Should have registered Coder commands", | ||
); | ||
assert.ok( | ||
coderCommands.includes("coder.login"), | ||
"Should have coder.login command", | ||
); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,13 @@ | ||
{ | ||
"compilerOptions": { | ||
"module":"Node16", | ||
"target":"ES2022", | ||
"outDir":"out", | ||
// "dom" is required for importing the API from coder/coder. | ||
"lib": ["ES2022","dom"], | ||
"sourceMap":true, | ||
"strict":true, | ||
"skipLibCheck":true | ||
}, | ||
"exclude": ["vitest.config.ts"] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import{defineConfig}from"vitest/config"; | ||
exportdefaultdefineConfig({ | ||
test:{ | ||
include:["src/**/*.test.ts"], | ||
exclude:[ | ||
"**/node_modules/**", | ||
"**/dist/**", | ||
"**/build/**", | ||
"**/out/**", | ||
"**/src/test/**", | ||
"src/test/**", | ||
"./src/test/**", | ||
], | ||
environment:"node", | ||
}, | ||
}); |
Uh oh!
There was an error while loading.Please reload this page.