Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Refactor visual tests
Rūdolfs Ošiņš committed 2 years ago
commit 5684b8ef42c17f320b9c005c6f25936a93e516d2
parent e194de4218866d202508d15ccd604390f9467e7c
18 files changed +497 -540
modified .github/workflows/check-visual.yml
@@ -46,7 +46,7 @@ jobs:

      - name: Install Playwright browsers
        if: steps.playwright-dep-cache.outputs.cache-hit != 'true'
-
        run: npx playwright install chromium
+
        run: npx playwright install chromium webkit --with-deps

      - name: Install Radicle binaries
        run: |
@@ -57,9 +57,9 @@ jobs:
      - name: Run Playwright tests
        run: |
          if [ ${{ github.ref }} = "refs/heads/master" ]; then
-
            npm run test:e2e -- --project visual --update-snapshots || true;
+
            npm run test:e2e -- --project visual-desktop visual-mobile --update-snapshots || true;
          else
-
            npm run test:e2e -- --project visual;
+
            npm run test:e2e -- --project visual-desktop visual-mobile;
          fi

      # We don't care about logs in visual snapshot tests, only the images.
modified playwright.config.ts
@@ -41,7 +41,7 @@ const config: PlaywrightTestConfig = {
      },
    },
    {
-
      name: "visual",
+
      name: "visual-desktop",
      timeout: 60_000,
      expect: {
        timeout: 30_000,
@@ -51,13 +51,32 @@ const config: PlaywrightTestConfig = {
          animations: "disabled",
        },
      },
-
      testDir: "./tests/visual",
-
      snapshotDir: "./tests/visual/snapshots",
+
      testDir: "./tests/visual/desktop",
+
      snapshotDir: "./tests/visual/snapshots/desktop",
      retries: 0,
      use: {
-
        ...devices["Desktop Chrome"],
+
        ...devices["Desktop Chrome HiDPI"],
+
        actionTimeout: 0,
+
        trace: "off",
+
      },
+
    },
+
    {
+
      name: "visual-mobile",
+
      timeout: 60_000,
+
      expect: {
+
        timeout: 30_000,
+
        toHaveScreenshot: {
+
          threshold: 0.01,
+
          scale: "device",
+
          animations: "disabled",
+
        },
+
      },
+
      testDir: "./tests/visual/mobile",
+
      snapshotDir: "./tests/visual/snapshots/mobile",
+
      retries: 0,
+
      use: {
+
        ...devices["iPhone 13 Mini"],
        actionTimeout: 0,
-
        deviceScaleFactor: 2,
        trace: "off",
      },
    },
modified tests/support/fixtures.ts
@@ -3,7 +3,7 @@ import type * as Stream from "node:stream";
import * as Fs from "node:fs/promises";
import * as Path from "node:path";
import assert from "node:assert";
-
import { test as base, expect, type ViewportSize } from "@playwright/test";
+
import { test as base, expect } from "@playwright/test";

import * as Process from "./process.js";
import * as issue from "@tests/support/cobs/issue.js";
@@ -18,13 +18,6 @@ export { expect };

const fixturesDir = Path.resolve(supportDir, "..", "./fixtures");

-
type ViewportTypes = "iPhoneXR" | "Desktop";
-

-
export const viewportSizes: Record<ViewportTypes, ViewportSize> = {
-
  iPhoneXR: { width: 414, height: 896 },
-
  Desktop: { width: 1280, height: 720 },
-
};
-

export const test = base.extend<{
  // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
  forAllTests: void;
deleted tests/visual/cob.spec.ts
@@ -1,104 +0,0 @@
-
import { test, expect, cobUrl } from "@tests/support/fixtures.js";
-

-
test.beforeEach(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,
-
      });
-
    };
-
  });
-
});
-

-
test("issues page", async ({ page }) => {
-
  await page.goto(`${cobUrl}/issues`, { waitUntil: "networkidle" });
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-

-
  await page.goto(`${cobUrl}/issues?state=closed`, {
-
    waitUntil: "networkidle",
-
  });
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
});
-

