diff --git a/test/e2e/codeServer.test.ts b/test/e2e/codeServer.test.ts index 1982a100b..d0e6ac929 100644 --- a/test/e2e/codeServer.test.ts +++ b/test/e2e/codeServer.test.ts @@ -1,5 +1,5 @@ import { test, expect } from "@playwright/test" -import { STORAGE } from "../utils/constants" +import { CODE_SERVER_ADDRESS, STORAGE } from "../utils/constants" import { CodeServer } from "./models/CodeServer" test.describe("CodeServer", () => { @@ -23,24 +23,23 @@ test.describe("CodeServer", () => { await codeServer.navigate() }) - test("should open the default folder if not open", options, async ({ page }) => { - await codeServer.openFolder() + test("should navigate to the CODE_SERVER_ADDRESS", options, async ({ page }) => { + // 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 - // which is the default folder that opens - expect(await page.isVisible("text=workspaceStorage")).toBe(true) + test("should always see the code-server editor", options, async ({ page }) => { + expect(await codeServer.isEditorVisible()).toBe(true) }) test("should show the Integrated Terminal", options, async ({ page }) => { - await codeServer.viewTerminal() + await codeServer.focusTerminal() 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=[]")) - }) }) diff --git a/test/e2e/models/CodeServer.ts b/test/e2e/models/CodeServer.ts index 98fce1907..7fbf37060 100644 --- a/test/e2e/models/CodeServer.ts +++ b/test/e2e/models/CodeServer.ts @@ -9,53 +9,66 @@ export class CodeServer { constructor(page: Page) { this.page = page } + + /** + * Navigates to CODE_SERVER_ADDRESS + */ async navigate() { 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 - await this.page.isVisible("div.monaco-workbench") - } - /** - * 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") - } + // 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 }) } /** - * Toggles the integrated terminal if not already in view - * and focuses it + * Focuses Integrated Terminal + * 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() { - 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) { - await this.page.keyboard.press("Meta+P") - await this.page.waitForSelector('[aria-describedby="quickInput_message"]') - await this.page.keyboard.type(input) - await this.page.waitForTimeout(2000) - await this.page.keyboard.press("Enter") - await this.page.waitForTimeout(2000) + // Click text=View + await this.page.hover("text=View") + await this.page.click("text=View") + + // Click text=Terminal + await this.page.hover("text=Terminal") + await this.page.click("text=Terminal") } } diff --git a/test/e2e/terminal.test.ts b/test/e2e/terminal.test.ts index a68f01bd1..9fb31bcfd 100644 --- a/test/e2e/terminal.test.ts +++ b/test/e2e/terminal.test.ts @@ -1,4 +1,8 @@ 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 { CodeServer } from "./models/CodeServer" @@ -6,7 +10,7 @@ test.describe("Integrated Terminal", () => { // Create a new context with the saved storage state // so we don't have to logged in const options: any = {} - const testFileName = "hello.txt" + const testFileName = "test.txt" const testString = "new string test from e2e test" let codeServer: CodeServer @@ -25,36 +29,34 @@ test.describe("Integrated Terminal", () => { }) test("should echo a string to a file", options, async ({ page }) => { - // Open the default folder - await codeServer.openFolder() - + const tmpFolderPath = fs.mkdtempSync(path.join(tmpdir(), "code-server-test")) + const tmpFile = `${tmpFolderPath}${path.sep}${testFileName}` // Open terminal and type in value - await codeServer.viewTerminal() 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.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) { - // Check that the file has the test string in it - await codeServer.quickOpen(testFileName) - expect(await page.isVisible(`text="${testString}"`)).toBe(true) + // .access checks if the file exists without opening it + // it doesn't return anything hence why we expect it to + // resolve to undefined + // 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 - // Remove file - await codeServer.focusTerminal() - await page.keyboard.type(`rm ${testFileName}`) - await page.keyboard.press("Enter") - await page.waitForTimeout(2000) - // Close the file from workbench - // otherwise it will still be visible - // and our assertion will fail - await page.keyboard.press(`Meta+W`) - expect(await page.isVisible(`text="${testString}"`)).toBe(false) - } + await fs.promises.rmdir(tmpFolderPath, { recursive: true }) + // Make sure neither file nor folder exist + // Note: We have to use ts-ignore because of an upstream typing error + // See: https://github.com/microsoft/folio/issues/230#event-4621948411 + /* eslint-disable @typescript-eslint/ban-ts-comment */ + // @ts-ignore + expect(fs.promises.access(tmpFile)).rejects.toThrowError(/no such file or directory/) + // @ts-ignore + expect(fs.promises.access(tmpFolderPath)).rejects.toThrowError(/no such file or directory/) }) })