-
Notifications
You must be signed in to change notification settings - Fork 6k
feat(testing): add e2e tests for code-server and terminal #3169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
2665a4f
feat: add CodeServer page object for e2e tests
jsjoeio 2bf0a0e
refactor: fix tests to check visibility correctly
jsjoeio cc99fdd
feat: add test for terminal echo to file
jsjoeio cb65590
refactor: move tmpdir into src/node/constants
jsjoeio b0ecff3
refactor: globalSetup to use CodeServer model
jsjoeio 7bfdd13
refactor: tmpdir and add to test utils
jsjoeio File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,23 @@ | ||
import { test, expect } from "@playwright/test" | ||
import { CODE_SERVER_ADDRESS } from "../utils/constants" | ||
import { CodeServer } from "./models/CodeServer" | ||
|
||
// This is a "gut-check" test to make sure playwright is working as expected | ||
test("browser should display correct userAgent", async ({ page, browserName }) => { | ||
const displayNames = { | ||
chromium: "Chrome", | ||
firefox: "Firefox", | ||
webkit: "Safari", | ||
} | ||
await page.goto(CODE_SERVER_ADDRESS, { waitUntil: "networkidle" }) | ||
const userAgent = await page.evaluate("navigator.userAgent") | ||
|
||
expect(userAgent).toContain(displayNames[browserName]) | ||
test.describe("browser", () => { | ||
let codeServer: CodeServer | ||
|
||
test.beforeEach(async ({ page }) => { | ||
codeServer = new CodeServer(page) | ||
await codeServer.navigate() | ||
}) | ||
jsjoeio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
test("browser should display correct userAgent", async ({ page, browserName }) => { | ||
const displayNames = { | ||
chromium: "Chrome", | ||
firefox: "Firefox", | ||
webkit: "Safari", | ||
} | ||
const userAgent = await page.evaluate("navigator.userAgent") | ||
|
||
expect(userAgent).toContain(displayNames[browserName]) | ||
}) | ||
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { test, expect } from "@playwright/test" | ||
import { CODE_SERVER_ADDRESS, STORAGE } from "../utils/constants" | ||
import { CodeServer } from "./models/CodeServer" | ||
|
||
test.describe("CodeServer", () => { | ||
// Create a new context with the saved storage state | ||
// so we don't have to logged in | ||
const options: any = {} | ||
let codeServer: CodeServer | ||
|
||
// TODO@jsjoeio | ||
// Fix this once https://github.com/microsoft/playwright-test/issues/240 | ||
// is fixed | ||
if (STORAGE) { | ||
const storageState = JSON.parse(STORAGE) || {} | ||
options.contextOptions = { | ||
storageState, | ||
} | ||
} | ||
|
||
test.beforeEach(async ({ page }) => { | ||
codeServer = new CodeServer(page) | ||
await codeServer.setup() | ||
}) | ||
jsjoeio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
test(`should navigate to ${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) | ||
}) | ||
|
||
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.focusTerminal() | ||
expect(await page.isVisible("#terminal")).toBe(true) | ||
}) | ||
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { Page } from "playwright" | ||
import { CODE_SERVER_ADDRESS } from "../../utils/constants" | ||
// This is a Page Object Model | ||
// We use these to simplify e2e test authoring | ||
// See Playwright docs: https://playwright.dev/docs/pom/ | ||
jsjoeio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
export class CodeServer { | ||
page: Page | ||
|
||
constructor(page: Page) { | ||
this.page = page | ||
} | ||
|
||
/** | ||
* Navigates to CODE_SERVER_ADDRESS | ||
*/ | ||
async navigate() { | ||
await this.page.goto(CODE_SERVER_ADDRESS, { waitUntil: "networkidle" }) | ||
} | ||
|
||
/** | ||
* Checks if the editor is visible | ||
* and reloads until it is | ||
*/ | ||
async reloadUntilEditorIsVisible() { | ||
const 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 | ||
jsjoeio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
while (!editorIsVisible) { | ||
reloadCount += 1 | ||
if (await this.isEditorVisible()) { | ||
console.log(` Editor became visible after ${reloadCount} reloads`) | ||
break | ||
} | ||
// 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.reload({ waitUntil: "load" }) | ||
jsjoeio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
/** | ||
* Checks if the editor is visible | ||
*/ | ||
async isEditorVisible() { | ||
// Make sure the editor actually loaded | ||
// If it's not visible after 5 seconds, something is wrong | ||
await this.page.waitForLoadState("networkidle") | ||
return await this.page.isVisible("div.monaco-workbench", { timeout: 5000 }) | ||
} | ||
|
||
/** | ||
* Focuses Integrated Terminal | ||
* by going to the Application Menu | ||
* and clicking View > Terminal | ||
*/ | ||
async focusTerminal() { | ||
// 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(`Control+Backquote`) | ||
// Wait for terminal to receive focus | ||
await this.page.waitForSelector("div.terminal.xterm.focus") | ||
// Sometimes the terminal reloads | ||
// which is why we wait for it twice | ||
await this.page.waitForSelector("div.terminal.xterm.focus") | ||
return | ||
} | ||
// Open using the manu | ||
// Click [aria-label="Application Menu"] div[role="none"] | ||
await this.page.click('[aria-label="Application Menu"] div[role="none"]') | ||
|
||
// 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") | ||
|
||
// Wait for terminal to receive focus | ||
// Sometimes the terminal reloads once or twice | ||
// which is why we wait for it to have the focus class | ||
await this.page.waitForSelector("div.terminal.xterm.focus") | ||
// Sometimes the terminal reloads | ||
// which is why we wait for it twice | ||
await this.page.waitForSelector("div.terminal.xterm.focus") | ||
} | ||
|
||
/** | ||
* Navigates to CODE_SERVER_ADDRESS | ||
* and reloads until the editor is visible | ||
* | ||
* Helpful for running before tests | ||
*/ | ||
async setup() { | ||
await this.navigate() | ||
await this.reloadUntilEditorIsVisible() | ||
} | ||
jsjoeio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.