-
test("issue page", async ({ page }) => {
-
  const issues = [
-
    ["This title has markdown", "open"],
-
    ["A closed issue", "closed"],
-
    ["A solved issue", "closed"],
-
  ];
-
  for (const [name, state] of issues) {
-
    await page.goto(`${cobUrl}/issues?state=${state}`);
-
    await page.getByRole("link", { name }).click();
-
    await page.getByRole("heading", { name }).waitFor();
-
    await expect(page).toHaveScreenshot({ fullPage: true });
-
  }
-
});
-

-
test("patches page", async ({ page }) => {
-
  await page.goto(`${cobUrl}/patches`, {
-
    waitUntil: "networkidle",
-
  });
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
  await page.goto(`${cobUrl}/patches?state=draft`, {
-
    waitUntil: "networkidle",
-
  });
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
  await page.goto(`${cobUrl}/patches?state=archived`, {
-
    waitUntil: "networkidle",
-
  });
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
  await page.goto(`${cobUrl}/patches?state=merged`, {
-
    waitUntil: "networkidle",
-
  });
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
});
-

-
test("patch page", async ({ page }) => {
-
  const patches = [
-
    ["This patch is going to be reverted to draft", "draft"],
-
    ["This patch is going to be archived", "archived"],
-
    ["Let's add a README", "merged"],
-
    ["Add subtitle to README", "open"],
-
    ["Taking another stab at the README", "open"],
-
  ];
-

-
  for (const [name, state] of patches) {
-
    await page.goto(`${cobUrl}/patches?state=${state}`);
-
    await page.getByRole("link", { name }).click();
-
    await page.getByRole("heading", { name }).waitFor();
-
    await expect(page).toHaveScreenshot({ fullPage: true });
-
  }
-

-
  // Expand commit messages to check border line height
-
  await page.getByLabel("expand").nth(2).click();
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-

-
  // Expand the commit message in the first revision
-
  await page.getByLabel("expand").first().click();
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
  await page.getByLabel("expand").nth(1).click();
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
  await page.getByRole("button", { name: "Changes" }).click();
-
  await page
-
    .getByText("1 file changed with 5 insertions and 1 deletion")
-
    .waitFor();
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
});
-

-
test("failed diff loading for a specific revision", async ({ page }) => {
-
  await page.route(
-
    "**/api/v1/projects/rad:z3fpY7nttPPa6MBnAv2DccHzQJnqe/diff/38c225e2a0b47ba59def211f4e4825c31d9463ec/9898da6155467adad511f63bf0fb5aa4156b92ef",
-
    route => route.fulfill({ status: 500 }),
-
  );
-

-
  await page.goto(`${cobUrl}/patches`);
-
  await page
-
    .getByRole("link", { name: "Taking another stab at the README" })
-
    .click();
-
  await page
-
    .getByRole("heading", { name: "Taking another stab at the README" })
-
    .waitFor();
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
});
added tests/visual/desktop/cob.spec.ts
@@ -0,0 +1,104 @@
+
import { test, expect, cobUrl } from "@tests/support/fixtures.js";
+

+
test.beforeEach(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,
+
      });
+
    };
+
  });
+
});
+

+
test("issues page", async ({ page }) => {
+
  await page.goto(`${cobUrl}/issues`, { waitUntil: "networkidle" });
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+

+
  await page.goto(`${cobUrl}/issues?state=closed`, {
+
    waitUntil: "networkidle",
+
  });
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
});
+

+
test("issue page", async ({ page }) => {
+
  const issues = [
+
    ["This title has markdown", "open"],
+
    ["A closed issue", "closed"],
+
    ["A solved issue", "closed"],
+
  ];
+
  for (const [name, state] of issues) {
+
    await page.goto(`${cobUrl}/issues?state=${state}`);
+
    await page.getByRole("link", { name }).click();
+
    await page.getByRole("heading", { name }).waitFor();
+
    await expect(page).toHaveScreenshot({ fullPage: true });
+
  }
+
});
+

