feat: add test for terminal echo to file

This commit is contained in:
Joe Previte 2021-04-20 12:41:54 -07:00
parent 2bf0a0e76e
commit cc99fddf24
No known key found for this signature in database
GPG Key ID: 2C91590C6B742C24
3 changed files with 93 additions and 79 deletions

View File

@ -1,5 +1,5 @@
import { test, expect } from "@playwright/test" import { test, expect } from "@playwright/test"
import { STORAGE } from "../utils/constants" import { CODE_SERVER_ADDRESS, STORAGE } from "../utils/constants"
import { CodeServer } from "./models/CodeServer" import { CodeServer } from "./models/CodeServer"
test.describe("CodeServer", () => { test.describe("CodeServer", () => {
@ -23,24 +23,23 @@ test.describe("CodeServer", () => {
await codeServer.navigate() await codeServer.navigate()
}) })
test("should open the default folder if not open", options, async ({ page }) => { test("should navigate to the CODE_SERVER_ADDRESS", options, async ({ page }) => {
await codeServer.openFolder() // We navigate codeServer before each test
// and we start the test with a storage state
// which means we should be logged in
// so it should be on the address
const url = page.url()
// We use match because there may be a / at the end
// so we don't want it to fail if we expect http://localhost:8080 to match http://localhost:8080/
expect(url).toMatch(CODE_SERVER_ADDRESS)
})
// find workspaceStorage in the Explorer menu, which would be open in the User folder test("should always see the code-server editor", options, async ({ page }) => {
// which is the default folder that opens expect(await codeServer.isEditorVisible()).toBe(true)
expect(await page.isVisible("text=workspaceStorage")).toBe(true)
}) })
test("should show the Integrated Terminal", options, async ({ page }) => { test("should show the Integrated Terminal", options, async ({ page }) => {
await codeServer.viewTerminal() await codeServer.focusTerminal()
expect(await page.isVisible("#terminal")).toBe(true) expect(await page.isVisible("#terminal")).toBe(true)
}) })
test("should open a file with quickOpen", options, async ({ page }) => {
await codeServer.openFolder()
await codeServer.quickOpen("extensions.json")
// If the file is open, we will see an empty array
// assuming no extensions are installed
expect(await page.isVisible("text=[]"))
})
}) })

View File

@ -9,53 +9,66 @@ export class CodeServer {
constructor(page: Page) { constructor(page: Page) {
this.page = page this.page = page
} }
/**
* Navigates to CODE_SERVER_ADDRESS
*/
async navigate() { async navigate() {
await this.page.goto(CODE_SERVER_ADDRESS, { waitUntil: "networkidle" }) await this.page.goto(CODE_SERVER_ADDRESS, { waitUntil: "networkidle" })
let editorIsVisible = await this.isEditorVisible()
let reloadCount = 0
// Occassionally code-server timeouts in Firefox
// we're not sure why
// but usually a reload or two fixes it
// TODO@jsjoeio @oxy look into Firefox reconnection/timeout issues
// TODO@jsjoeio sometimes it's 2 reloads, othertimes it's 9
// double-check this logic
while (!editorIsVisible) {
reloadCount += 1
editorIsVisible = await this.isEditorVisible()
if (editorIsVisible) {
console.log(`Editor became visible after ${reloadCount} reloads`)
break
}
await this.page.reload({ waitUntil: "networkidle" })
}
}
/**
* Checks if the editor is visible
*/
async isEditorVisible() {
// Make sure the editor actually loaded // Make sure the editor actually loaded
await this.page.isVisible("div.monaco-workbench") // If it's not visible after 2 seconds, something is wrong
} await this.page.waitForLoadState("networkidle")
/** return await this.page.isVisible("div.monaco-workbench", { timeout: 5000 })
* Opens the default folder /User if no arg passed
* @param absolutePath Example: /Users/jp/.local/share/code-server/User/
*
*/
async openFolder(absolutePath?: string) {
// Check if no folder is opened
const folderIsNotOpen = await this.page.isVisible("text=You have not yet opened")
if (folderIsNotOpen) {
// Open the default folder
await this.page.keyboard.press("Meta+O")
await this.page.keyboard.press("Enter")
await this.page.waitForLoadState("networkidle")
}
} }
/** /**
* Toggles the integrated terminal if not already in view * Focuses Integrated Terminal
* and focuses it * by going to the Application Menu
* and clicking View > Terminal
*/ */
async viewTerminal() {
// Check if Terminal is already in view
const isTerminalInView = await this.page.isVisible("#terminal")
if (!isTerminalInView) {
// Open using default keyboard shortcut
await this.focusTerminal()
await this.page.waitForSelector("#terminal")
}
}
async focusTerminal() { async focusTerminal() {
await this.page.keyboard.press("Control+Backquote") // If the terminal is already visible
} // then we can focus it by hitting the keyboard shortcut
const isTerminalVisible = await this.page.isVisible("#terminal")
if (isTerminalVisible) {
await this.page.keyboard.press(`Meta+Backquote`)
return
}
// Open using the manu
// Click [aria-label="Application Menu"] div[role="none"]
await this.page.click('[aria-label="Application Menu"] div[role="none"]')
async quickOpen(input: string) { // Click text=View
await this.page.keyboard.press("Meta+P") await this.page.hover("text=View")
await this.page.waitForSelector('[aria-describedby="quickInput_message"]') await this.page.click("text=View")
await this.page.keyboard.type(input)
await this.page.waitForTimeout(2000) // Click text=Terminal
await this.page.keyboard.press("Enter") await this.page.hover("text=Terminal")
await this.page.waitForTimeout(2000) await this.page.click("text=Terminal")
} }
} }

