Skip to content

Commit cc99fdd

Browse files
committed
feat: add test for terminal echo to file
1 parent 2bf0a0e commit cc99fdd

File tree

3 files changed

+90
-76
lines changed

3 files changed

+90
-76
lines changed

test/e2e/codeServer.test.ts

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { test, expect } from "@playwright/test"
2-
import { STORAGE } from "../utils/constants"
2+
import { CODE_SERVER_ADDRESS, STORAGE } from "../utils/constants"
33
import { CodeServer } from "./models/CodeServer"
44

55
test.describe("CodeServer", () => {
@@ -23,24 +23,23 @@ test.describe("CodeServer", () => {
2323
await codeServer.navigate()
2424
})
2525

26-
test("should open the default folder if not open", options, async ({ page }) => {
27-
await codeServer.openFolder()
26+
test("should navigate to the CODE_SERVER_ADDRESS", options, async ({ page }) => {
27+
// We navigate codeServer before each test
28+
// and we start the test with a storage state
29+
// which means we should be logged in
30+
// so it should be on the address
31+
const url = page.url()
32+
// We use match because there may be a / at the end
33+
// so we don't want it to fail if we expect http://localhost:8080 to match http://localhost:8080/
34+
expect(url).toMatch(CODE_SERVER_ADDRESS)
35+
})
2836

29-
// find workspaceStorage in the Explorer menu, which would be open in the User folder
30-
// which is the default folder that opens
31-
expect(await page.isVisible("text=workspaceStorage")).toBe(true)
37+
test("should always see the code-server editor", options, async ({ page }) => {
38+
expect(await codeServer.isEditorVisible()).toBe(true)
3239
})
3340

3441
test("should show the Integrated Terminal", options, async ({ page }) => {
35-
await codeServer.viewTerminal()
42+
await codeServer.focusTerminal()
3643
expect(await page.isVisible("#terminal")).toBe(true)
3744
})
38-
39-
test("should open a file with quickOpen", options, async ({ page }) => {
40-
await codeServer.openFolder()
41-
await codeServer.quickOpen("extensions.json")
42-
// If the file is open, we will see an empty array
43-
// assuming no extensions are installed
44-
expect(await page.isVisible("text=[]"))
45-
})
4645
})

test/e2e/models/CodeServer.ts

+49-36
Original file line numberDiff line numberDiff line change
@@ -9,53 +9,66 @@ export class CodeServer {
99
constructor(page: Page) {
1010
this.page = page
1111
}
12+
13+
/**
14+
* Navigates to CODE_SERVER_ADDRESS
15+
*/
1216
async navigate() {
1317
await this.page.goto(CODE_SERVER_ADDRESS, { waitUntil: "networkidle" })
14-
// Make sure the editor actually loaded
15-
await this.page.isVisible("div.monaco-workbench")
18+
19+
let editorIsVisible = await this.isEditorVisible()
20+
let reloadCount = 0
21+
22+
// Occassionally code-server timeouts in Firefox
23+
// we're not sure why
24+
// but usually a reload or two fixes it
25+
// TODO@jsjoeio @oxy look into Firefox reconnection/timeout issues
26+
// TODO@jsjoeio sometimes it's 2 reloads, othertimes it's 9
27+
// double-check this logic
28+
while (!editorIsVisible) {
29+
reloadCount += 1
30+
editorIsVisible = await this.isEditorVisible()
31+
if (editorIsVisible) {
32+
console.log(`Editor became visible after ${reloadCount} reloads`)
33+
break
34+
}
35+
await this.page.reload({ waitUntil: "networkidle" })
36+
}
1637
}
38+
1739
/**
18-
* Opens the default folder /User if no arg passed
19-
* @param absolutePath Example: /Users/jp/.local/share/code-server/User/
20-
*
40+
* Checks if the editor is visible
2141
*/
22-
async openFolder(absolutePath?: string) {
23-
// Check if no folder is opened
24-
const folderIsNotOpen = await this.page.isVisible("text=You have not yet opened")
25-
26-
if (folderIsNotOpen) {
27-
// Open the default folder
28-
await this.page.keyboard.press("Meta+O")
29-
await this.page.keyboard.press("Enter")
30-
await this.page.waitForLoadState("networkidle")
31-
}
42+
async isEditorVisible() {
43+
// Make sure the editor actually loaded
44+
// If it's not visible after 2 seconds, something is wrong
45+
await this.page.waitForLoadState("networkidle")
46+
return await this.page.isVisible("div.monaco-workbench", { timeout: 5000 })
3247
}
3348

3449
/**
35-
* Toggles the integrated terminal if not already in view
36-
* and focuses it
50+
* Focuses Integrated Terminal
51+
* by going to the Application Menu
52+
* and clicking View > Terminal
3753
*/
38-
async viewTerminal() {
39-
// Check if Terminal is already in view
40-
const isTerminalInView = await this.page.isVisible("#terminal")
41-
42-
if (!isTerminalInView) {
43-
// Open using default keyboard shortcut
44-
await this.focusTerminal()
45-
await this.page.waitForSelector("#terminal")
54+
async focusTerminal() {
55+
// If the terminal is already visible
56+
// then we can focus it by hitting the keyboard shortcut
57+
const isTerminalVisible = await this.page.isVisible("#terminal")
58+
if (isTerminalVisible) {
59+
await this.page.keyboard.press(`Meta+Backquote`)
60+
return
4661
}
47-
}
62+
// Open using the manu
63+
// Click [aria-label="Application Menu"] div[role="none"]
64+
await this.page.click('[aria-label="Application Menu"] div[role="none"]')
4865

49-
async focusTerminal() {
50-
await this.page.keyboard.press("Control+Backquote")
51-
}
66+
// Click text=View
67+
await this.page.hover("text=View")
68+
await this.page.click("text=View")
5269

53-
async quickOpen(input: string) {
54-
await this.page.keyboard.press("Meta+P")
55-
await this.page.waitForSelector('[aria-describedby="quickInput_message"]')
56-
await this.page.keyboard.type(input)
57-
await this.page.waitForTimeout(2000)
58-
await this.page.keyboard.press("Enter")
59-
await this.page.waitForTimeout(2000)
70+
// Click text=Terminal
71+
await this.page.hover("text=Terminal")
72+
await this.page.click("text=Terminal")
6073
}
6174
}

test/e2e/terminal.test.ts

+27-25
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import { test, expect } from "@playwright/test"
2+
import * as fs from "fs"
3+
import { tmpdir } from "os"
4+
import * as path from "path"
5+
26
import { STORAGE } from "../utils/constants"
37
import { CodeServer } from "./models/CodeServer"
48

59
test.describe("Integrated Terminal", () => {
610
// Create a new context with the saved storage state
711
// so we don't have to logged in
812
const options: any = {}
9-
const testFileName = "hello.txt"
13+
const testFileName = "test.txt"
1014
const testString = "new string test from e2e test"
1115
let codeServer: CodeServer
1216

@@ -25,36 +29,34 @@ test.describe("Integrated Terminal", () => {
2529
})
2630

2731
test("should echo a string to a file", options, async ({ page }) => {
28-
// Open the default folder
29-
await codeServer.openFolder()
30-
32+
const tmpFolderPath = fs.mkdtempSync(path.join(tmpdir(), "code-server-test"))
33+
const tmpFile = `${tmpFolderPath}${path.sep}${testFileName}`
3134
// Open terminal and type in value
32-
await codeServer.viewTerminal()
3335
await codeServer.focusTerminal()
3436

35-
await page.keyboard.type(`echo '${testString}' >> ${testFileName}`)
37+
// give the terminal a second to load
38+
await page.waitForTimeout(3000)
39+
await page.keyboard.type(`echo '${testString}' > ${tmpFile}`)
40+
// Wait for the typing to finish before hitting enter
41+
await page.waitForTimeout(500)
3642
await page.keyboard.press("Enter")
3743
await page.waitForTimeout(2000)
38-
// It should show up on the left sidebar as a new file
39-
const isFileVisible = await page.isVisible(`text="${testFileName}"`)
40-
expect(isFileVisible).toBe(true)
4144

42-
if (isFileVisible) {
43-
// Check that the file has the test string in it
44-
await codeServer.quickOpen(testFileName)
45-
expect(await page.isVisible(`text="${testString}"`)).toBe(true)
45+
// .access checks if the file exists without opening it
46+
// it doesn't return anything hence why we expect it to
47+
// resolve to undefined
48+
// If the promise rejects (i.e. the file doesn't exist)
49+
// then the assertion will fail
50+
await expect(fs.promises.access(tmpFile)).resolves.toBeUndefined()
4651

47-
// Clean up
48-
// Remove file
49-
await codeServer.focusTerminal()
50-
await page.keyboard.type(`rm ${testFileName}`)
51-
await page.keyboard.press("Enter")
52-
await page.waitForTimeout(2000)
53-
// Close the file from workbench
54-
// otherwise it will still be visible
55-
// and our assertion will fail
56-
await page.keyboard.press(`Meta+W`)
57-
expect(await page.isVisible(`text="${testString}"`)).toBe(false)
58-
}
52+
await fs.promises.rmdir(tmpFolderPath, { recursive: true })
53+
// Make sure neither file nor folder exist
54+
// Note: We have to use ts-ignore because of an upstream typing error
55+
// See: https://github.com/microsoft/folio/issues/230#event-4621948411
56+
/* eslint-disable @typescript-eslint/ban-ts-comment */
57+
// @ts-ignore
58+
expect(fs.promises.access(tmpFile)).rejects.toThrowError(/no such file or directory/)
59+
// @ts-ignore
60+
expect(fs.promises.access(tmpFolderPath)).rejects.toThrowError(/no such file or directory/)
5961
})
6062
})

0 commit comments

Comments
 (0)