+
test("patches page", async ({ page }) => {
+
  await page.goto(`${cobUrl}/patches`, {
+
    waitUntil: "networkidle",
+
  });
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
  await page.goto(`${cobUrl}/patches?state=draft`, {
+
    waitUntil: "networkidle",
+
  });
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
  await page.goto(`${cobUrl}/patches?state=archived`, {
+
    waitUntil: "networkidle",
+
  });
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
  await page.goto(`${cobUrl}/patches?state=merged`, {
+
    waitUntil: "networkidle",
+
  });
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
});
+

+
test("patch page", async ({ page }) => {
+
  const patches = [
+
    ["This patch is going to be reverted to draft", "draft"],
+
    ["This patch is going to be archived", "archived"],
+
    ["Let's add a README", "merged"],
+
    ["Add subtitle to README", "open"],
+
    ["Taking another stab at the README", "open"],
+
  ];
+

+
  for (const [name, state] of patches) {
+
    await page.goto(`${cobUrl}/patches?state=${state}`);
+
    await page.getByRole("link", { name }).click();
+
    await page.getByRole("heading", { name }).waitFor();
+
    await expect(page).toHaveScreenshot({ fullPage: true });
+
  }
+

+
  // Expand commit messages to check border line height
+
  await page.getByLabel("expand").nth(2).click();
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+

+
  // Expand the commit message in the first revision
+
  await page.getByLabel("expand").first().click();
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
  await page.getByLabel("expand").nth(1).click();
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
  await page.getByRole("button", { name: "Changes" }).click();
+
  await page
+
    .getByText("1 file changed with 5 insertions and 1 deletion")
+
    .waitFor();
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
});
+

+
test("failed diff loading for a specific revision", async ({ page }) => {
+
  await page.route(
+
    "**/api/v1/projects/rad:z3fpY7nttPPa6MBnAv2DccHzQJnqe/diff/38c225e2a0b47ba59def211f4e4825c31d9463ec/9898da6155467adad511f63bf0fb5aa4156b92ef",
+
    route => route.fulfill({ status: 500 }),
+
  );
+

+
  await page.goto(`${cobUrl}/patches`);
+
  await page
+
    .getByRole("link", { name: "Taking another stab at the README" })
+
    .click();
+
  await page
+
    .getByRole("heading", { name: "Taking another stab at the README" })
+
    .waitFor();
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
});
added tests/visual/desktop/landingPage.spec.ts
@@ -0,0 +1,42 @@
+
import { test, expect, appConfigWithFixture } from "@tests/support/fixtures.js";
+

+
test.use({
+
  customAppConfig: true,
+
});
+

+
test("pinned projects", 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.addInitScript(appConfigWithFixture);
+
  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, 8090);
+
  await page.goto("/", { waitUntil: "networkidle" });
+
  await expect(page).toHaveScreenshot();
+
});
added tests/visual/desktop/markdown.spec.ts
@@ -0,0 +1,148 @@
+
import type { Page } from "@playwright/test";
+
import { test, expect, markdownUrl } from "@tests/support/fixtures.js";
+

+
async function goToSection(section: string, page: Page) {
+
  await page.goto(`${markdownUrl}/tree/main/cheatsheet.md`, {
+
    waitUntil: "networkidle",
+
  });
+
  await page.getByText("Collapse").click();
+
  await page.locator(`[href="${section}"]`).click();
+
}
+

