2021-06-23 05:34:11 +08:00
|
|
|
import { promises as fs } from "fs"
|
|
|
|
import * as path from "path"
|
2021-04-20 06:25:57 +08:00
|
|
|
import { Page } from "playwright"
|
2021-06-23 05:34:11 +08:00
|
|
|
import { CODE_SERVER_ADDRESS, workspaceDir } from "../../utils/constants"
|
|
|
|
import { tmpdir } from "../../utils/helpers"
|
|
|
|
|
2021-04-20 06:25:57 +08:00
|
|
|
// This is a Page Object Model
|
|
|
|
// We use these to simplify e2e test authoring
|
|
|
|
// See Playwright docs: https://playwright.dev/docs/pom/
|
|
|
|
export class CodeServer {
|
2021-06-23 05:34:11 +08:00
|
|
|
private readonly editorSelector = "div.monaco-workbench"
|
2021-04-20 06:25:57 +08:00
|
|
|
|
2021-06-23 05:34:11 +08:00
|
|
|
constructor(public readonly page: Page) {}
|
2021-04-21 03:41:54 +08:00
|
|
|
|
|
|
|
/**
|
2021-06-23 05:34:11 +08:00
|
|
|
* Navigates to CODE_SERVER_ADDRESS. It will open a newly created random
|
|
|
|
* directory.
|
2021-04-21 03:41:54 +08:00
|
|
|
*/
|
2021-04-20 06:25:57 +08:00
|
|
|
async navigate() {
|
2021-06-23 05:34:11 +08:00
|
|
|
const dir = await this.createWorkspace()
|
|
|
|
await this.page.goto(`${CODE_SERVER_ADDRESS}?folder=${dir}`, { waitUntil: "networkidle" })
|
2021-04-22 05:31:15 +08:00
|
|
|
}
|
2021-04-21 03:41:54 +08:00
|
|
|
|
2021-04-22 05:31:15 +08:00
|
|
|
/**
|
|
|
|
* Checks if the editor is visible
|
2021-05-01 04:26:25 +08:00
|
|
|
* and that we are connected to the host
|
|
|
|
*
|
|
|
|
* Reload until both checks pass
|
2021-04-22 05:31:15 +08:00
|
|
|
*/
|
2021-05-01 04:26:25 +08:00
|
|
|
async reloadUntilEditorIsReady() {
|
2021-04-22 04:22:11 +08:00
|
|
|
const editorIsVisible = await this.isEditorVisible()
|
2021-05-01 04:26:25 +08:00
|
|
|
const editorIsConnected = await this.isConnected()
|
2021-04-21 03:41:54 +08:00
|
|
|
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
|
2021-05-01 04:26:25 +08:00
|
|
|
while (!editorIsVisible && !editorIsConnected) {
|
2021-04-28 02:30:22 +08:00
|
|
|
// When a reload happens, we want to wait for all resources to be
|
|
|
|
// loaded completely. Hence why we use that instead of DOMContentLoaded
|
|
|
|
// Read more: https://thisthat.dev/dom-content-loaded-vs-load/
|
|
|
|
await this.page.waitForLoadState("load")
|
|
|
|
// Give it an extra second just in case it's feeling extra slow
|
|
|
|
await this.page.waitForTimeout(1000)
|
2021-04-21 03:41:54 +08:00
|
|
|
reloadCount += 1
|
2021-06-10 21:09:38 +08:00
|
|
|
if ((await this.isEditorVisible()) && (await this.isConnected())) {
|
2021-05-01 04:26:25 +08:00
|
|
|
console.log(` Editor became ready after ${reloadCount} reloads`)
|
2021-04-21 03:41:54 +08:00
|
|
|
break
|
|
|
|
}
|
2021-04-28 02:30:22 +08:00
|
|
|
await this.page.reload()
|
2021-04-21 03:41:54 +08:00
|
|
|
}
|
2021-04-20 06:25:57 +08:00
|
|
|
}
|
2021-04-21 03:41:54 +08:00
|
|
|
|
2021-04-20 06:25:57 +08:00
|
|
|
/**
|
2021-04-21 03:41:54 +08:00
|
|
|
* Checks if the editor is visible
|
2021-04-20 06:25:57 +08:00
|
|
|
*/
|
2021-04-21 03:41:54 +08:00
|
|
|
async isEditorVisible() {
|
|
|
|
// Make sure the editor actually loaded
|
2021-06-10 21:09:38 +08:00
|
|
|
await this.page.waitForSelector(this.editorSelector)
|
2021-04-28 02:30:22 +08:00
|
|
|
return await this.page.isVisible(this.editorSelector)
|
2021-04-20 06:25:57 +08:00
|
|
|
}
|
|
|
|
|
2021-05-01 03:33:20 +08:00
|
|
|
/**
|
|
|
|
* Checks if the editor is visible
|
|
|
|
*/
|
|
|
|
async isConnected() {
|
|
|
|
await this.page.waitForLoadState("networkidle")
|
|
|
|
|
2021-05-01 04:26:25 +08:00
|
|
|
const host = new URL(CODE_SERVER_ADDRESS).host
|
|
|
|
const hostSelector = `[title="Editing on ${host}"]`
|
|
|
|
await this.page.waitForSelector(hostSelector)
|
2021-05-01 03:33:20 +08:00
|
|
|
|
2021-05-01 04:26:25 +08:00
|
|
|
return await this.page.isVisible(hostSelector)
|
2021-05-01 03:33:20 +08:00
|
|
|
}
|
|
|
|
|
2021-04-20 06:25:57 +08:00
|
|
|
/**
|
2021-04-21 03:41:54 +08:00
|
|
|
* Focuses Integrated Terminal
|
2021-04-28 02:30:22 +08:00
|
|
|
* by using "Terminal: Focus Terminal"
|
|
|
|
* from the Command Palette
|
|
|
|
*
|
|
|
|
* This should focus the terminal no matter
|
|
|
|
* if it already has focus and/or is or isn't
|
|
|
|
* visible already.
|
2021-04-20 06:25:57 +08:00
|
|
|
*/
|
2021-04-21 03:41:54 +08:00
|
|
|
async focusTerminal() {
|
|
|
|
// Click [aria-label="Application Menu"] div[role="none"]
|
|
|
|
await this.page.click('[aria-label="Application Menu"] div[role="none"]')
|
2021-04-20 06:25:57 +08:00
|
|
|
|
2021-04-21 03:41:54 +08:00
|
|
|
// Click text=View
|
|
|
|
await this.page.hover("text=View")
|
|
|
|
await this.page.click("text=View")
|
2021-04-20 06:25:57 +08:00
|
|
|
|
2021-04-28 02:30:22 +08:00
|
|
|
// Click text=Command Palette
|
|
|
|
await this.page.hover("text=Command Palette")
|
|
|
|
await this.page.click("text=Command Palette")
|
|
|
|
|
|
|
|
// Type Terminal: Focus Terminal
|
|
|
|
await this.page.keyboard.type("Terminal: Focus Terminal")
|
|
|
|
|
|
|
|
// Click Terminal: Focus Terminal
|
|
|
|
await this.page.hover("text=Terminal: Focus Terminal")
|
|
|
|
await this.page.click("text=Terminal: Focus Terminal")
|
2021-04-22 05:31:15 +08:00
|
|
|
|
2021-04-28 02:30:22 +08:00
|
|
|
// Wait for terminal textarea to show up
|
|
|
|
await this.page.waitForSelector("textarea.xterm-helper-textarea")
|
2021-04-22 05:31:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Navigates to CODE_SERVER_ADDRESS
|
2021-05-01 04:26:25 +08:00
|
|
|
* and reloads until the editor is ready
|
2021-04-22 05:31:15 +08:00
|
|
|
*
|
|
|
|
* Helpful for running before tests
|
|
|
|
*/
|
|
|
|
async setup() {
|
|
|
|
await this.navigate()
|
2021-05-01 04:26:25 +08:00
|
|
|
await this.reloadUntilEditorIsReady()
|
2021-04-20 06:25:57 +08:00
|
|
|
}
|
2021-06-23 05:34:11 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a random workspace and seed it with settings.
|
|
|
|
*/
|
|
|
|
private async createWorkspace(): Promise<string> {
|
|
|
|
const dir = await tmpdir(workspaceDir)
|
|
|
|
await fs.mkdir(path.join(dir, ".vscode"))
|
|
|
|
await fs.writeFile(
|
|
|
|
path.join(dir, ".vscode/settings.json"),
|
|
|
|
JSON.stringify({
|
|
|
|
"workbench.startupEditor": "none",
|
|
|
|
}),
|
|
|
|
"utf8",
|
|
|
|
)
|
|
|
|
return dir
|
|
|
|
}
|
2021-04-20 06:25:57 +08:00
|
|
|
}
|