chore: update cSpell and fix isNotificationTextPrefixed (#4076)

* chore: update cSpell words

* chore: add ignorePaths for cSpell

* fix: update isNotificationTextPrefixed

This removes an eslint-disable rule and adds two new tests to ensure
isNotificationTextPrefixed is working as expected.

* fix(e2e): remove filter in workspacesPage
This commit is contained in:
Joe Previte
2022-09-15 16:59:22 -03:00
committed by GitHub
parent 9e9a9e0cd2
commit b8bd3208ca
5 changed files with 38 additions and 98 deletions
+9
View File
@@ -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",
@@ -140,6 +145,10 @@
"xstate",
"yamux"
],
"cSpell.ignorePaths": [
"site/package.json",
".vscode/settings.json"
],
"emeraldwalk.runonsave": {
"commands": [
{
+1 -5
View File
@@ -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, "?filter=owner%3Ame")
await waitForClientSideNavigation(page, { to: workspacesPage.url })
await page.waitForSelector("text=Workspaces")
})
-91
View File
@@ -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<void> => {
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<boolean>`
* @param timeToWaitInMilliseconds The total time to wait for the condition to be `true`.
* @returns
*/
export const waitFor = async (
f: () => Promise<boolean>,
timeToWaitInMilliseconds = 30000,
): Promise<void> => {
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<void> => {
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`)
}
@@ -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)
})
+4 -2
View File
@@ -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[] => {