+
test.describe("markdown rendering basics", async () => {
+
  test.use({ viewport: { width: 1600, height: 1200 } });
+

+
  test("table of contents", async ({ page }) => {
+
    await page.goto(
+
      `${markdownUrl}/tree/main/cheatsheet.md#table-of-contents`,
+
      {
+
        waitUntil: "networkidle",
+
      },
+
    );
+
    await page.getByText("Collapse").click();
+
    await expect(page.getByText("Table of Contents")).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("headers", async ({ page }) => {
+
    await goToSection("#headers", page);
+
    await expect(page.getByText("###### H6")).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("emphasis", async ({ page }) => {
+
    await goToSection("#emphasis", page);
+
    await expect(page.getByText("Emphasis, aka").first()).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("lists", async ({ page }) => {
+
    await goToSection("#lists", page);
+
    await expect(page.getByText("First ordered list").first()).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("links", async ({ page }) => {
+
    await goToSection("#links", page);
+
    await expect(page.getByText("There are two ways")).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("images", async ({ page }) => {
+
    await goToSection("#images", page);
+
    await expect(page.getByText("Here's our logo").first()).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("code and syntax highlighting", async ({ page }) => {
+
    await goToSection("#code", page);
+
    await expect(page.getByText("Code blocks are part")).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("tables", async ({ page }) => {
+
    await goToSection("#tables", page);
+
    await expect(page.getByText("Tables aren't part of the")).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("blockquotes", async ({ page }) => {
+
    await goToSection("#blockquotes", page);
+
    await expect(page.getByText("Blockquotes are").first()).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("inline HTML", async ({ page }) => {
+
    await goToSection("#html", page);
+
    await expect(page.getByText("You can also use raw HTML")).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("horizontal rule", async ({ page }) => {
+
    await goToSection("#hr", page);
+
    await expect(page.getByText("Three or more...").first()).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("line breaks", async ({ page }) => {
+
    await goToSection("#lines", page);
+
    await expect(page.getByText("My basic recommendation")).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+

+
  test("videos", async ({ page }) => {
+
    await goToSection("#videos", page);
+
    await expect(page.getByText("They can't be added")).toBeVisible();
+
    await expect(page).toHaveScreenshot();
+
  });
+
});
+

+
test("footnotes", async ({ page }) => {
+
  await page.goto(`${markdownUrl}/tree/main/footnotes.md#footnotes`, {
+
    waitUntil: "networkidle",
+
  });
+
  await expect(
+
    page.locator(
+
      "text=This is an example footnote[0]. And some radicle[1] examples.",
+
    ),
+
  ).toBeVisible();
+
  await page.getByText("Collapse").click();
+
  await expect(page.getByText("0. https://example.com ↩")).toBeVisible();
+
  await expect(page.getByText("1. https://radicle.xyz ↩")).toBeVisible();
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+

+
  await page.getByText("Plain").click();
+
  await expect(
+
    page.locator(
+
      "text=This is an example footnote[^0]. And some radicle[^1] examples.",
+
    ),
+
  ).toBeVisible();
+
  await expect(page.getByText("[^0]: https://example.com")).toBeVisible();
+
  await expect(page.getByText("[^1]: https://radicle.xyz")).toBeVisible();
+
});
+

+
test("math", async ({ page }) => {
+
  await page.goto(`${markdownUrl}/tree/main/math.md`, {
+
    waitUntil: "networkidle",
+
  });
+
  await expect(page.getByText("The Cauchy-Schwarz Inequality")).toBeVisible();
+
  await page.getByText("Collapse").click();
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
});
+

+
test("relative image not able to being loaded", async ({ page }) => {
+
  await page.goto(`${markdownUrl}/tree/main/loading-image.md`, {
+
    waitUntil: "networkidle",
+
  });
+
  await page.getByText("Collapse").click();
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
});
+

+
test("markdown in issues is not overflowing", async ({ page }) => {
+
  await page.goto(`${markdownUrl}/issues`, {
+
    waitUntil: "networkidle",
+
  });
+
  await page.getByText("Collapse").click();
+
  await page.getByRole("link", { name: "This title has markdown" }).click();
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
});
added tests/visual/desktop/node.spec.ts
@@ -0,0 +1,39 @@
+
import { test, expect } from "@tests/support/fixtures.js";
+
import { createProject } from "@tests/support/project.js";
+

+
test("node page", 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.goto("/nodes/radicle.local", { waitUntil: "networkidle" });
+
  await expect(page).toHaveScreenshot();
+
});
+

+
test("private projects", async ({ page, authenticatedPeer }) => {
+
  await createProject(authenticatedPeer, {
+
    name: "private-project",
+
    visibility: "private",
+
  });
+
  await page.goto("/", { waitUntil: "networkidle" });
+
  await expect(page).toHaveScreenshot();
+

+
  await page.goto(authenticatedPeer.uiUrl(), { waitUntil: "networkidle" });
+
  await expect(page).toHaveScreenshot();
+

+
  await page.getByRole("link", { name: "private-project Private" }).click();
+
  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();
+
});
added tests/visual/desktop/notFound.spec.ts
@@ -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();
+
});
added tests/visual/desktop/project.spec.ts
@@ -0,0 +1,124 @@
+
import {
+
  test,
+
  expect,
+
  cobUrl,
+
  sourceBrowsingUrl,
+
  aliceRemote,
+
  markdownUrl,
+
} from "@tests/support/fixtures.js";
+

+
test("source page", async ({ page }) => {
+
  await page.goto(sourceBrowsingUrl, { waitUntil: "networkidle" });
+
  await expect(page).toHaveScreenshot();
+
});
+

+
test("history page", 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.goto(
+
    `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(8)}/history`,
+
    {
+
      waitUntil: "networkidle",
+
    },
+
  );
+

+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
});
+

+
test("commit page", 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.goto(
+
    `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
+
      8,
+
    )}/commits/1aded56c3ad55299df9f06c326af50b802a05949`,
+
  );
+
  await expect(page.getByText("subconscious.txt added")).toBeVisible();
+
  await expect(page).toHaveScreenshot({ fullPage: true });
+
});
+

+
test("diff selection", 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.goto(
+
    `${cobUrl}/patches/a27a6b77246e6ada5e81bc8764b5f5c593be80a5?tab=changes#README.md:H0L0H0L3`,
+
  );
+
  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("readme not found", async ({ page }) => {
+
  await page.goto(`${markdownUrl}/tree`, {
+
    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();
+
});
deleted tests/visual/landingPage.spec.ts
@@ -1,42 +0,0 @@
-
import { test, expect, appConfigWithFixture } from "@tests/support/fixtures.js";
-

-
test.use({
-
  customAppConfig: true,
-
});
-

-
test("pinned projects", 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.addInitScript(appConfigWithFixture);
-
  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, 8090);
-
  await page.goto("/", { waitUntil: "networkidle" });
-
  await expect(page).toHaveScreenshot();
-
});
deleted tests/visual/markdown.spec.ts
@@ -1,194 +0,0 @@
-
import type { Page } from "@playwright/test";
-
import {
-
  test,
-
  expect,
-
  markdownUrl,
-
  viewportSizes,
-
} from "@tests/support/fixtures.js";
-

-
async function goToSection(section: string, page: Page) {
-
  await page.goto(`${markdownUrl}/tree/main/cheatsheet.md`, {
-
    waitUntil: "networkidle",
-
  });
-
  await page.locator(`[href="${section}"]`).click();
-
}
-

-
const viewportWidth = viewportSizes["Desktop"].width;
-

-
test.describe("markdown rendering", async () => {
-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 450 } });
-
    test("table of contents", async ({ page }) => {
-
      await page.goto(
-
        `${markdownUrl}/tree/main/cheatsheet.md#table-of-contents`,
-
        {
-
          waitUntil: "networkidle",
-
        },
-
      );
-
      await expect(page.getByText("Table of Contents")).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({
-
      viewport: { width: viewportWidth, height: 1030 },
-
    });
-
    test("headers", async ({ page }) => {
-
      await goToSection("#headers", page);
-
      await expect(page.getByText("###### H6")).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 470 } });
-
    test("emphasis", async ({ page }) => {
-
      await goToSection("#emphasis", page);
-
      await expect(page.getByText("Emphasis, aka").first()).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 1100 } });
-
    test("lists", async ({ page }) => {
-
      await goToSection("#lists", page);
-
      await expect(page.getByText("First ordered list").first()).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 1024 } });
-
    test("links", async ({ page }) => {
-
      await goToSection("#links", page);
-
      await expect(page.getByText("There are two ways")).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 520 } });
-
    test("images", async ({ page }) => {
-
      await goToSection("#images", page);
-
      await expect(page.getByText("Here's our logo").first()).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 1130 } });
-
    test("code and syntax highlighting", async ({ page }) => {
-
      await goToSection("#code", page);
-
      await expect(page.getByText("Code blocks are part")).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test("footnotes", async ({ page }) => {
-
      await page.goto(`${markdownUrl}/tree/main/footnotes.md#footnotes`, {
-
        waitUntil: "networkidle",
-
      });
-
      await expect(
-
        page.locator(
-
          "text=This is an example footnote[0]. And some radicle[1] examples.",
-
        ),
-
      ).toBeVisible();
-
      await expect(page.getByText("0. https://example.com ↩")).toBeVisible();
-
      await expect(page.getByText("1. https://radicle.xyz ↩")).toBeVisible();
-
      await expect(page).toHaveScreenshot({ fullPage: true });
-

-
      await page.getByText("Plain").click();
-
      await expect(
-
        page.locator(
-
          "text=This is an example footnote[^0]. And some radicle[^1] examples.",
-
        ),
-
      ).toBeVisible();
-
      await expect(page.getByText("[^0]: https://example.com")).toBeVisible();
-
      await expect(page.getByText("[^1]: https://radicle.xyz")).toBeVisible();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test("math", async ({ page }) => {
-
      await page.goto(`${markdownUrl}/tree/main/math.md`, {
-
        waitUntil: "networkidle",
-
      });
-
      await expect(
-
        page.getByText("The Cauchy-Schwarz Inequality"),
-
      ).toBeVisible();
-
      await expect(page).toHaveScreenshot({ fullPage: true });
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 1100 } });
-
    test("tables", async ({ page }) => {
-
      await goToSection("#tables", page);
-
      await expect(page.getByText("Tables aren't part of the")).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 450 } });
-
    test("blockquotes", async ({ page }) => {
-
      await goToSection("#blockquotes", page);
-
      await expect(page.getByText("Blockquotes are").first()).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 510 } });
-
    test("inline HTML", async ({ page }) => {
-
      await goToSection("#html", page);
-
      await expect(page.getByText("You can also use raw HTML")).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 710 } });
-
    test("horizontal rule", async ({ page }) => {
-
      await goToSection("#hr", page);
-
      await expect(page.getByText("Three or more...").first()).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 625 } });
-
    test("line breaks", async ({ page }) => {
-
      await goToSection("#lines", page);
-
      await expect(page.getByText("My basic recommendation")).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-

-
  test.describe(async () => {
-
    test.use({ viewport: { width: viewportWidth, height: 500 } });
-
    test("videos", async ({ page }) => {
-
      await goToSection("#videos", page);
-
      await expect(page.getByText("They can't be added")).toBeVisible();
-
      await expect(page).toHaveScreenshot();
-
    });
-
  });
-
});
-

-
test("relative image not able to being loaded", async ({ page }) => {
-
  await page.goto(`${markdownUrl}/tree/main/loading-image.md`, {
-
    waitUntil: "networkidle",
-
  });
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
});
-

-
test("markdown in issues is not overflowing", async ({ page }) => {
-
  await page.goto(`${markdownUrl}/issues`, {
-
    waitUntil: "networkidle",
-
  });
-
  await page.getByRole("link", { name: "This title has markdown" }).click();
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
});
modified tests/visual/mobile/cob.spec.ts
@@ -1,11 +1,4 @@
-
import {
-
  test,
-
  expect,
-
  cobUrl,
-
  viewportSizes,
-
} from "@tests/support/fixtures.js";
-

-
test.use({ viewport: viewportSizes["iPhoneXR"] });
+
import { test, expect, cobUrl } from "@tests/support/fixtures.js";

test.beforeEach(async ({ page }) => {
  await page.addInitScript(() => {
@@ -68,11 +61,12 @@ test("patch page", async ({ page }) => {
    ["This patch is going to be archived", "archived"],
    ["Let's add a README", "merged"],
    ["Add subtitle to README", "open"],
-
    ["Taking another stab at the README", "open"],
  ];

  for (const [name, state] of patches) {
-
    await page.goto(`${cobUrl}/patches?state=${state}`);
+
    await page.goto(`${cobUrl}/patches?state=${state}`, {
+
      waitUntil: "networkidle",
+
    });
    await page.getByRole("link", { name }).click();
    await page.getByRole("heading", { name }).waitFor();
    await expect(page).toHaveScreenshot({ fullPage: true });
modified tests/visual/mobile/project.spec.ts
@@ -3,11 +3,8 @@ import {
  expect,
  sourceBrowsingUrl,
  test,
-
  viewportSizes,
} from "@tests/support/fixtures.js";

-
test.use({ viewport: viewportSizes["iPhoneXR"] });
-

test("source tree page", async ({ page }) => {
  await page.goto(sourceBrowsingUrl, { waitUntil: "networkidle" });
  await expect(page).toHaveScreenshot();
deleted tests/visual/node.spec.ts
@@ -1,39 +0,0 @@
-
import { test, expect } from "@tests/support/fixtures.js";
-
import { createProject } from "@tests/support/project.js";
-

-
test("node page", 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.goto("/nodes/radicle.local", { waitUntil: "networkidle" });
-
  await expect(page).toHaveScreenshot();
-
});
-

-
test("private projects", async ({ page, authenticatedPeer }) => {
-
  await createProject(authenticatedPeer, {
-
    name: "private-project",
-
    visibility: "private",
-
  });
-
  await page.goto("/", { waitUntil: "networkidle" });
-
  await expect(page).toHaveScreenshot();
-

-
  await page.goto(authenticatedPeer.uiUrl(), { waitUntil: "networkidle" });
-
  await expect(page).toHaveScreenshot();
-

-
  await page.getByRole("link", { name: "private-project Private" }).click();
-
  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();
-
});
deleted tests/visual/notFound.spec.ts
@@ -1,8 +0,0 @@
-
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();
-
});
deleted tests/visual/project.spec.ts
@@ -1,124 +0,0 @@
-
import {
-
  test,
-
  expect,
-
  cobUrl,
-
  sourceBrowsingUrl,
-
  aliceRemote,
-
  markdownUrl,
-
} from "@tests/support/fixtures.js";
-

-
test("source page", async ({ page }) => {
-
  await page.goto(sourceBrowsingUrl, { waitUntil: "networkidle" });
-
  await expect(page).toHaveScreenshot();
-
});
-

-
test("history page", 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.goto(
-
    `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(8)}/history`,
-
    {
-
      waitUntil: "networkidle",
-
    },
-
  );
-

-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
});
-

-
test("commit page", 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.goto(
-
    `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
-
      8,
-
    )}/commits/1aded56c3ad55299df9f06c326af50b802a05949`,
-
  );
-
  await expect(page.getByText("subconscious.txt added")).toBeVisible();
-
  await expect(page).toHaveScreenshot({ fullPage: true });
-
});
-

-
test("diff selection", 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.goto(
-
    `${cobUrl}/patches/a27a6b77246e6ada5e81bc8764b5f5c593be80a5?tab=changes#README.md:H0L0H0L3`,
-
  );
-
  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("readme not found", async ({ page }) => {
-
  await page.goto(`${markdownUrl}/tree`, {
-
    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();
-
});
deleted tests/visual/snapshots/.gitkeep