mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-10-30 08:40:52 +08:00
Fix not found and loading error screens
Signed-off-by: Rūdolfs Ošiņš <rudolfs@osins.org>
This commit is contained in:
+2
-6
@@ -17,6 +17,7 @@
|
||||
import Issues from "@app/views/projects/Issues.svelte";
|
||||
import NewIssue from "@app/views/projects/Issue/New.svelte";
|
||||
import Nodes from "@app/views/nodes/View.svelte";
|
||||
import NotFound from "@app/views/NotFound.svelte";
|
||||
import Patch from "@app/views/projects/Patch.svelte";
|
||||
import Patches from "@app/views/projects/Patches.svelte";
|
||||
import Session from "@app/views/session/Index.svelte";
|
||||
@@ -24,7 +25,6 @@
|
||||
|
||||
import LoadError from "@app/components/LoadError.svelte";
|
||||
import Loading from "@app/components/Loading.svelte";
|
||||
import NotFound from "@app/components/NotFound.svelte";
|
||||
|
||||
const activeRouteStore = router.activeRouteStore;
|
||||
|
||||
@@ -95,11 +95,7 @@
|
||||
{:else if $activeRouteStore.resource === "loadError"}
|
||||
<LoadError {...$activeRouteStore.params} />
|
||||
{:else if $activeRouteStore.resource === "notFound"}
|
||||
<div class="layout-centered">
|
||||
<NotFound
|
||||
title="Page not found"
|
||||
subtitle={`${$activeRouteStore.params.url.replace("/", "")}`} />
|
||||
</div>
|
||||
<NotFound {...$activeRouteStore.params} />
|
||||
{:else}
|
||||
{unreachable($activeRouteStore)}
|
||||
{/if}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { twemoji } from "@app/lib/utils";
|
||||
|
||||
import Button from "@app/components/Button.svelte";
|
||||
import ErrorMessage from "@app/components/ErrorMessage.svelte";
|
||||
|
||||
export let title: string | undefined = undefined;
|
||||
export let title: string;
|
||||
export let errorMessage: string;
|
||||
export let stackTrace: string;
|
||||
</script>
|
||||
@@ -22,15 +21,9 @@
|
||||
|
||||
<div class="wrapper layout-centered">
|
||||
<div class="emoji" use:twemoji>🏜️</div>
|
||||
{#if title}
|
||||
<div class="title txt-medium txt-bold txt-highlight">
|
||||
{title}
|
||||
</div>
|
||||
{/if}
|
||||
<ErrorMessage message={errorMessage} {stackTrace} />
|
||||
<div style:margin-top="1rem">
|
||||
<Button variant="foreground" on:click={() => window.history.back()}>
|
||||
Back
|
||||
</Button>
|
||||
<div class="title txt-medium txt-bold txt-highlight">
|
||||
{title}
|
||||
</div>
|
||||
|
||||
<ErrorMessage message={errorMessage} {stackTrace} />
|
||||
</div>
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { twemoji } from "@app/lib/utils";
|
||||
|
||||
import Button from "@app/components/Button.svelte";
|
||||
|
||||
export let title: string;
|
||||
export let subtitle: string;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.emoji {
|
||||
display: flex;
|
||||
font-size: var(--font-size-xx-large);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--color-secondary);
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<div class="emoji" use:twemoji>🏜️</div>
|
||||
<div class="title txt-medium txt-bold">{title}</div>
|
||||
<div>{subtitle}</div>
|
||||
|
||||
<div class="actions">
|
||||
<Button variant="foreground" on:click={() => window.history.back()}>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
+6
-6
@@ -76,7 +76,7 @@ export async function navigateToUrl(
|
||||
} else {
|
||||
await navigate(action, {
|
||||
resource: "notFound",
|
||||
params: { url: relativeUrl },
|
||||
params: { title: "Page not found" },
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -241,8 +241,6 @@ export function routeToPath(route: Route): string {
|
||||
return `/session?id=${route.params.id}&sig=${route.params.signature}&pk=${route.params.publicKey}`;
|
||||
} else if (route.resource === "nodes") {
|
||||
return nodePath(route.params.baseUrl);
|
||||
} else if (route.resource === "loadError") {
|
||||
return "";
|
||||
} else if (
|
||||
route.resource === "project.source" ||
|
||||
route.resource === "project.history" ||
|
||||
@@ -254,10 +252,12 @@ export function routeToPath(route: Route): string {
|
||||
route.resource === "project.patch"
|
||||
) {
|
||||
return projectRouteToPath(route);
|
||||
} else if (route.resource === "booting") {
|
||||
} else if (
|
||||
route.resource === "booting" ||
|
||||
route.resource === "notFound" ||
|
||||
route.resource === "loadError"
|
||||
) {
|
||||
return "";
|
||||
} else if (route.resource === "notFound") {
|
||||
return route.params.url;
|
||||
} else {
|
||||
return utils.unreachable(route);
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ interface BootingRoute {
|
||||
resource: "booting";
|
||||
}
|
||||
|
||||
interface NotFoundRoute {
|
||||
export interface NotFoundRoute {
|
||||
resource: "notFound";
|
||||
params: { url: string };
|
||||
params: { title: string };
|
||||
}
|
||||
|
||||
interface SessionRoute {
|
||||
@@ -23,10 +23,10 @@ interface SessionRoute {
|
||||
params: { id: string; signature: string; publicKey: string };
|
||||
}
|
||||
|
||||
export interface LoadError {
|
||||
export interface LoadErrorRoute {
|
||||
resource: "loadError";
|
||||
params: {
|
||||
title?: string;
|
||||
title: string;
|
||||
errorMessage: string;
|
||||
stackTrace: string;
|
||||
};
|
||||
@@ -35,7 +35,7 @@ export interface LoadError {
|
||||
export type Route =
|
||||
| BootingRoute
|
||||
| HomeRoute
|
||||
| LoadError
|
||||
| LoadErrorRoute
|
||||
| NotFoundRoute
|
||||
| ProjectRoute
|
||||
| NodesRoute
|
||||
@@ -44,7 +44,7 @@ export type Route =
|
||||
export type LoadedRoute =
|
||||
| BootingRoute
|
||||
| HomeLoadedRoute
|
||||
| LoadError
|
||||
| LoadErrorRoute
|
||||
| NotFoundRoute
|
||||
| ProjectLoadedRoute
|
||||
| NodesLoadedRoute
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<script lang="ts">
|
||||
import { twemoji } from "@app/lib/utils";
|
||||
|
||||
export let title: string;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.emoji {
|
||||
display: flex;
|
||||
font-size: var(--font-size-xx-large);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--color-secondary);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="layout-centered">
|
||||
<div class="container">
|
||||
<div class="emoji" use:twemoji>🏜️</div>
|
||||
<div class="title txt-medium txt-bold">{title}</div>
|
||||
</div>
|
||||
</div>
|
||||
+18
-26
@@ -1,4 +1,4 @@
|
||||
import type { LoadError } from "@app/lib/router/definitions";
|
||||
import type { LoadErrorRoute } from "@app/lib/router/definitions";
|
||||
import type { ProjectBaseUrl } from "@app/lib/search";
|
||||
import type { WeeklyActivity } from "@app/lib/commit";
|
||||
|
||||
@@ -19,30 +19,22 @@ export interface HomeLoadedRoute {
|
||||
params: { projects: ProjectBaseUrlActivity[] };
|
||||
}
|
||||
|
||||
export async function loadHomeRoute(): Promise<HomeLoadedRoute | LoadError> {
|
||||
try {
|
||||
const projects = await getProjectsFromNodes(config.projects.pinned);
|
||||
const results = await Promise.all(
|
||||
projects.map(async projectNode => {
|
||||
const activity = await loadProjectActivity(
|
||||
projectNode.project.id,
|
||||
projectNode.baseUrl,
|
||||
);
|
||||
return {
|
||||
...projectNode,
|
||||
activity,
|
||||
};
|
||||
}),
|
||||
);
|
||||
export async function loadHomeRoute(): Promise<
|
||||
HomeLoadedRoute | LoadErrorRoute
|
||||
> {
|
||||
const projects = await getProjectsFromNodes(config.projects.pinned);
|
||||
const results = await Promise.all(
|
||||
projects.map(async projectNode => {
|
||||
const activity = await loadProjectActivity(
|
||||
projectNode.project.id,
|
||||
projectNode.baseUrl,
|
||||
);
|
||||
return {
|
||||
...projectNode,
|
||||
activity,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return { resource: "home", params: { projects: results } };
|
||||
} catch (error: any) {
|
||||
return {
|
||||
resource: "loadError",
|
||||
params: {
|
||||
errorMessage: "Could not load pinned projects.",
|
||||
stackTrace: error.stack,
|
||||
},
|
||||
};
|
||||
}
|
||||
return { resource: "home", params: { projects: results } };
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { BaseUrl, Project } from "@httpd-client";
|
||||
import type { LoadError } from "@app/lib/router/definitions";
|
||||
import type { NotFoundRoute } from "@app/lib/router/definitions";
|
||||
import type { WeeklyActivity } from "@app/lib/commit";
|
||||
|
||||
import { HttpdClient } from "@httpd-client";
|
||||
@@ -81,7 +81,7 @@ export function nodePath(baseUrl: BaseUrl) {
|
||||
|
||||
export async function loadNodeRoute(
|
||||
params: NodesRouteParams,
|
||||
): Promise<NodesLoadedRoute | LoadError> {
|
||||
): Promise<NodesLoadedRoute | NotFoundRoute> {
|
||||
const api = new HttpdClient(params.baseUrl);
|
||||
try {
|
||||
const projectPageIndex = 0;
|
||||
@@ -102,11 +102,9 @@ export async function loadNodeRoute(
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
resource: "loadError",
|
||||
resource: "notFound",
|
||||
params: {
|
||||
title: `${params.baseUrl.hostname}:${params.baseUrl.port}`,
|
||||
errorMessage: "Not able to query this node.",
|
||||
stackTrace: error.stack,
|
||||
title: "Node not found",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import type { LoadError } from "@app/lib/router/definitions";
|
||||
import type {
|
||||
LoadErrorRoute,
|
||||
NotFoundRoute,
|
||||
} from "@app/lib/router/definitions";
|
||||
import type {
|
||||
BaseUrl,
|
||||
Blob,
|
||||
@@ -230,13 +233,13 @@ function parseRevisionToOid(
|
||||
|
||||
export async function loadProjectRoute(
|
||||
route: ProjectRoute,
|
||||
): Promise<ProjectLoadedRoute | LoadError> {
|
||||
): Promise<ProjectLoadedRoute | LoadErrorRoute | NotFoundRoute> {
|
||||
const api = new HttpdClient(route.node);
|
||||
try {
|
||||
if (route.resource === "project.source") {
|
||||
return loadTreeView(route);
|
||||
return await loadTreeView(route);
|
||||
} else if (route.resource === "project.history") {
|
||||
return loadHistoryView(route);
|
||||
return await loadHistoryView(route);
|
||||
} else if (route.resource === "project.commit") {
|
||||
const [project, commit] = await Promise.all([
|
||||
api.project.getById(route.project),
|
||||
@@ -252,33 +255,22 @@ export async function loadProjectRoute(
|
||||
},
|
||||
};
|
||||
} else if (route.resource === "project.issue") {
|
||||
try {
|
||||
const [project, issue] = await Promise.all([
|
||||
api.project.getById(route.project),
|
||||
api.project.getIssueById(route.project, route.issue),
|
||||
]);
|
||||
return {
|
||||
resource: "project.issue",
|
||||
params: {
|
||||
baseUrl: route.node,
|
||||
project,
|
||||
issue,
|
||||
},
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
resource: "loadError",
|
||||
params: {
|
||||
title: route.issue,
|
||||
errorMessage: "Not able to load this issue.",
|
||||
stackTrace: error.stack,
|
||||
},
|
||||
};
|
||||
}
|
||||
const [project, issue] = await Promise.all([
|
||||
api.project.getById(route.project),
|
||||
api.project.getIssueById(route.project, route.issue),
|
||||
]);
|
||||
return {
|
||||
resource: "project.issue",
|
||||
params: {
|
||||
baseUrl: route.node,
|
||||
project,
|
||||
issue,
|
||||
},
|
||||
};
|
||||
} else if (route.resource === "project.patch") {
|
||||
return loadPatchView(route);
|
||||
return await loadPatchView(route);
|
||||
} else if (route.resource === "project.issues") {
|
||||
return loadIssuesView(route);
|
||||
return await loadIssuesView(route);
|
||||
} else if (route.resource === "project.newIssue") {
|
||||
const project = await api.project.getById(route.project);
|
||||
return {
|
||||
@@ -289,19 +281,40 @@ export async function loadProjectRoute(
|
||||
},
|
||||
};
|
||||
} else if (route.resource === "project.patches") {
|
||||
return loadPatchesView(route);
|
||||
return await loadPatchesView(route);
|
||||
} else {
|
||||
return unreachable(route);
|
||||
}
|
||||
} catch (error: any) {
|
||||
return {
|
||||
resource: "loadError",
|
||||
params: {
|
||||
title: route.project,
|
||||
errorMessage: "Not able to load this project.",
|
||||
stackTrace: error.stack,
|
||||
},
|
||||
};
|
||||
if (error?.status === 404) {
|
||||
let subject;
|
||||
|
||||
if (route.resource === "project.commit") {
|
||||
subject = "Commit";
|
||||
} else if (route.resource === "project.issue") {
|
||||
subject = "Issue";
|
||||
} else if (route.resource === "project.patch") {
|
||||
subject = "Patch";
|
||||
} else {
|
||||
subject = "Project";
|
||||
}
|
||||
|
||||
return {
|
||||
resource: "notFound",
|
||||
params: {
|
||||
title: `${subject} not found`,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
resource: "loadError",
|
||||
params: {
|
||||
title: "Could not load this project",
|
||||
errorMessage: error.message,
|
||||
stackTrace: error.stack,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -245,6 +245,24 @@ export function appConfigWithFixture() {
|
||||
},
|
||||
projects: {
|
||||
pinned: [
|
||||
{
|
||||
name: "cobs",
|
||||
id: "rad:z3fpY7nttPPa6MBnAv2DccHzQJnqe",
|
||||
baseUrl: {
|
||||
hostname: "127.0.0.1",
|
||||
port: 8081,
|
||||
scheme: "http",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "markdown",
|
||||
id: "rad:z2tchH2Ti4LxRKdssPQYs6VHE5rsg",
|
||||
baseUrl: {
|
||||
hostname: "127.0.0.1",
|
||||
port: 8081,
|
||||
scheme: "http",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "source-browsing",
|
||||
id: "rad:z4BwwjPCFNVP27FwVbDFgwVwkjcir",
|
||||
@@ -349,11 +367,11 @@ export async function createSourceBrowsingFixture(
|
||||
await bob.git(["push", "rad"], { cwd: bobProjectPath });
|
||||
|
||||
await bob.waitForEvent(
|
||||
{ type: "refs-synced", remote: palm.nodeId, rid },
|
||||
{ type: "refsSynced", remote: palm.nodeId, rid },
|
||||
2000,
|
||||
);
|
||||
await bob.waitForEvent(
|
||||
{ type: "refs-synced", remote: alice.nodeId, rid },
|
||||
{ type: "refsSynced", remote: alice.nodeId, rid },
|
||||
2000,
|
||||
);
|
||||
await alice.stopNode();
|
||||
|
||||
@@ -24,29 +24,34 @@ export type RefsUpdate =
|
||||
|
||||
export type NodeEvent =
|
||||
| {
|
||||
type: "refs-fetched";
|
||||
type: "refsFetched";
|
||||
remote: string;
|
||||
rid: string;
|
||||
updated: RefsUpdate[];
|
||||
}
|
||||
| {
|
||||
type: "refs-synced";
|
||||
type: "refsSynced";
|
||||
remote: string;
|
||||
rid: string;
|
||||
}
|
||||
| {
|
||||
type: "seed-discovered";
|
||||
type: "seedDiscovered";
|
||||
rid: string;
|
||||
nid: string;
|
||||
}
|
||||
| {
|
||||
type: "seed-dropped";
|
||||
type: "seedDropped";
|
||||
nid: string;
|
||||
rid: string;
|
||||
}
|
||||
| {
|
||||
type: "peer-connected";
|
||||
type: "peerConnected";
|
||||
nid: string;
|
||||
}
|
||||
| {
|
||||
type: "peerDisconnected";
|
||||
nid: string;
|
||||
reason: string;
|
||||
};
|
||||
|
||||
export interface RoutingEntry {
|
||||
@@ -340,7 +345,7 @@ export class RadiclePeer {
|
||||
});
|
||||
|
||||
await this.waitForEvent(
|
||||
{ type: "seed-discovered", rid, nid: this.nodeId },
|
||||
{ type: "seedDiscovered", rid, nid: this.nodeId },
|
||||
6000,
|
||||
);
|
||||
}
|
||||
@@ -356,11 +361,11 @@ export class RadiclePeer {
|
||||
);
|
||||
|
||||
await this.waitForEvent(
|
||||
{ type: "peer-connected", nid: remote.nodeId },
|
||||
{ type: "peerConnected", nid: remote.nodeId },
|
||||
1000,
|
||||
);
|
||||
await remote.waitForEvent(
|
||||
{ type: "peer-connected", nid: this.nodeId },
|
||||
{ type: "peerConnected", nid: this.nodeId },
|
||||
1000,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ test.use({
|
||||
customAppConfig: true,
|
||||
});
|
||||
|
||||
test("landing page", async ({ page }) => {
|
||||
test("pinned projects", async ({ page }) => {
|
||||
await page.addInitScript(() => {
|
||||
window.initializeTestStubs = () => {
|
||||
window.e2eTestStubs.FakeTimers.install({
|
||||
@@ -19,3 +19,24 @@ test("landing page", async ({ page }) => {
|
||||
await page.goto("/", { waitUntil: "networkidle" });
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("load error", async ({ page }) => {
|
||||
await page.addInitScript(() => {
|
||||
window.initializeTestStubs = () => {
|
||||
window.e2eTestStubs.FakeTimers.install({
|
||||
now: new Date("November 24 2022 12:00:00").valueOf(),
|
||||
shouldClearNativeTimers: true,
|
||||
shouldAdvanceTime: false,
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
await page.route(
|
||||
"**/api/v1/projects/rad:z4BwwjPCFNVP27FwVbDFgwVwkjcir",
|
||||
route => route.fulfill({ status: 500 }),
|
||||
);
|
||||
|
||||
await page.addInitScript(appConfigWithFixture);
|
||||
await page.goto("/", { waitUntil: "networkidle" });
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
|
||||
@@ -14,3 +14,10 @@ test("node page", async ({ page }) => {
|
||||
await page.goto("/nodes/radicle.local", { waitUntil: "networkidle" });
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("node not found", async ({ page }) => {
|
||||
await page.goto("/nodes/this.node.does.not.exist.xyz", {
|
||||
waitUntil: "networkidle",
|
||||
});
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
import { expect, test } from "@tests/support/fixtures.js";
|
||||
|
||||
test("page not found", async ({ page }) => {
|
||||
await page.goto("/this/page/does/not/exist", {
|
||||
waitUntil: "networkidle",
|
||||
});
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
@@ -6,12 +6,12 @@ import {
|
||||
aliceRemote,
|
||||
} from "@tests/support/fixtures.js";
|
||||
|
||||
test("source tree page", async ({ page }) => {
|
||||
test("source page", async ({ page }) => {
|
||||
await page.goto(sourceBrowsingUrl, { waitUntil: "networkidle" });
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("commits page", async ({ page }) => {
|
||||
test("history page", async ({ page }) => {
|
||||
await page.addInitScript(() => {
|
||||
window.initializeTestStubs = () => {
|
||||
window.e2eTestStubs.FakeTimers.install({
|
||||
@@ -68,3 +68,49 @@ test("diff selection", async ({ page }) => {
|
||||
);
|
||||
await expect(page).toHaveScreenshot({ fullPage: true });
|
||||
});
|
||||
|
||||
test("project load error", async ({ page }) => {
|
||||
await page.goto(
|
||||
`${sourceBrowsingUrl}/remotes/zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz`,
|
||||
{ waitUntil: "networkidle" },
|
||||
);
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("project not found", async ({ page }) => {
|
||||
await page.goto(`/nodes/127.0.0.1/rad:z4Vzzzzzzzzzzzzzzzzzzzzzzzzzz`, {
|
||||
waitUntil: "networkidle",
|
||||
});
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("file not found", async ({ page }) => {
|
||||
await page.goto(`${sourceBrowsingUrl}/tree/this.file.does.not.exist`, {
|
||||
waitUntil: "networkidle",
|
||||
});
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("commit not found", async ({ page }) => {
|
||||
await page.goto(
|
||||
`${sourceBrowsingUrl}/commits/0000000000000000000000000000000000000000`,
|
||||
{ waitUntil: "networkidle" },
|
||||
);
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("issue not found", async ({ page }) => {
|
||||
await page.goto(
|
||||
`${sourceBrowsingUrl}/issues/0000000000000000000000000000000000000000`,
|
||||
{ waitUntil: "networkidle" },
|
||||
);
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("patch not found", async ({ page }) => {
|
||||
await page.goto(
|
||||
`${sourceBrowsingUrl}/patches/0000000000000000000000000000000000000000`,
|
||||
{ waitUntil: "networkidle" },
|
||||
);
|
||||
await expect(page).toHaveScreenshot();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user