Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit fa548e9

Browse files
authoredJan 26, 2021
Merge pull request #2564 from cdr/issue-2550-migrate-mocha-jest
refactor(tests): migrate from mocha to jest
2 parents c52198f + 102f51c commit fa548e9

File tree

20 files changed

+4036
-609
lines changed

20 files changed

+4036
-609
lines changed
 

‎.eslintrc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ parser: "@typescript-eslint/parser"
22
env:
33
browser: true
44
es6: true # Map, etc.
5-
mocha: true
5+
jest: true
66
node: true
77

88
parserOptions:

‎.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ node-*
1414
/plugins
1515
/lib/coder-cloud-agent
1616
.home
17+
coverage

‎README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# code-server · [!["GitHub Discussions"](https://img.shields.io/badge/%20GitHub-%20Discussions-gray.svg?longCache=true&logo=github&colorB=purple)](https://github.com/cdr/code-server/discussions) [!["Join us on Slack"](https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen)](https://cdr.co/join-community) [![Twitter Follow](https://img.shields.io/twitter/follow/CoderHQ?label=%40CoderHQ&style=social)](https://twitter.com/coderhq)
22

3+
![Lines](https://img.shields.io/badge/Coverage-46.71%25-green.svg)
4+
35
Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and access it in the browser.
46

57
![Screenshot](./doc/assets/screenshot.png)

‎ci/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Make sure you have `$GITHUB_TOKEN` set and [hub](https://github.com/github/hub)
2121
- Remember to update the chart version as well on top of appVersion in `Chart.yaml`.
2222
- Run `rg -g '!yarn.lock' -g '!*.svg' '3\.7\.5'` to ensure all values have been
2323
changed. Replace the numbers as needed.
24+
4. Update the code coverage badge (see [here](#updating-code-coverage-in-readme) for instructions)
2425
2. GitHub actions will generate the `npm-package`, `release-packages` and `release-images` artifacts.
2526
1. You do not have to wait for these.
2627
3. Run `yarn release:github-draft` to create a GitHub draft release from the template with
@@ -43,6 +44,19 @@ Make sure you have `$GITHUB_TOKEN` set and [hub](https://github.com/github/hub)
4344
11. Update the homebrew package.
4445
- Send a pull request to [homebrew-core](https://github.com/Homebrew/homebrew-core) with the URL in the [formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/code-server.rb) updated.
4546

47+
## Updating Code Coverage in README
48+
49+
Currently, we run a command to manually generate the code coverage shield. Follow these steps:
50+
51+
1. Run `yarn badges`
52+
2. Go into the README and change the color from `red` to `green` in this line:
53+
54+
```
55+
![Lines](https://img.shields.io/badge/Coverage-46.71%25-red.svg)
56+
```
57+
58+
NOTE: we have to manually change the color because the default is red if coverage is less than 80. See code [here](https://github.com/olavoparno/istanbul-badges-readme/blob/develop/src/editor.ts#L24-L33).
59+
4660
## dev
4761

4862
This directory contains scripts used for the development of code-server.

‎ci/dev/postinstall.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ main() {
55
cd "$(dirname "$0")/../.."
66
source ./ci/lib.sh
77

8+
# This installs the dependencies needed for testing
9+
cd test
10+
yarn
11+
cd ..
12+
813
cd lib/vscode
914
yarn ${CI+--frozen-lockfile}
1015

‎ci/dev/test.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ set -euo pipefail
33

44
main() {
55
cd "$(dirname "$0")/../.."
6-
76
cd test/test-plugin
87
make -s out/index.js
8+
# We must keep jest in a sub-directory. See ../../test/package.json for more
9+
# information. We must also run it from the root otherwise coverage will not
10+
# include our source files.
911
cd "$OLDPWD"
10-
mocha -r ts-node/register ./test/*.test.ts "$@"
12+
./test/node_modules/.bin/jest "$@"
1113
}
1214

1315
main "$@"

‎lib/vscode/extensions/typescript-language-features/src/utils/platform.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
import * as vscode from 'vscode';
77

88
export function isWeb(): boolean {
9-
// NOTE@coder: Remove unused ts-expect-error directive which causes tsc to error.
9+
// @ts-expect-error
1010
return typeof navigator !== 'undefined' && vscode.env.uiKind === vscode.UIKind.Web;
1111
}

‎package.json

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"test": "./ci/dev/test.sh",
2727
"ci": "./ci/dev/ci.sh",
2828
"watch": "VSCODE_IPC_HOOK_CLI= NODE_OPTIONS=--max_old_space_size=32384 ts-node ./ci/dev/watch.ts",
29-
"icons": "./ci/dev/gen_icons.sh"
29+
"icons": "./ci/dev/gen_icons.sh",
30+
"badges": "istanbul-badges-readme"
3031
},
3132
"main": "out/node/entry.js",
3233
"devDependencies": {
@@ -36,9 +37,7 @@
3637
"@types/fs-extra": "^8.0.1",
3738
"@types/http-proxy": "^1.17.4",
3839
"@types/js-yaml": "^3.12.3",
39-
"@types/mocha": "^8.0.3",
4040
"@types/node": "^12.12.7",
41-
"@types/node-fetch": "^2.5.7",
4241
"@types/parcel-bundler": "^1.12.1",
4342
"@types/pem": "^1.9.5",
4443
"@types/proxy-from-env": "^1.0.1",
@@ -55,14 +54,14 @@
5554
"eslint-config-prettier": "^6.0.0",
5655
"eslint-plugin-import": "^2.18.2",
5756
"eslint-plugin-prettier": "^3.1.0",
57+
"istanbul-badges-readme": "^1.2.0",
5858
"leaked-handles": "^5.2.0",
59-
"mocha": "^8.1.2",
6059
"parcel-bundler": "^1.12.4",
6160
"prettier": "^2.0.5",
6261
"stylelint": "^13.0.0",
6362
"stylelint-config-recommended": "^3.0.0",
6463
"ts-node": "^9.0.0",
65-
"typescript": "4.0.2"
64+
"typescript": "^4.1.3"
6665
},
6766
"resolutions": {
6867
"@types/node": "^12.12.7",
@@ -109,5 +108,34 @@
109108
],
110109
"engines": {
111110
"node": ">= 12"
111+
},
112+
"jest": {
113+
"transform": {
114+
"^.+\\.ts$": "<rootDir>/test/node_modules/ts-jest"
115+
},
116+
"testEnvironment": "node",
117+
"testPathIgnorePatterns": [
118+
"node_modules",
119+
"lib",
120+
"out"
121+
],
122+
"collectCoverage": true,
123+
"collectCoverageFrom": [
124+
"<rootDir>/src/**/*.ts"
125+
],
126+
"coverageDirectory": "<rootDir>/coverage",
127+
"coverageReporters": [
128+
"json",
129+
"json-summary",
130+
"text"
131+
],
132+
"coveragePathIgnorePatterns": [
133+
"out"
134+
],
135+
"coverageThreshold": {
136+
"global": {
137+
"lines": 40
138+
}
139+
}
112140
}
113141
}

‎src/node/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const createApp = async (args: DefaultedArgs): Promise<[Express, Express,
2424
: http.createServer(app)
2525

2626
let resolved = false
27-
await new Promise<http.Server>(async (resolve2, reject) => {
27+
await new Promise<void>(async (resolve2, reject) => {
2828
const resolve = () => {
2929
resolved = true
3030
resolve2()

‎src/node/util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ export const open = async (url: string): Promise<void> => {
187187
url = url.replace(/&/g, "^&")
188188
}
189189
const proc = cp.spawn(command, [...args, url], options)
190-
await new Promise((resolve, reject) => {
190+
await new Promise<void>((resolve, reject) => {
191191
proc.on("error", reject)
192192
proc.on("close", (code) => {
193193
return code !== 0 ? reject(new Error(`Failed to open with code ${code}`)) : resolve()

‎test/cli.test.ts

Lines changed: 99 additions & 89 deletions
Large diffs are not rendered by default.

‎test/package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"#": "We must put jest in a sub-directory otherwise VS Code somehow picks up",
3+
"#": "the types and generates conflicts with mocha.",
4+
"devDependencies": {
5+
"@types/jest": "^26.0.20",
6+
"@types/node-fetch": "^2.5.8",
7+
"@types/supertest": "^2.0.10",
8+
"jest": "^26.6.3",
9+
"node-fetch": "^2.6.1",
10+
"supertest": "^6.1.1",
11+
"ts-jest": "^26.4.4"
12+
}
13+
}

‎test/plugin.test.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { logger } from "@coder/logger"
2-
import * as assert from "assert"
32
import * as express from "express"
43
import * as fs from "fs"
5-
import { describe } from "mocha"
64
import * as path from "path"
75
import { PluginAPI } from "../src/node/plugin"
86
import * as apps from "../src/node/routes/apps"
@@ -16,7 +14,7 @@ describe("plugin", () => {
1614
let papi: PluginAPI
1715
let s: httpserver.HttpServer
1816

19-
before(async () => {
17+
beforeAll(async () => {
2018
papi = new PluginAPI(logger, `${path.resolve(__dirname, "test-plugin")}:meow`)
2119
await papi.loadPlugins()
2220

@@ -28,16 +26,16 @@ describe("plugin", () => {
2826
await s.listen(app)
2927
})
3028

31-
after(async () => {
29+
afterAll(async () => {
3230
await s.close()
3331
})
3432

3533
it("/api/applications", async () => {
3634
const resp = await s.fetch("/api/applications")
37-
assert.equal(200, resp.status)
35+
expect(resp.status).toBe(200)
3836
const body = await resp.json()
3937
logger.debug(`${JSON.stringify(body)}`)
40-
assert.deepEqual(body, [
38+
expect(body).toStrictEqual([
4139
{
4240
name: "Test App",
4341
version: "4.0.0",
@@ -66,8 +64,8 @@ describe("plugin", () => {
6664
encoding: "utf8",
6765
})
6866
const resp = await s.fetch("/test-plugin/test-app")
69-
assert.equal(200, resp.status)
67+
expect(resp.status).toBe(200)
7068
const body = await resp.text()
71-
assert.equal(body, indexHTML)
69+
expect(body).toBe(indexHTML)
7270
})
7371
})

‎test/proxy.test.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as assert from "assert"
21
import * as express from "express"
32
import * as httpserver from "./httpserver"
43
import * as integration from "./integration"
@@ -8,7 +7,7 @@ describe("proxy", () => {
87
const nhooyrDevServer = new httpserver.HttpServer()
98
let proxyPath: string
109

11-
before(async () => {
10+
beforeAll(async () => {
1211
const e = express.default()
1312
await nhooyrDevServer.listen(e)
1413
e.get("/wsup", (req, res) => {
@@ -20,7 +19,7 @@ describe("proxy", () => {
2019
})
2120
})
2221

23-
after(async () => {
22+
afterAll(async () => {
2423
await nhooyrDevServer.close()
2524
})
2625

@@ -34,14 +33,16 @@ describe("proxy", () => {
3433
it("should rewrite the base path", async () => {
3534
;[, , codeServer] = await integration.setup(["--auth=none"], "")
3635
const resp = await codeServer.fetch(proxyPath)
37-
assert.equal(resp.status, 200)
38-
assert.equal(await resp.json(), "asher is the best")
36+
expect(resp.status).toBe(200)
37+
const json = await resp.json()
38+
expect(json).toBe("asher is the best")
3939
})
4040

4141
it("should not rewrite the base path", async () => {
4242
;[, , codeServer] = await integration.setup(["--auth=none", "--proxy-path-passthrough=true"], "")
4343
const resp = await codeServer.fetch(proxyPath)
44-
assert.equal(resp.status, 200)
45-
assert.equal(await resp.json(), "joe is the best")
44+
expect(resp.status).toBe(200)
45+
const json = await resp.json()
46+
expect(json).toBe("joe is the best")
4647
})
4748
})

‎test/socket.test.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { field, logger } from "@coder/logger"
2-
import * as assert from "assert"
32
import * as fs from "fs-extra"
43
import "leaked-handles"
54
import * as net from "net"
@@ -15,8 +14,8 @@ describe("SocketProxyProvider", () => {
1514
const onServerError = new Emitter<{ event: string; error: Error }>()
1615
const onClientError = new Emitter<{ event: string; error: Error }>()
1716
const onProxyError = new Emitter<{ event: string; error: Error }>()
18-
const fromServerToClient = new Emitter<string>()
19-
const fromClientToServer = new Emitter<string>()
17+
const fromServerToClient = new Emitter<Buffer>()
18+
const fromClientToServer = new Emitter<Buffer>()
2019
const fromClientToProxy = new Emitter<Buffer>()
2120

2221
let errors = 0
@@ -44,7 +43,7 @@ describe("SocketProxyProvider", () => {
4443
})
4544
}
4645

47-
before(async () => {
46+
beforeAll(async () => {
4847
const cert = await generateCertificate("localhost")
4948
const options = {
5049
cert: fs.readFileSync(cert.cert),
@@ -56,7 +55,7 @@ describe("SocketProxyProvider", () => {
5655
const socketPath = await provider.findFreeSocketPath(path.join(tmpdir, "tests/tls-socket-proxy"))
5756
await fs.remove(socketPath)
5857

59-
return new Promise((_resolve) => {
58+
return new Promise<void>((_resolve) => {
6059
const resolved: { [key: string]: boolean } = { client: false, server: false }
6160
const resolve = (type: "client" | "server"): void => {
6261
resolved[type] = true
@@ -93,14 +92,16 @@ describe("SocketProxyProvider", () => {
9392

9493
it("should work without a proxy", async () => {
9594
server.write("server->client")
96-
assert.equal(await getData(fromServerToClient), "server->client")
95+
const dataFromServerToClient = (await getData(fromServerToClient)).toString()
96+
expect(dataFromServerToClient).toBe("server->client")
9797
client.write("client->server")
98-
assert.equal(await getData(fromClientToServer), "client->server")
99-
assert.equal(errors, 0)
98+
const dataFromClientToServer = (await getData(fromClientToServer)).toString()
99+
expect(dataFromClientToServer).toBe("client->server")
100+
expect(errors).toEqual(0)
100101
})
101102

102103
it("should work with a proxy", async () => {
103-
assert.equal(server instanceof tls.TLSSocket, true)
104+
expect(server instanceof tls.TLSSocket).toBe(true)
104105
proxy = (await provider.createProxy(server))
105106
.on("data", (d) => fromClientToProxy.emit(d))
106107
.on("error", (error) => onProxyError.emit({ event: "error", error }))
@@ -110,10 +111,12 @@ describe("SocketProxyProvider", () => {
110111
provider.stop() // We don't need more proxies.
111112

112113
proxy.write("server proxy->client")
113-
assert.equal(await getData(fromServerToClient), "server proxy->client")
114+
const dataFromServerToClient = await (await getData(fromServerToClient)).toString()
115+
expect(dataFromServerToClient).toBe("server proxy->client")
114116
client.write("client->server proxy")
115-
assert.equal(await getData(fromClientToProxy), "client->server proxy")
116-
assert.equal(errors, 0)
117+
const dataFromClientToProxy = await (await getData(fromClientToProxy)).toString()
118+
expect(dataFromClientToProxy).toBe("client->server proxy")
119+
expect(errors).toEqual(0)
117120
})
118121

119122
it("should close", async () => {

‎test/update.test.ts

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as assert from "assert"
21
import * as fs from "fs-extra"
32
import * as http from "http"
43
import * as path from "path"
@@ -45,7 +44,7 @@ describe.skip("update", () => {
4544
return _provider
4645
}
4746

48-
before(async () => {
47+
beforeAll(async () => {
4948
await new Promise((resolve, reject) => {
5049
server.on("error", reject)
5150
server.on("listening", resolve)
@@ -58,7 +57,7 @@ describe.skip("update", () => {
5857
await fs.mkdirp(path.join(tmpdir, "tests/updates"))
5958
})
6059

61-
after(() => {
60+
afterAll(() => {
6261
server.close()
6362
})
6463

@@ -73,11 +72,11 @@ describe.skip("update", () => {
7372
const now = Date.now()
7473
const update = await p.getUpdate()
7574

76-
assert.deepEqual({ update }, await settings.read())
77-
assert.equal(isNaN(update.checked), false)
78-
assert.equal(update.checked < Date.now() && update.checked >= now, true)
79-
assert.equal(update.version, "2.1.0")
80-
assert.deepEqual(spy, ["/latest"])
75+
await expect(settings.read()).resolves.toEqual({ update })
76+
expect(isNaN(update.checked)).toEqual(false)
77+
expect(update.checked < Date.now() && update.checked >= now).toEqual(true)
78+
expect(update.version).toBe("2.1.0")
79+
expect(spy).toEqual(["/latest"])
8180
})
8281

8382
it("should keep existing information", async () => {
@@ -87,11 +86,11 @@ describe.skip("update", () => {
8786
const now = Date.now()
8887
const update = await p.getUpdate()
8988

90-
assert.deepEqual({ update }, await settings.read())
91-
assert.equal(isNaN(update.checked), false)
92-
assert.equal(update.checked < now, true)
93-
assert.equal(update.version, "2.1.0")
94-
assert.deepEqual(spy, [])
89+
await expect(settings.read()).resolves.toEqual({ update })
90+
expect(isNaN(update.checked)).toBe(false)
91+
expect(update.checked < now).toBe(true)
92+
expect(update.version).toBe("2.1.0")
93+
expect(spy).toEqual([])
9594
})
9695

9796
it("should force getting the latest", async () => {
@@ -101,53 +100,54 @@ describe.skip("update", () => {
101100
const now = Date.now()
102101
const update = await p.getUpdate(true)
103102

104-
assert.deepEqual({ update }, await settings.read())
105-
assert.equal(isNaN(update.checked), false)
106-
assert.equal(update.checked < Date.now() && update.checked >= now, true)
107-
assert.equal(update.version, "4.1.1")
108-
assert.deepEqual(spy, ["/latest"])
103+
await expect(settings.read()).resolves.toEqual({ update })
104+
expect(isNaN(update.checked)).toBe(false)
105+
expect(update.checked < Date.now() && update.checked >= now).toBe(true)
106+
expect(update.version).toBe("4.1.1")
107+
expect(spy).toBe(["/latest"])
109108
})
110109

111110
it("should get latest after interval passes", async () => {
112111
const p = provider()
113112
await p.getUpdate()
114-
assert.deepEqual(spy, [])
113+
expect(spy).toEqual([])
115114

116115
let checked = Date.now() - 1000 * 60 * 60 * 23
117116
await settings.write({ update: { checked, version } })
118117
await p.getUpdate()
119-
assert.deepEqual(spy, [])
118+
expect(spy).toEqual([])
120119

121120
checked = Date.now() - 1000 * 60 * 60 * 25
122121
await settings.write({ update: { checked, version } })
123122

124123
const update = await p.getUpdate()
125-
assert.notEqual(update.checked, checked)
126-
assert.deepEqual(spy, ["/latest"])
124+
expect(update.checked).not.toBe(checked)
125+
expect(spy).toBe(["/latest"])
127126
})
128127

129128
it("should check if it's the current version", async () => {
130129
version = "9999999.99999.9999"
131130

132131
const p = provider()
133132
let update = await p.getUpdate(true)
134-
assert.equal(p.isLatestVersion(update), false)
133+
expect(p.isLatestVersion(update)).toBe(false)
135134

136135
version = "0.0.0"
137136
update = await p.getUpdate(true)
138-
assert.equal(p.isLatestVersion(update), true)
137+
expect(p.isLatestVersion(update)).toBe(true)
139138

140139
// Old version format; make sure it doesn't report as being later.
141140
version = "999999.9999-invalid999.99.9"
142141
update = await p.getUpdate(true)
143-
assert.equal(p.isLatestVersion(update), true)
142+
expect(p.isLatestVersion(update)).toBe(true)
144143
})
145144

146145
it("should not reject if unable to fetch", async () => {
146+
expect.assertions(2)
147147
let provider = new UpdateProvider("invalid", settings)
148-
await assert.doesNotReject(() => provider.getUpdate(true))
148+
await expect(() => provider.getUpdate(true)).resolves.toBe(undefined)
149149

150150
provider = new UpdateProvider("http://probably.invalid.dev.localhost/latest", settings)
151-
await assert.doesNotReject(() => provider.getUpdate(true))
151+
await expect(() => provider.getUpdate(true)).resolves.toBe(undefined)
152152
})
153153
})

‎test/util.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import * as assert from "assert"
21
import { normalize } from "../src/common/util"
32

43
describe("util", () => {
54
describe("normalize", () => {
65
it("should remove multiple slashes", () => {
7-
assert.equal(normalize("//foo//bar//baz///mumble"), "/foo/bar/baz/mumble")
6+
expect(normalize("//foo//bar//baz///mumble")).toBe("/foo/bar/baz/mumble")
87
})
98

109
it("should remove trailing slashes", () => {
11-
assert.equal(normalize("qux///"), "qux")
10+
expect(normalize("qux///")).toBe("qux")
1211
})
1312

1413
it("should preserve trailing slash if it exists", () => {
15-
assert.equal(normalize("qux///", true), "qux/")
16-
assert.equal(normalize("qux", true), "qux")
14+
expect(normalize("qux///", true)).toBe("qux/")
15+
expect(normalize("qux", true)).toBe("qux")
1716
})
1817
})
1918
})

‎test/yarn.lock

Lines changed: 3755 additions & 0 deletions
Large diffs are not rendered by default.

‎tsconfig.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
"sourceMap": true,
1616
"tsBuildInfoFile": "./.cache/tsbuildinfo",
1717
"incremental": true,
18-
"rootDir": "./src",
19-
"typeRoots": ["./node_modules/@types", "./typings"],
18+
"typeRoots": ["./node_modules/@types", "./typings", "./test/node_modules/@types"],
2019
"downlevelIteration": true
2120
},
22-
"include": ["./src/**/*.ts"]
21+
"include": ["./src/**/*.ts"],
22+
"exclude": ["/test", "/lib", "/ci", "/doc"]
2323
}

‎yarn.lock

Lines changed: 43 additions & 447 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.