Skip to content

Commit 4bb7a8d

Browse files
authored
Merge pull request coder#3590 from mxschmitt/chore/upgrade-to-latest-playwright
chore: upgrade to Playwright 1.12 with its new test-runner
2 parents 2c818e3 + dbb34ad commit 4bb7a8d

17 files changed

+483
-1044
lines changed

ci/dev/test-e2e.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ main() {
66
cd test
77
# We set these environment variables because they're used in the e2e tests
88
# they don't have to be these values, but these are the defaults
9-
PASSWORD=e45432jklfdsab CODE_SERVER_ADDRESS=http://localhost:8080 yarn folio --config=config.ts --reporter=list "$@"
9+
PASSWORD=e45432jklfdsab CODE_SERVER_ADDRESS=http://localhost:8080 yarn playwright test "$@"
1010
}
1111

1212
main "$@"

src/node/util.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,7 @@ export const isHashLegacyMatch = (password: string, hashPassword: string) => {
165165
return safeCompare(hashedWithLegacy, hashPassword)
166166
}
167167

168-
const passwordMethods = ["SHA256", "ARGON2", "PLAIN_TEXT"] as const
169-
export type PasswordMethod = typeof passwordMethods[number]
168+
export type PasswordMethod = "SHA256" | "ARGON2" | "PLAIN_TEXT"
170169

