From fe4ccde080ed99b7019e2f0112089147407096dd Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 15 Sep 2022 16:38:15 +0000 Subject: [PATCH 1/5] chore: update cSpell words --- .vscode/settings.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index c328f9a746da9..40dff72a7aecc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,8 @@ "circbuf", "cliflag", "cliui", + "codecov", + "Codespaces", "coderd", "coderdtest", "codersdk", @@ -80,6 +82,7 @@ "ptty", "ptys", "ptytest", + "quickstart", "reconfig", "retrier", "rpty", @@ -117,10 +120,12 @@ "tstun", "turnconn", "typegen", + "typesafe", "unconvert", "Untar", "Userspace", "VMID", + "walkthrough", "weblinks", "webrtc", "wgcfg", From b23f35f79bbf9f210debe5354ffba345b126c8f4 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 15 Sep 2022 16:55:04 +0000 Subject: [PATCH 2/5] chore: add ignorePaths for cSpell --- .vscode/settings.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 40dff72a7aecc..726e2a012112f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -145,6 +145,10 @@ "xstate", "yamux" ], + "cSpell.ignorePaths": [ + "site/package.json", + ".vscode/settings.json" + ], "emeraldwalk.runonsave": { "commands": [ { From e6a5499cef22060ed2ad75e9ba49f817decb0cd7 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 15 Sep 2022 16:55:29 +0000 Subject: [PATCH 3/5] fix: update isNotificationTextPrefixed This removes an eslint-disable rule and adds two new tests to ensure isNotificationTextPrefixed is working as expected. --- .../components/GlobalSnackbar/utils.test.ts | 24 +++++++++++++++++++ site/src/components/GlobalSnackbar/utils.ts | 6 +++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/site/src/components/GlobalSnackbar/utils.test.ts b/site/src/components/GlobalSnackbar/utils.test.ts index 32fa8ce663d1f..c49e162079219 100644 --- a/site/src/components/GlobalSnackbar/utils.test.ts +++ b/site/src/components/GlobalSnackbar/utils.test.ts @@ -4,6 +4,7 @@ import { isNotificationTextPrefixed, MsgType, NotificationMsg, + NotificationTextPrefixed, SnackbarEventType, } from "./utils" @@ -17,6 +18,29 @@ describe("Snackbar", () => { // When const isTextPrefixed = isNotificationTextPrefixed(msg) + // Then + expect(isTextPrefixed).toBe(false) + }) + it("returns true if prefixed", () => { + // Given + const msg: NotificationTextPrefixed = { + prefix: "warning", + text: "careful with this workspace", + } + + // When + const isTextPrefixed = isNotificationTextPrefixed(msg) + + // Then + expect(isTextPrefixed).toBe(true) + }) + it("returns false if not prefixed", () => { + // Given + const msg = "plain ol' message" + + // When + const isTextPrefixed = isNotificationTextPrefixed(msg) + // Then expect(isTextPrefixed).toBe(false) }) diff --git a/site/src/components/GlobalSnackbar/utils.ts b/site/src/components/GlobalSnackbar/utils.ts index fea01718a7cf4..ac5e79cf9fc58 100644 --- a/site/src/components/GlobalSnackbar/utils.ts +++ b/site/src/components/GlobalSnackbar/utils.ts @@ -27,8 +27,10 @@ export const isNotificationText = (msg: AdditionalMessage): msg is string => { export const isNotificationTextPrefixed = ( msg: AdditionalMessage | null, ): msg is NotificationTextPrefixed => { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - return typeof (msg as NotificationTextPrefixed)?.prefix !== "undefined" + if (msg) { + return typeof msg !== "string" && Object.prototype.hasOwnProperty.call(msg, "prefix") + } + return false } export const isNotificationList = (msg: AdditionalMessage): msg is string[] => { From 609e7d57c5f48ed75f709c4e62aa018dd3a89487 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 15 Sep 2022 19:17:50 +0000 Subject: [PATCH 4/5] fix(e2e): remove filter in workspacesPage --- site/e2e/tests/login.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/e2e/tests/login.spec.ts b/site/e2e/tests/login.spec.ts index 0e6482e602072..7127f84e9562e 100644 --- a/site/e2e/tests/login.spec.ts +++ b/site/e2e/tests/login.spec.ts @@ -10,7 +10,7 @@ test("Login takes user to /workspaces", async ({ baseURL, page }) => { const signInPage = new SignInPage(baseURL, page) await signInPage.submitBuiltInAuthentication(email, password) - const workspacesPage = new WorkspacesPage(baseURL, page, "?filter=owner%3Ame") + const workspacesPage = new WorkspacesPage(baseURL, page) await waitForClientSideNavigation(page, { to: workspacesPage.url }) await page.waitForSelector("text=Workspaces") From 6a7c46d348791daa66b90da4804af912bfe4b17a Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 15 Sep 2022 19:48:47 +0000 Subject: [PATCH 5/5] refactor: remove waitForClientSideNavigation --- site/e2e/tests/login.spec.ts | 6 +-- site/e2e/util.ts | 91 ------------------------------------ 2 files changed, 1 insertion(+), 96 deletions(-) delete mode 100644 site/e2e/util.ts diff --git a/site/e2e/tests/login.spec.ts b/site/e2e/tests/login.spec.ts index 7127f84e9562e..2b3d266704765 100644 --- a/site/e2e/tests/login.spec.ts +++ b/site/e2e/tests/login.spec.ts @@ -1,7 +1,6 @@ import { test } from "@playwright/test" import { email, password } from "../constants" -import { SignInPage, WorkspacesPage } from "../pom" -import { waitForClientSideNavigation } from "./../util" +import { SignInPage } from "../pom" test("Login takes user to /workspaces", async ({ baseURL, page }) => { await page.goto(baseURL + "/", { waitUntil: "networkidle" }) @@ -10,8 +9,5 @@ test("Login takes user to /workspaces", async ({ baseURL, page }) => { const signInPage = new SignInPage(baseURL, page) await signInPage.submitBuiltInAuthentication(email, password) - const workspacesPage = new WorkspacesPage(baseURL, page) - await waitForClientSideNavigation(page, { to: workspacesPage.url }) - await page.waitForSelector("text=Workspaces") }) diff --git a/site/e2e/util.ts b/site/e2e/util.ts deleted file mode 100644 index 072c89eff7fe7..0000000000000 --- a/site/e2e/util.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Page } from "@playwright/test" - -/** - * `timeout(x)` is a helper function to create a promise that resolves after `x` milliseconds. - * - * @param timeoutInMilliseconds Time to wait for promise to resolve - * @returns `Promise` - */ -export const timeout = (timeoutInMilliseconds: number): Promise => { - return new Promise((resolve) => { - setTimeout(resolve, timeoutInMilliseconds) - }) -} - -/** - * `waitFor(f, timeout?)` waits for a predicate to return `true`, running it periodically until it returns `true`. - * - * If `f` never returns `true`, the function will simply return. In other words, the burden is on the consumer - * to check that the predicate is passing (`waitFor` does no validation). - * - * @param f A predicate that returns a `Promise` - * @param timeToWaitInMilliseconds The total time to wait for the condition to be `true`. - * @returns - */ -export const waitFor = async ( - f: () => Promise, - timeToWaitInMilliseconds = 30000, -): Promise => { - let elapsedTime = 0 - const timeToWaitPerIteration = 1000 - - while (elapsedTime < timeToWaitInMilliseconds) { - const condition = await f() - - if (condition) { - return - } - - await timeout(timeToWaitPerIteration) - elapsedTime += timeToWaitPerIteration - } -} - -interface WaitForClientSideNavigationOpts { - /** - * from is the page before navigation (the 'current' page) - */ - from?: string - /** - * to is the page after navigation (the 'next' page) - */ - to?: string -} - -/** - * waitForClientSideNavigation waits for the url to change from opts.from to - * opts.to (if specified), as well as a network idle load state. This enhances - * a native playwright check for navigation or loadstate. - * - * @remark This is necessary in a client-side SPA world since playwright - * waitForNavigation waits for load events on the DOM (ex: after a page load - * from the server). - */ -export const waitForClientSideNavigation = async ( - page: Page, - opts: WaitForClientSideNavigationOpts, -): Promise => { - console.info(`--- waitForClientSideNavigation: start`) - - await Promise.all([ - waitFor(() => { - const conditions: boolean[] = [] - - if (opts.from) { - conditions.push(page.url() !== opts.from) - } - - if (opts.to) { - conditions.push(page.url() === opts.to) - } - - const unmetConditions = conditions.filter((condition) => !condition) - console.info(`--- waitForClientSideNavigation: ${unmetConditions.length} conditions not met`) - - return Promise.resolve(unmetConditions.length === 0) - }), - page.waitForLoadState("networkidle"), - ]) - - console.info(`--- waitForClientSideNavigation: done`) -}