Skip to content

Commit fea63fe

Browse files
authored
Merge ecb29c4 into 1b80244
2 parents 1b80244 + ecb29c4 commit fea63fe

18 files changed

+206
-60
lines changed

.eslintrc.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ rules:
3636
import/order:
3737
[error, { alphabetize: { order: "asc" }, groups: [["builtin", "external", "internal"], "parent", "sibling"] }]
3838
no-async-promise-executor: off
39-
# This isn't a real module, just types, which apparently doesn't resolve.
40-
import/no-unresolved: [error, { ignore: ["express-serve-static-core"] }]
39+
# These aren't real modules, just types, which apparently don't resolve.
40+
import/no-unresolved: [error, { ignore: ["express-serve-static-core", "vscode"] }]
4141

4242
settings:
4343
# Does not work with CommonJS unfortunately.

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ VS Code v0.00.0
3939

4040
### New Features
4141

42-
- item
42+
- Add `VSCODE_PROXY_URI` env var for use in the terminal and extensions (#1510)
4343

4444
### Bug Fixes
4545

ci/dev/postinstall.sh

+12-5
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@ set -euo pipefail
33

44
main() {
55
cd "$(dirname "$0")/../.."
6+
source ./ci/lib.sh
67

7-
echo "Installing code-server test dependencies..."
8+
pushd test
9+
echo "Installing dependencies for $PWD"
10+
yarn install
11+
popd
812

9-
cd test
13+
pushd test/e2e/extensions/test-extension
14+
echo "Installing dependencies for $PWD"
1015
yarn install
11-
cd ..
16+
popd
1217

13-
cd vendor
14-
echo "Installing vendor dependencies..."
18+
pushd vendor
19+
echo "Installing dependencies for $PWD"
1520

1621
# * We install in 'modules' instead of 'node_modules' because VS Code's extensions
1722
# use a webpack config which cannot differentiate between its own node_modules
@@ -32,6 +37,8 @@ main() {
3237

3338
# Finally, run the vendor `postinstall`
3439
yarn run postinstall
40+
41+
popd
3542
}
3643

3744
main "$@"

ci/dev/test-e2e.sh

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ main() {
66

77
source ./ci/lib.sh
88

9+
pushd test/e2e/extensions/test-extension
10+
echo "Building test extension"
11+
yarn build
12+
popd
13+
914
local dir="$PWD"
1015
if [[ ! ${CODE_SERVER_TEST_ENTRY-} ]]; then
1116
echo "Set CODE_SERVER_TEST_ENTRY to test another build of code-server"

ci/dev/test-unit.sh

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ set -euo pipefail
33

44
main() {
55
cd "$(dirname "$0")/../.."
6-
cd test/unit/node/test-plugin
6+
source ./ci/lib.sh
7+
8+
echo "Building test plugin"
9+
pushd test/unit/node/test-plugin
710
make -s out/index.js
11+
popd
12+
813
# We must keep jest in a sub-directory. See ../../test/package.json for more
914
# information. We must also run it from the root otherwise coverage will not
1015
# include our source files.
11-
cd "$OLDPWD"
1216
CS_DISABLE_PLUGINS=true ./test/node_modules/.bin/jest "$@"
1317
}
1418

src/common/util.ts

+28-19
Original file line numberDiff line numberDiff line change
@@ -66,33 +66,42 @@ export const resolveBase = (base?: string): string => {
6666
return normalize(url.pathname)
6767
}
6868

69+
let options: Options
70+
6971
/**
7072
* Get options embedded in the HTML or query params.
7173
*/
7274
export const getOptions = <T extends Options>(): T => {
73-
let options: T
74-
try {
75-
options = JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!)
76-
} catch (error) {
77-
options = {} as T
78-
}
75+
if (!options) {
76+
try {
77+
options = JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!)
78+
} catch (error) {
79+
console.error(error)
80+
options = {} as T
81+
}
7982

80-
// You can also pass options in stringified form to the options query
81-
// variable. Options provided here will override the ones in the options
82-
// element.
83-
const params = new URLSearchParams(location.search)
84-
const queryOpts = params.get("options")
85-
if (queryOpts) {
86-
options = {
87-
...options,
88-
...JSON.parse(queryOpts),
83+
// You can also pass options in stringified form to the options query
84+
// variable. Options provided here will override the ones in the options
85+
// element.
86+
const params = new URLSearchParams(location.search)
87+
const queryOpts = params.get("options")
88+
if (queryOpts) {
89+
try {
90+
options = {
91+
...options,
92+
...JSON.parse(queryOpts),
93+
}
94+
} catch (error) {
95+
// Don't fail if the query parameters are malformed.
96+
console.error(error)
97+
}
8998
}
90-
}
9199

92-
options.base = resolveBase(options.base)
93-
options.csStaticBase = resolveBase(options.csStaticBase)
100+
options.base = resolveBase(options.base)
101+
options.csStaticBase = resolveBase(options.csStaticBase)
102+
}
94103

95-
return options
104+
return options as T
96105
}
97106

98107
/**

test/e2e/extensions.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { describe, test } from "./baseFixture"
2+
3+
describe("Extensions", true, () => {
4+
// This will only work if the test extension is loaded into code-server.
5+
test("should have access to VSCODE_PROXY_URI", async ({ codeServerPage }) => {
6+
const address = await codeServerPage.address()
7+
8+
await codeServerPage.executeCommandViaMenus("code-server: Get proxy URI")
9+
10+
await codeServerPage.page.waitForSelector(`text=${address}/proxy/{port}`)
11+
})
12+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/extension.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as vscode from "vscode"
2+
3+
export function activate(context: vscode.ExtensionContext) {
4+
context.subscriptions.push(
5+
vscode.commands.registerCommand("codeServerTest.proxyUri", () => {
6+
if (process.env.VSCODE_PROXY_URI) {
7+
vscode.window.showInformationMessage(process.env.VSCODE_PROXY_URI)
8+
} else {
9+
vscode.window.showErrorMessage("No proxy URI was set")
10+
}
11+
}),
12+
)
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "code-server-extension",
3+
"description": "code-server test extension",
4+
"version": "0.0.1",
5+
"publisher": "cdr",
6+
"activationEvents": [
7+
"onCommand:codeServerTest.proxyUri"
8+
],
9+
"engines": {
10+
"vscode": "^1.56.0"
11+
},
12+
"main": "./extension.js",
13+
"contributes": {
14+
"commands": [
15+
{
16+
"command": "codeServerTest.proxyUri",
17+
"title": "Get proxy URI",
18+
"category": "code-server"
19+
}
20+
]
21+
},
22+
"devDependencies": {
23+
"@types/vscode": "^1.56.0",
24+
"typescript": "^4.0.5"
25+
},
26+
"scripts": {
27+
"build": "tsc extension.ts"
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2020",
4+
"module": "commonjs",
5+
"outDir": ".",
6+
"strict": true,
7+
"baseUrl": "./"
8+
},
9+
"include": ["./extension.ts"]
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2+
# yarn lockfile v1
3+
4+
5+
"@types/vscode@^1.56.0":
6+
version "1.57.0"
7+
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.57.0.tgz#cc648e0573b92f725cd1baf2621f8da9f8bc689f"
8+
integrity sha512-FeznBFtIDCWRluojTsi9c3LLcCHOXP5etQfBK42+ixo1CoEAchkw39tuui9zomjZuKfUVL33KZUDIwHZ/xvOkQ==
9+
10+
typescript@^4.0.5:
11+
version "4.3.2"
12+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
13+
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==

test/e2e/models/CodeServer.ts

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ export class CodeServer {
8787
path.join(dir, "config.yaml"),
8888
"--user-data-dir",
8989
dir,
90+
"--extensions-dir",
91+
path.join(__dirname, "../extensions"),
9092
// The last argument is the workspace to open.
9193
dir,
9294
],

test/playwright.config.ts

-2
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,10 @@ const config: PlaywrightTestConfig = {
2020
name: "Chromium",
2121
use: { browserName: "chromium" },
2222
},
23-
2423
{
2524
name: "Firefox",
2625
use: { browserName: "firefox" },
2726
},
28-
2927
{
3028
name: "WebKit",
3129
use: { browserName: "webkit" },

test/unit/common/util.test.ts

+48-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { JSDOM } from "jsdom"
22
import * as util from "../../../src/common/util"
3-
import { createLoggerMock } from "../../utils/helpers"
3+
import * as helpers from "../../utils/helpers"
44

55
const dom = new JSDOM()
66
global.document = dom.window.document
@@ -111,6 +111,8 @@ describe("util", () => {
111111
})
112112

113113
describe("getOptions", () => {
114+
let getOptions: typeof import("../../../src/common/util").getOptions
115+
114116
beforeEach(() => {
115117
const location: LocationLike = {
116118
pathname: "/healthz",
@@ -124,54 +126,80 @@ describe("util", () => {
124126
// and tell TS that our location should be looked at
125127
// as Location (even though it's missing some properties)
126128
global.location = location as Location
129+
130+
// Reset and re-import since the options are cached.
131+
jest.resetModules()
132+
getOptions = require("../../../src/common/util").getOptions
133+
134+
helpers.spyOnConsole()
127135
})
128136

129137
afterEach(() => {
130138
jest.restoreAllMocks()
131139
})
132140

133141
it("should return options with base and cssStaticBase even if it doesn't exist", () => {
134-
expect(util.getOptions()).toStrictEqual({
142+
expect(getOptions()).toStrictEqual({
135143
base: "",
136144
csStaticBase: "",
137145
})
146+
expect(console.error).toBeCalledTimes(1)
138147
})
139148

140149
it("should return options when they do exist", () => {
150+
const expected = {
151+
base: ".",
152+
csStaticBase: "./static/development/Users/jp/Dev/code-server",
153+
logLevel: 2,
154+
disableTelemetry: false,
155+
disableUpdateCheck: false,
156+
}
157+
141158
// Mock getElementById
142159
const spy = jest.spyOn(document, "getElementById")
143-
// Create a fake element and set the attribute
160+
// Create a fake element and set the attribute. Options are expected to be
161+
// stringified JSON.
144162
const mockElement = document.createElement("div")
145-
mockElement.setAttribute(
146-
"data-settings",
147-
'{"base":".","csStaticBase":"./static/development/Users/jp/Dev/code-server","logLevel":2,"disableUpdateCheck":false}',
148-
)
163+
mockElement.setAttribute("data-settings", JSON.stringify(expected))
149164
// Return mockElement from the spy
150165
// this way, when we call "getElementById"
151166
// it returns the element
152167
spy.mockImplementation(() => mockElement)
153168

154-
expect(util.getOptions()).toStrictEqual({
169+
expect(getOptions()).toStrictEqual({
170+
...expected,
171+
// The two bases should get resolved. The rest should be unchanged.
155172
base: "",
156173
csStaticBase: "/static/development/Users/jp/Dev/code-server",
157-
disableUpdateCheck: false,
174+
})
175+
expect(console.error).toBeCalledTimes(0)
176+
})
177+
178+
it("should merge options in the query", () => {
179+
// Options provided in the query will override any options provided in the
180+
// HTML. Options are expected to be stringified JSON (same as the
181+
// element).
182+
const expected = {
158183
logLevel: 2,
184+
}
185+
location.search = `?options=${JSON.stringify(expected)}`
186+
expect(getOptions()).toStrictEqual({
187+
...expected,
188+
base: "",
189+
csStaticBase: "",
159190
})
191+
// Once for the element.
192+
expect(console.error).toBeCalledTimes(1)
160193
})
161194

162-
it("should include queryOpts", () => {
163-
// Trying to understand how the implementation works
164-
// 1. It grabs the search params from location.search (i.e. ?)
165-
// 2. it then grabs the "options" param if it exists
166-
// 3. then it creates a new options object
167-
// spreads the original options
168-
// then parses the queryOpts
169-
location.search = '?options={"logLevel":2}'
170-
expect(util.getOptions()).toStrictEqual({
195+
it("should skip bad query options", () => {
196+
location.search = "?options=invalidJson"
197+
expect(getOptions()).toStrictEqual({
171198
base: "",
172199
csStaticBase: "",
173-
logLevel: 2,
174200
})
201+
// Once for the element, once for the query.
202+
expect(console.error).toBeCalledTimes(2)
175203
})
176204
})
177205

@@ -217,7 +245,7 @@ describe("util", () => {
217245
jest.restoreAllMocks()
218246
})
219247

220-
const loggerModule = createLoggerMock()
248+
const loggerModule = helpers.createLoggerMock()
221249

222250
it("should log an error with the message and stack trace", () => {
223251
const message = "You don't have access to that folder."

0 commit comments

Comments
 (0)