Skip to content

Commit b3f7a20

Browse files
authored
refactor: move vscode tests to e2e (#5911)
* wip: migrate vscode tests to e2e * feat: add codeWorkspace to global setup * refactor: only use dir in spawn when we should * wip: migrate more tests * refactor: move all vscode tests to e2e * refactor(ci): move unit to own job * fixup: add codecov to unit test step * Update test/e2e/models/CodeServer.ts * Update test/e2e/models/CodeServer.ts * docs: add note about intercept requests * refactor: rm unused clean() calls * refactor: delete duplicate test * refactor: update 'should not redirect' test
1 parent fc54c44 commit b3f7a20

File tree

6 files changed

+181
-169
lines changed

6 files changed

+181
-169
lines changed

.github/workflows/build.yaml

+49-13
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,55 @@ jobs:
139139
if: steps.changed-files.outputs.any_changed == 'true'
140140
run: yarn lint:ts
141141

142+
test-unit:
143+
name: Run unit tests
144+
runs-on: ubuntu-20.04
145+
timeout-minutes: 5
146+
steps:
147+
- name: Checkout repo
148+
uses: actions/checkout@v3
149+
with:
150+
fetch-depth: 2
151+
152+
- name: Get changed files
153+
id: changed-files
154+
uses: tj-actions/[email protected]
155+
with:
156+
files: |
157+
**/*.ts
158+
files_ignore: |
159+
lib/vscode/**
160+
161+
- name: Install Node.js v16
162+
if: steps.changed-files.outputs.any_changed == 'true'
163+
uses: actions/setup-node@v3
164+
with:
165+
node-version: "16"
166+
167+
- name: Fetch dependencies from cache
168+
if: steps.changed-files.outputs.any_changed == 'true'
169+
id: cache-node-modules
170+
uses: actions/cache@v3
171+
with:
172+
path: "**/node_modules"
173+
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
174+
restore-keys: |
175+
yarn-build-
176+
177+
- name: Install dependencies
178+
if: steps.changed-files.outputs.any_changed == 'true' && steps.cache-node-modules.outputs.cache-hit != 'true'
179+
run: SKIP_SUBMODULE_DEPS=1 yarn --frozen-lockfile
180+
181+
- name: Run unit tests
182+
if: steps.changed-files.outputs.any_changed == 'true'
183+
run: yarn test:unit
184+
185+
- name: Upload coverage report to Codecov
186+
uses: codecov/codecov-action@v3
187+
with:
188+
token: ${{ secrets.CODECOV_TOKEN }}
189+
if: success()
190+
142191
build:
143192
name: Build code-server
144193
runs-on: ubuntu-20.04
@@ -206,19 +255,6 @@ jobs:
206255
if: steps.cache-vscode.outputs.cache-hit != 'true'
207256
run: yarn build:vscode
208257

209-
# Our code imports code from VS Code's `out` directory meaning VS Code
210-
# must be built before running these tests.
211-
# TODO: Move to its own step?
212-
- name: Run code-server unit tests
213-
run: yarn test:unit
214-
if: success()
215-
216-
- name: Upload coverage report to Codecov
217-
uses: codecov/codecov-action@v3
218-
with:
219-
token: ${{ secrets.CODECOV_TOKEN }}
220-
if: success()
221-
222258
# The release package does not contain any native modules
223259
# and is neutral to architecture/os/libc version.
224260
- name: Create release package

ci/dev/test-unit.sh

-16
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,6 @@ main() {
1111
make -s out/index.js
1212
popd
1313

14-
# Our code imports from `out` in order to work during development but if you
15-
# have only built for production you will have not have this directory. In
16-
# that case symlink `out` to a production build directory.
17-
if [[ ! -e lib/vscode/out ]]; then
18-
pushd lib
19-
local out=(vscode-reh-web-*)
20-
if [[ -d "${out[0]}" ]]; then
21-
ln -s "../${out[0]}/out" ./vscode/out
22-
else
23-
echo "Could not find lib/vscode/out or lib/vscode-reh-web-*"
24-
echo "Code must be built before running unit tests"
25-
exit 1
26-
fi
27-
popd
28-
fi
29-
3014
# We must keep jest in a sub-directory. See ../../test/package.json for more
3115
# information. We must also run it from the root otherwise coverage will not
3216
# include our source files.

test/e2e/models/CodeServer.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ export class CodeServer {
128128
path.join(dir, "extensions"),
129129
"--auth",
130130
"none",
131+
// The workspace to open.
132+
...(this.args.includes("--ignore-last-opened") ? [] : [dir]),
131133
...this.args,
132134
// Using port zero will spawn on a random port.
133135
"--bind-addr",
@@ -139,8 +141,6 @@ export class CodeServer {
139141
path.join(dir, "config.yaml"),
140142
"--user-data-dir",
141143
dir,
142-
// The last argument is the workspace to open.
143-
dir,
144144
]
145145
this.logger.debug("spawning `node " + args.join(" ") + "`")
146146
const proc = cp.spawn("node", args, {

test/e2e/routes.test.ts

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import { describe, test, expect } from "./baseFixture"
2+
import { clean, tmpdir } from "../utils/helpers"
3+
import * as path from "path"
4+
import { promises as fs } from "fs"
5+
6+
const routes = ["/", "/vscode", "/vscode/"]
7+
8+
describe("VS Code Routes", ["--disable-workspace-trust"], {}, async () => {
9+
const testName = "vscode-routes-default"
10+
test.beforeAll(async () => {
11+
await clean(testName)
12+
})
13+
14+
test("should load all route variations", async ({ codeServerPage }) => {
15+
for (const route of routes) {
16+
await codeServerPage.navigate(route)
17+
18+
// Check there were no redirections
19+
const url = new URL(codeServerPage.page.url())
20+
expect(url.pathname).toBe(route)
21+
22+
// TODO@jsjoeio
23+
// now that we are in a proper browser instead of scraping the HTML we
24+
// could possibly intercept requests to make sure assets are loading from
25+
// the right spot.
26+
//
27+
// Check that page loaded from correct route
28+
const html = await codeServerPage.page.innerHTML("html")
29+
switch (route) {
30+
case "/":
31+
case "/vscode/":
32+
expect(html).toMatch(/src="\.\/[a-z]+-[0-9a-z]+\/static\//)
33+
break
34+
case "/vscode":
35+
expect(html).toMatch(/src="\.\/vscode\/[a-z]+-[0-9a-z]+\/static\//)
36+
break
37+
}
38+
}
39+
})
40+
})
41+
42+
const CODE_WORKSPACE_DIR = process.env.CODE_WORKSPACE_DIR || ""
43+
describe("VS Code Routes with code-workspace", ["--disable-workspace-trust", CODE_WORKSPACE_DIR], {}, async () => {
44+
test("should redirect to the passed in workspace using human-readable query", async ({ codeServerPage }) => {
45+
const url = new URL(codeServerPage.page.url())
46+
expect(url.pathname).toBe("/")
47+
expect(url.search).toBe(`?workspace=${CODE_WORKSPACE_DIR}`)
48+
})
49+
})
50+
51+
const CODE_FOLDER_DIR = process.env.CODE_FOLDER_DIR || ""
52+
describe("VS Code Routes with code-workspace", ["--disable-workspace-trust", CODE_FOLDER_DIR], {}, async () => {
53+
test("should redirect to the passed in folder using human-readable query", async ({ codeServerPage }) => {
54+
const url = new URL(codeServerPage.page.url())
55+
expect(url.pathname).toBe("/")
56+
expect(url.search).toBe(`?folder=${CODE_FOLDER_DIR}`)
57+
})
58+
})
59+
60+
describe(
61+
"VS Code Routes with ignore-last-opened",
62+
["--disable-workspace-trust", "--ignore-last-opened"],
63+
{},
64+
async () => {
65+
test("should not redirect", async ({ codeServerPage }) => {
66+
const folder = process.env.CODE_FOLDER_DIR
67+
68+
await codeServerPage.navigate(`/`)
69+
await codeServerPage.navigate(`/?folder=${folder}`)
70+
await codeServerPage.navigate(`/`)
71+
72+
const url = new URL(codeServerPage.page.url())
73+
expect(url.pathname).toBe("/")
74+
expect(url.search).toBe("")
75+
})
76+
},
77+
)
78+
79+
describe(
80+
"VS Code Routes with no workspace or folder",
81+
["--disable-workspace-trust"],
82+
{},
83+
async () => {
84+
test("should redirect to last query folder/workspace", async ({ codeServerPage }) => {
85+
const folder = process.env.CODE_FOLDER_DIR
86+
const workspace = process.env.CODE_WORKSPACE_DIR
87+
await codeServerPage.navigate(`/?folder=${folder}&workspace=${workspace}`)
88+
89+
// If you visit again without query parameters it will re-attach them by
90+
// redirecting. It should always redirect to the same route.
91+
for (const route of routes) {
92+
await codeServerPage.navigate(route)
93+
const url = new URL(codeServerPage.page.url())
94+
expect(url.pathname).toBe(route)
95+
expect(url.search).toBe(`?folder=${folder}&workspace=${workspace}`)
96+
}
97+
})
98+
},
99+
)
100+
101+
describe(
102+
"VS Code Routes with no workspace or folder",
103+
["--disable-workspace-trust"],
104+
{},
105+
async () => {
106+
test("should not redirect if ew passed in", async ({ codeServerPage }) => {
107+
const folder = process.env.CODE_FOLDER_DIR
108+
const workspace = process.env.CODE_WORKSPACE_DIR
109+
await codeServerPage.navigate(`/?folder=${folder}&workspace=${workspace}`)
110+
111+
// Closing the folder should stop the redirecting.
112+
await codeServerPage.navigate("/?ew=true")
113+
let url = new URL(codeServerPage.page.url())
114+
expect(url.pathname).toBe("/")
115+
expect(url.search).toBe("?ew=true")
116+
})
117+
},
118+
)

test/unit/node/routes/vscode.test.ts

-137
This file was deleted.

test/utils/globalE2eSetup.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { workspaceDir } from "./constants"
2-
import { clean } from "./helpers"
2+
import { clean, tmpdir } from "./helpers"
33
import * as wtfnode from "./wtfnode"
4+
import * as path from "path"
5+
import { promises as fs } from "fs"
46

57
/**
68
* Perform workspace cleanup and authenticate. This should be ran before e2e
@@ -17,5 +19,14 @@ export default async function () {
1719
wtfnode.setup()
1820
}
1921

22+
// Create dummy code-workspace for routes.test.ts
23+
const codeWorkspace = path.join(await tmpdir(workspaceDir), "test.code-workspace")
24+
await fs.writeFile(codeWorkspace, "")
25+
process.env.CODE_WORKSPACE_DIR = codeWorkspace
26+
27+
// Create dummy folder for routes.test.ts
28+
const folder = await tmpdir(workspaceDir)
29+
process.env.CODE_FOLDER_DIR = folder
30+
2031
console.log("✅ Global Setup for Playwright End-to-End Tests is now complete.")
2132
}

0 commit comments

Comments
 (0)