View File

@ -1,4 +1,8 @@
import { test, expect } from "@playwright/test" import { test, expect } from "@playwright/test"
import * as fs from "fs"
import { tmpdir } from "os"
import * as path from "path"
import { STORAGE } from "../utils/constants" import { STORAGE } from "../utils/constants"
import { CodeServer } from "./models/CodeServer" import { CodeServer } from "./models/CodeServer"
@ -6,7 +10,7 @@ test.describe("Integrated Terminal", () => {
// Create a new context with the saved storage state // Create a new context with the saved storage state
// so we don't have to logged in // so we don't have to logged in
const options: any = {} const options: any = {}
const testFileName = "hello.txt" const testFileName = "test.txt"
const testString = "new string test from e2e test" const testString = "new string test from e2e test"
let codeServer: CodeServer let codeServer: CodeServer
@ -25,36 +29,34 @@ test.describe("Integrated Terminal", () => {
}) })
test("should echo a string to a file", options, async ({ page }) => { test("should echo a string to a file", options, async ({ page }) => {
// Open the default folder const tmpFolderPath = fs.mkdtempSync(path.join(tmpdir(), "code-server-test"))
await codeServer.openFolder() const tmpFile = `${tmpFolderPath}${path.sep}${testFileName}`
// Open terminal and type in value // Open terminal and type in value
await codeServer.viewTerminal()
await codeServer.focusTerminal() await codeServer.focusTerminal()
await page.keyboard.type(`echo '${testString}' >> ${testFileName}`) // give the terminal a second to load
await page.waitForTimeout(3000)
await page.keyboard.type(`echo '${testString}' > ${tmpFile}`)
// Wait for the typing to finish before hitting enter
await page.waitForTimeout(500)
await page.keyboard.press("Enter") await page.keyboard.press("Enter")
await page.waitForTimeout(2000) await page.waitForTimeout(2000)
// It should show up on the left sidebar as a new file
const isFileVisible = await page.isVisible(`text="${testFileName}"`)
expect(isFileVisible).toBe(true)
if (isFileVisible) { // .access checks if the file exists without opening it
// Check that the file has the test string in it // it doesn't return anything hence why we expect it to
await codeServer.quickOpen(testFileName) // resolve to undefined
expect(await page.isVisible(`text="${testString}"`)).toBe(true) // If the promise rejects (i.e. the file doesn't exist)
// then the assertion will fail
await expect(fs.promises.access(tmpFile)).resolves.toBeUndefined()
// Clean up await fs.promises.rmdir(tmpFolderPath, { recursive: true })
// Remove file // Make sure neither file nor folder exist
await codeServer.focusTerminal() // Note: We have to use ts-ignore because of an upstream typing error
await page.keyboard.type(`rm ${testFileName}`) // See: https://github.com/microsoft/folio/issues/230#event-4621948411
await page.keyboard.press("Enter") /* eslint-disable @typescript-eslint/ban-ts-comment */
await page.waitForTimeout(2000) // @ts-ignore
// Close the file from workbench expect(fs.promises.access(tmpFile)).rejects.toThrowError(/no such file or directory/)
// otherwise it will still be visible // @ts-ignore
// and our assertion will fail expect(fs.promises.access(tmpFolderPath)).rejects.toThrowError(/no such file or directory/)
await page.keyboard.press(`Meta+W`)
expect(await page.isVisible(`text="${testString}"`)).toBe(false)
}
}) })
}) })