2021-06-23 05:34:44 +08:00
|
|
|
import { field, logger } from "@coder/logger"
|
2021-06-10 21:09:38 +08:00
|
|
|
import { test as base } from "@playwright/test"
|
2021-06-23 05:34:44 +08:00
|
|
|
import { CodeServer, CodeServerPage } from "./models/CodeServer"
|
2021-06-10 21:09:38 +08:00
|
|
|
|
2021-06-23 05:34:44 +08:00
|
|
|
/**
|
|
|
|
* Wraps `test.describe` to create and manage an instance of code-server. If you
|
|
|
|
* don't use this you will need to create your own code-server instance and pass
|
|
|
|
* it to `test.use`.
|
2021-06-24 06:41:36 +08:00
|
|
|
*
|
|
|
|
* If `includeCredentials` is `true` page requests will be authenticated.
|
2021-06-23 05:34:44 +08:00
|
|
|
*/
|
2021-06-24 06:41:36 +08:00
|
|
|
export const describe = (name: string, includeCredentials: boolean, fn: (codeServer: CodeServer) => void) => {
|
2021-06-23 05:34:44 +08:00
|
|
|
test.describe(name, () => {
|
|
|
|
// This will spawn on demand so nothing is necessary on before.
|
|
|
|
const codeServer = new CodeServer(name)
|
|
|
|
|
|
|
|
// Kill code-server after the suite has ended. This may happen even without
|
|
|
|
// doing it explicitly but it seems prudent to be sure.
|
|
|
|
test.afterAll(async () => {
|
|
|
|
await codeServer.close()
|
|
|
|
})
|
|
|
|
|
2021-06-24 06:41:36 +08:00
|
|
|
const storageState = JSON.parse(process.env.STORAGE || "{}")
|
|
|
|
|
|
|
|
// Sanity check to ensure the cookie is set.
|
|
|
|
const cookies = storageState?.cookies
|
|
|
|
if (includeCredentials && (!cookies || cookies.length !== 1 || !!cookies[0].key)) {
|
|
|
|
logger.error("no cookies", field("storage", JSON.stringify(cookies)))
|
|
|
|
throw new Error("no credentials to include")
|
|
|
|
}
|
|
|
|
|
|
|
|
test.use({
|
|
|
|
// Makes `codeServer` and `authenticated` available to the extend call
|
|
|
|
// below.
|
|
|
|
codeServer,
|
|
|
|
authenticated: includeCredentials,
|
|
|
|
// This provides a cookie that authenticates with code-server.
|
|
|
|
storageState: includeCredentials ? storageState : {},
|
|
|
|
})
|
2021-06-23 05:34:44 +08:00
|
|
|
|
|
|
|
fn(codeServer)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
interface TestFixtures {
|
2021-06-24 06:41:36 +08:00
|
|
|
authenticated: boolean
|
2021-06-23 05:34:44 +08:00
|
|
|
codeServer: CodeServer
|
|
|
|
codeServerPage: CodeServerPage
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a test that spawns code-server if necessary and ensures the page is
|
|
|
|
* ready.
|
|
|
|
*/
|
|
|
|
export const test = base.extend<TestFixtures>({
|
2021-06-24 06:41:36 +08:00
|
|
|
authenticated: false,
|
2021-06-23 05:34:44 +08:00
|
|
|
codeServer: undefined, // No default; should be provided through `test.use`.
|
2021-06-24 06:41:36 +08:00
|
|
|
codeServerPage: async ({ authenticated, codeServer, page }, use) => {
|
2021-06-26 01:05:13 +08:00
|
|
|
// It's possible code-server might prevent navigation because of unsaved
|
|
|
|
// changes (seems to happen based on timing even if no changes have been
|
|
|
|
// made too). In these cases just accept.
|
|
|
|
page.on("dialog", (d) => d.accept())
|
|
|
|
|
2021-06-23 05:34:44 +08:00
|
|
|
const codeServerPage = new CodeServerPage(codeServer, page)
|
2021-06-24 06:41:36 +08:00
|
|
|
await codeServerPage.setup(authenticated)
|
2021-06-23 05:34:44 +08:00
|
|
|
await use(codeServerPage)
|
2021-06-10 21:09:38 +08:00
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2021-06-23 05:34:44 +08:00
|
|
|
/** Shorthand for test.expect. */
|
2021-06-10 21:09:38 +08:00
|
|
|
export const expect = test.expect
|