Skip to content

Commit 62d8361

Browse files
committed
feat: add installExtension integration test
This adds a new helper function called `runCodeServerCommand` along with a test for `--install-extension`. We can use this approach for writing integration tests (i.e. testing a real code-server build, CLI commands, etc).
1 parent eb314ff commit 62d8361

File tree

3 files changed

+107
-33
lines changed

3 files changed

+107
-33
lines changed

ci/build/test-standalone-release.sh

-33
This file was deleted.
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { clean, tmpdir } from "../utils/helpers"
2+
import { runCodeServerCommand } from "../utils/integration"
3+
4+
describe("--install-extension", () => {
5+
const testName = "installExtension"
6+
let tempDir: string
7+
let setupFlags: string[]
8+
9+
beforeEach(async () => {
10+
await clean(testName)
11+
tempDir = await tmpdir(testName)
12+
setupFlags = ["--extensions-dir", tempDir]
13+
})
14+
it("should install an extension", async () => {
15+
const extName = "wesbos.theme-cobalt2"
16+
await runCodeServerCommand([...setupFlags, "--install-extension", extName], {})
17+
const { stdout } = await runCodeServerCommand([...setupFlags, "--list-extensions"], {
18+
stdout: "log",
19+
})
20+
expect(stdout).toContain(extName)
21+
})
22+
})

test/utils/integration.ts

+85
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { spawn } from "child_process"
12
import { promises as fs } from "fs"
23
import * as path from "path"
34
import { parse, parseConfigFile, setDefaults } from "../../src/node/cli"
@@ -29,3 +30,87 @@ export async function setup(argv: string[], configFile?: string): Promise<httpse
2930

3031
return new httpserver.HttpServer(server)
3132
}
33+
34+
type RunCodeServerCommandOptions = {
35+
stderr?: "log"
36+
stdout?: "log"
37+
ignoreFail?: boolean
38+
}
39+
interface ErrorWithMoreInfo extends Error {
40+
stderr: string
41+
stdout: string
42+
}
43+
44+
type CSCmd =
45+
| {
46+
code: number | null
47+
signal: NodeJS.Signals | null
48+
stdout: string
49+
stderr: string
50+
}
51+
| ErrorWithMoreInfo
52+
53+
/**
54+
*
55+
* A helper function for integration tests to run code-server commands.
56+
*/
57+
export async function runCodeServerCommand(argv: string[], options: RunCodeServerCommandOptions = {}): Promise<CSCmd> {
58+
const CODE_SERVER_COMMAND = process.env.CODE_SERVER_PATH || "/var/tmp/coder/code-server/bin/code-server"
59+
// Credit: https://github.com/vercel/next.js/blob/canary/test/lib/next-test-utils.js#L139
60+
return new Promise((resolve, reject) => {
61+
console.log(`Running command "${CODE_SERVER_COMMAND} ${argv.join(" ")}"`)
62+
const instance = spawn(CODE_SERVER_COMMAND, [...argv])
63+
let mergedStdio = ""
64+
65+
let stderrOutput = ""
66+
if (options.stderr) {
67+
instance.stderr.on("data", function (chunk) {
68+
mergedStdio += chunk
69+
stderrOutput += chunk
70+
71+
if (options.stderr === "log") {
72+
console.log(chunk.toString())
73+
}
74+
})
75+
} else {
76+
instance.stderr.on("data", function (chunk) {
77+
mergedStdio += chunk
78+
})
79+
}
80+
81+
let stdoutOutput = ""
82+
if (options.stdout) {
83+
instance.stdout.on("data", function (chunk) {
84+
mergedStdio += chunk
85+
stdoutOutput += chunk
86+
87+
if (options.stdout === "log") {
88+
console.log(chunk.toString())
89+
}
90+
})
91+
} else {
92+
instance.stdout.on("data", function (chunk) {
93+
mergedStdio += chunk
94+
})
95+
}
96+
97+
instance.on("close", (code, signal) => {
98+
if (!options.stderr && !options.stdout && !options.ignoreFail && code !== 0) {
99+
return reject(new Error(`command failed with code ${code}\n${mergedStdio}`))
100+
}
101+
102+
resolve({
103+
code,
104+
signal,
105+
stdout: stdoutOutput,
106+
stderr: stderrOutput,
107+
})
108+
})
109+
110+
instance.on("error", (err: ErrorWithMoreInfo) => {
111+
err.stdout = stdoutOutput
112+
err.stderr = stderrOutput
113+
reject(err)
114+
})
115+
})
116+
}

0 commit comments

Comments
 (0)