171170
/**
172171
* Used to determine the password method.
@@ -413,7 +412,7 @@ export const isObject = <T extends object>(obj: T): obj is T => {
413412
* we don't have to set up a `vs` alias to be able to import with types (since
414413
* the alternative is to directly import from `out`).
415414
*/
416-
const enum CharCode {
415+
enum CharCode {
417416
Slash = 47,
418417
A = 65,
419418
Z = 90,

test/config.ts

-76
This file was deleted.

test/e2e/baseFixture.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { test as base } from "@playwright/test"
2+
import { CodeServer } from "./models/CodeServer"
3+
4+
export const test = base.extend<{ codeServerPage: CodeServer }>({
5+
codeServerPage: async ({ page }, use) => {
6+
const codeServer = new CodeServer(page)
7+
await codeServer.navigate()
8+
await use(codeServer)
9+
},
10+
})
11+
12+
export const expect = test.expect

test/e2e/browser.test.ts

+3-11
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
1-
import { test, expect } from "@playwright/test"
2-
import { CodeServer } from "./models/CodeServer"
1+
import { test, expect } from "./baseFixture"
32

43
// This is a "gut-check" test to make sure playwright is working as expected
54
test.describe("browser", () => {
6-
let codeServer: CodeServer
7-
8-
test.beforeEach(async ({ page }) => {
9-
codeServer = new CodeServer(page)
10-
await codeServer.navigate()
11-
})
12-
13-
test("browser should display correct userAgent", async ({ page, browserName }) => {
5+
test("browser should display correct userAgent", async ({ codeServerPage, browserName }) => {
146
const displayNames = {
157
chromium: "Chrome",
168
firefox: "Firefox",
179
webkit: "Safari",
1810
}
19-
const userAgent = await page.evaluate("navigator.userAgent")
11+
const userAgent = await codeServerPage.page.evaluate("navigator.userAgent")
2012

2113
expect(userAgent).toContain(displayNames[browserName])
2214
})

test/e2e/codeServer.test.ts

+13-30
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,32 @@
1-
import { test, expect } from "@playwright/test"
2-
import { CODE_SERVER_ADDRESS, STORAGE } from "../utils/constants"
3-
import { CodeServer } from "./models/CodeServer"
1+
import { CODE_SERVER_ADDRESS, storageState } from "../utils/constants"
2+
import { test, expect } from "./baseFixture"
43

54
test.describe("CodeServer", () => {
6-
// Create a new context with the saved storage state
7-
// so we don't have to logged in
8-
const options: any = {}
9-
let codeServer: CodeServer
10-
11-
// TODO@jsjoeio
12-
// Fix this once https://github.com/microsoft/playwright-test/issues/240
13-
// is fixed
14-
if (STORAGE) {
15-
const storageState = JSON.parse(STORAGE) || {}
16-
options.contextOptions = {
17-
storageState,
18-
}
19-
}
20-
21-
test.beforeEach(async ({ page }) => {
22-
codeServer = new CodeServer(page)
23-
await codeServer.setup()
5+
test.use({
6+
storageState,
247
})
258

26-
test(`should navigate to ${CODE_SERVER_ADDRESS}`, options, async ({ page }) => {
9+
test(`should navigate to ${CODE_SERVER_ADDRESS}`, async ({ codeServerPage }) => {
2710
// We navigate codeServer before each test
2811
// and we start the test with a storage state
2912
// which means we should be logged in
3013
// so it should be on the address
31-
const url = page.url()
14+
const url = codeServerPage.page.url()
3215
// We use match because there may be a / at the end
3316
// so we don't want it to fail if we expect http://localhost:8080 to match http://localhost:8080/
3417
expect(url).toMatch(CODE_SERVER_ADDRESS)
3518
})
3619

37-
test("should always see the code-server editor", options, async ({ page }) => {
38-
expect(await codeServer.isEditorVisible()).toBe(true)
20+
test("should always see the code-server editor", async ({ codeServerPage }) => {
21+
expect(await codeServerPage.isEditorVisible()).toBe(true)
3922
})
4023

41-
test("should always have a connection", options, async ({ page }) => {
42-
expect(await codeServer.isConnected()).toBe(true)
24+
test("should always have a connection", async ({ codeServerPage }) => {
25+
expect(await codeServerPage.isConnected()).toBe(true)
4326
})
4427

45-
test("should show the Integrated Terminal", options, async ({ page }) => {
46-
await codeServer.focusTerminal()
47-
expect(await page.isVisible("#terminal")).toBe(true)
28+
test("should show the Integrated Terminal", async ({ codeServerPage }) => {
29+
await codeServerPage.focusTerminal()
30+
expect(await codeServerPage.page.isVisible("#terminal")).toBe(true)
4831
})
4932
})

test/e2e/globalSetup.test.ts

+8-23
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,15 @@
1-
import { test, expect } from "@playwright/test"
2-
import { STORAGE } from "../utils/constants"
3-
import { CodeServer } from "./models/CodeServer"
1+
import { storageState } from "../utils/constants"
2+
import { test, expect } from "./baseFixture"
43

54
// This test is to make sure the globalSetup works as expected
6-
// meaning globalSetup ran and stored the storageState in STORAGE
5+
// meaning globalSetup ran and stored the storageState
76
test.describe("globalSetup", () => {
8-
// Create a new context with the saved storage state
9-
// so we don't have to logged in
10-
const options: any = {}
11-
let codeServer: CodeServer
12-
13-
// TODO@jsjoeio
14-
// Fix this once https://github.com/microsoft/playwright-test/issues/240
15-
// is fixed
16-
if (STORAGE) {
17-
const storageState = JSON.parse(STORAGE) || {}
18-
options.contextOptions = {
19-
storageState,
20-
}
21-
}
22-
test.beforeEach(async ({ page }) => {
23-
codeServer = new CodeServer(page)
24-
await codeServer.setup()
7+
test.use({
8+
storageState,
259
})
26-
test("should keep us logged in using the storageState", options, async ({ page }) => {
10+
11+
test("should keep us logged in using the storageState", async ({ codeServerPage }) => {
2712
// Make sure the editor actually loaded
28-
expect(await codeServer.isEditorVisible()).toBe(true)
13+
expect(await codeServerPage.isEditorVisible()).toBe(true)
2914
})
3015
})

test/e2e/login.test.ts

+28-37
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,67 @@
1-
import { test, expect } from "@playwright/test"
21
import { PASSWORD } from "../utils/constants"
3-
import { CodeServer } from "./models/CodeServer"
2+
import { test, expect } from "./baseFixture"
43

54
test.describe("login", () => {
65
// Reset the browser so no cookies are persisted
76
// by emptying the storageState
8-
const options = {
9-
contextOptions: {
10-
storageState: {},
11-
},
12-
}
13-
let codeServer: CodeServer
14-
15-
test.beforeEach(async ({ page }) => {
16-
codeServer = new CodeServer(page)
17-
await codeServer.navigate()
7+
test.use({
8+
storageState: {},
189
})
1910

20-
test("should see the login page", options, async ({ page }) => {
11+
test("should see the login page", async ({ codeServerPage }) => {
2112
// It should send us to the login page
22-
expect(await page.title()).toBe("code-server login")
13+
expect(await codeServerPage.page.title()).toBe("code-server login")
2314
})
2415

25-
test("should be able to login", options, async ({ page }) => {
16+
test("should be able to login", async ({ codeServerPage }) => {
2617
// Type in password
27-
await page.fill(".password", PASSWORD)
18+
await codeServerPage.page.fill(".password", PASSWORD)
2819
// Click the submit button and login
29-
await page.click(".submit")
30-
await page.waitForLoadState("networkidle")
20+
await codeServerPage.page.click(".submit")
21+
await codeServerPage.page.waitForLoadState("networkidle")
3122
// We do this because occassionally code-server doesn't load on Firefox
3223
// but loads if you reload once or twice
33-
await codeServer.reloadUntilEditorIsReady()
24+
await codeServerPage.reloadUntilEditorIsReady()
3425
// Make sure the editor actually loaded
35-
expect(await codeServer.isEditorVisible()).toBe(true)
26+
expect(await codeServerPage.isEditorVisible()).toBe(true)
3627
})
3728

38-
test("should see an error message for missing password", options, async ({ page }) => {
29+
test("should see an error message for missing password", async ({ codeServerPage }) => {
3930
// Skip entering password
4031
// Click the submit button and login
41-
await page.click(".submit")
42-
await page.waitForLoadState("networkidle")
43-
expect(await page.isVisible("text=Missing password"))
32+
await codeServerPage.page.click(".submit")
33+
await codeServerPage.page.waitForLoadState("networkidle")
34+
expect(await codeServerPage.page.isVisible("text=Missing password"))
4435
})
4536

46-
test("should see an error message for incorrect password", options, async ({ page }) => {
37+
test("should see an error message for incorrect password", async ({ codeServerPage }) => {
4738
// Type in password
48-
await page.fill(".password", "password123")
39+
await codeServerPage.page.fill(".password", "password123")
4940
// Click the submit button and login
50-
await page.click(".submit")
51-
await page.waitForLoadState("networkidle")
52-
expect(await page.isVisible("text=Incorrect password"))
41+
await codeServerPage.page.click(".submit")
42+
await codeServerPage.page.waitForLoadState("networkidle")
43+
expect(await codeServerPage.page.isVisible("text=Incorrect password"))
5344
})
5445

55-
test("should hit the rate limiter for too many unsuccessful logins", options, async ({ page }) => {
46+
test("should hit the rate limiter for too many unsuccessful logins", async ({ codeServerPage }) => {
5647
// Type in password
57-
await page.fill(".password", "password123")
48+
await codeServerPage.page.fill(".password", "password123")
5849
// Click the submit button and login
5950
// The current RateLimiter allows 2 logins per minute plus
6051
// 12 logins per hour for a total of 14
6152
// See: src/node/routes/login.ts
6253
for (let i = 1; i <= 14; i++) {
63-
await page.click(".submit")
64-
await page.waitForLoadState("networkidle")
54+
await codeServerPage.page.click(".submit")
55+
await codeServerPage.page.waitForLoadState("networkidle")
6556
// We double-check that the correct error message shows
6657
// which should be for incorrect password
67-
expect(await page.isVisible("text=Incorrect password"))
58+
expect(await codeServerPage.page.isVisible("text=Incorrect password"))
6859
}
6960

7061
// The 15th should fail for a different reason:
7162
// login rate
72-
await page.click(".submit")
73-
await page.waitForLoadState("networkidle")
74-
expect(await page.isVisible("text=Login rate limited!"))
63+
await codeServerPage.page.click(".submit")
64+
await codeServerPage.page.waitForLoadState("networkidle")
65+
expect(await codeServerPage.page.isVisible("text=Login rate limited!"))
7566
})
7667
})

0 commit comments

Comments
 (0)