Radish alpha
r
rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5
Radicle web interface
Radicle
Git
Remove hash routing
Merged did:key:z6MkkfM3...sVz5 opened 2 years ago

Since we don’t have or want any deployments on IPFS, and we don’t have much use for hash routing else, we can clean up some code and remove some tests.

check check-visual check-unit-test check-httpd-api-unit-test check-e2e check-build

👉 Preview
👉 Workflow runs
👉 Branch on GitHub

12 files changed +203 -411 69429cb0 4bb0e728
modified .github/workflows/check-e2e.yml
@@ -35,9 +35,7 @@ jobs:
          ./scripts/install-binaries;

      - name: Run Playwright tests
-
        run: |
-
          npm run test:e2e -- --project ${{ matrix.browser }};
-
          npm run test:e2e:ipfs -- --project ${{ matrix.browser }};
+
        run: npm run test:e2e -- --project ${{ matrix.browser }}

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
modified package.json
@@ -2,16 +2,13 @@
  "version": "1.0.0",
  "scripts": {
    "start": "vite",
-
    "start:ipfs": "VITE_HASH_ROUTING=1 vite --base ./",
    "serve": "vite preview",
    "build": "vite build && scripts/copy-katex-assets && scripts/install-twemoji-assets",
-
    "build:ipfs": "VITE_HASH_ROUTING=1 vite build --base ./",
    "postinstall": "scripts/copy-katex-assets && scripts/install-twemoji-assets",
    "check": "scripts/check",
    "format": "npx prettier '**/*.@(ts|js|svelte|json|css|html|yml)' --write",
    "test:unit": "TZ='UTC' vitest run",
    "test:e2e": "TZ='UTC' playwright test",
-
    "test:e2e:ipfs": "TZ='UTC' playwright test ./tests/e2e/hashRouter.spec.ts --config playwright.ipfs.config.ts",
    "test:httpd-api:unit": "TZ='UTC' vitest run --config httpd-client/vite.config.ts --reporter verbose"
  },
  "type": "module",
deleted playwright.ipfs.config.ts
@@ -1,14 +0,0 @@
-
import type { PlaywrightTestConfig } from "@playwright/test";
-

-
import base from "./playwright.config.js";
-

-
const config: PlaywrightTestConfig = {
-
  ...base,
-
  testIgnore: undefined,
-
  webServer: {
-
    command: "npm run start:ipfs -- --strictPort --port 3001",
-
    port: 3001,
-
  },
-
};
-

-
export default config;
modified src/App.svelte
@@ -32,10 +32,7 @@
  void httpd.initialize().finally(() => void router.loadFromLocation());

  if (!window.VITEST && !window.PLAYWRIGHT && import.meta.env.PROD) {
-
    const plausible = Plausible({
-
      domain: "app.radicle.xyz",
-
      hashMode: import.meta.env.VITE_HASH_ROUTING,
-
    });
+
    const plausible = Plausible({ domain: "app.radicle.xyz" });

    plausible.enableAutoPageviews();
  }
modified src/components/Markdown.svelte
@@ -146,11 +146,7 @@
      }

      // Make sure the source isn't a URL before trying to fetch it from the repo
-
      if (
-
        imagePath &&
-
        !isUrl(imagePath) &&
-
        !imagePath.startsWith(`${router.base}twemoji`)
-
      ) {
+
      if (imagePath && !isUrl(imagePath) && !imagePath.startsWith("/twemoji")) {
        i.setAttribute("src", `${rawPath}/${canonicalize(imagePath, path)}`);
      }
    }
modified src/env.d.ts
@@ -9,6 +9,5 @@ interface ImportMeta extends Readonly<Record<string, unknown>> {
    PROD: boolean;
    DEV: boolean;
    SSR: boolean;
-
    VITE_HASH_ROUTING: boolean;
  };
}
modified src/lib/router.ts
@@ -34,8 +34,6 @@ export function useDefaultNavigation(event: MouseEvent) {
  );
}

-
export const base = import.meta.env.VITE_HASH_ROUTING ? "./" : "/";
-

export async function loadFromLocation(): Promise<void> {
  await navigateToUrl("replace", new URL(window.location.href));
}
@@ -44,28 +42,18 @@ export async function navigateToUrl(
  action: "push" | "replace",
  url: URL,
): Promise<void> {
-
  let { pathname, hash } = url;
+
  const { pathname, hash } = url;

  if (url.origin !== window.origin) {
    throw new Error("Cannot navigate to other origin");
  }

-
  if (import.meta.env.VITE_HASH_ROUTING) {
-
    if (pathname === "/" && hash && !hash.startsWith("#/")) {
-
      // We land here if the user clicked an link with only a hash reference.
-
      // Instead of going to the root page we stop routing here and have the
-
      // browser take care of things.
-
      return;
-
    }
-
    [pathname, hash] = hash.substring(1).split("#");
-
  } else {
-
    if (
-
      currentUrl &&
-
      currentUrl.pathname === pathname &&
-
      currentUrl.search === url.search
-
    ) {
-
      return;
-
    }
+
  if (
+
    currentUrl &&
+
    currentUrl.pathname === pathname &&
+
    currentUrl.search === url.search
+
  ) {
+
    return;
  }

  const relativeUrl = pathname + url.search + (hash || "");
@@ -91,9 +79,7 @@ async function navigate(
  newRoute: Route,
): Promise<void> {
  isLoading.set(true);
-
  const path = import.meta.env.VITE_HASH_ROUTING
-
    ? "#" + routeToPath(newRoute)
-
    : routeToPath(newRoute);
+
  const path = routeToPath(newRoute);

  if (action === "push") {
    window.history.pushState(newRoute, "", path);
modified src/lib/utils.ts
@@ -4,8 +4,6 @@ import md5 from "md5";
import bs58 from "bs58";
import twemojiModule from "twemoji";

-
import { base } from "@app/lib/router";
-

export async function toClipboard(text: string): Promise<void> {
  await navigator.clipboard.writeText(text);
}
@@ -278,7 +276,7 @@ export function twemoji(
        ? false
        : "".concat(options.base, options.size, "/", icon, options.ext);
    },
-
    base,
+
    base: "/",
    folder: "twemoji",
    ext: ".svg",
    className: `txt-emoji`,
deleted tests/e2e/hashRouter.spec.ts
@@ -1,165 +0,0 @@
-
import {
-
  aliceMainHead,
-
  aliceRemote,
-
  appConfigWithFixture,
-
  expect,
-
  sourceBrowsingUrl,
-
  test,
-
} from "@tests/support/fixtures.js";
-
import {
-
  expectBackAndForwardNavigationWorks,
-
  expectUrlPersistsReload,
-
} from "@tests/support/router.js";
-

-
test("navigate between landing and project page", async ({ page }) => {
-
  await page.addInitScript(appConfigWithFixture);
-

-
  await page.goto("/#/");
-
  await expect(page).toHaveURL("/#/");
-

-
  await page.getByText("source-browsing").click();
-
  await expect(page).toHaveURL(`/#${sourceBrowsingUrl}`);
-

-
  await expectBackAndForwardNavigationWorks("/#/", page);
-
  await expectUrlPersistsReload(page);
-
});
-

-
test("navigation between node and project pages", async ({ page }) => {
-
  await page.goto("/#/nodes/radicle.local");
-

-
  const project = page
-
    .locator(".project-card", { hasText: "source-browsing" })
-
    .nth(0);
-
  await project.click();
-
  await expect(page).toHaveURL(`/#${sourceBrowsingUrl}`);
-

-
  await expectBackAndForwardNavigationWorks("/#/nodes/radicle.local", page);
-
  await expectUrlPersistsReload(page);
-

-
  await page.getByRole("link", { name: "Local Node" }).click();
-
  await expect(page).toHaveURL("/#/nodes/127.0.0.1");
-
});
-

-
test.describe("project page navigation", () => {
-
  test("navigation between commit history and single commit", async ({
-
    page,
-
  }) => {
-
    const projectHistoryURL = `/#${sourceBrowsingUrl}/history/${aliceMainHead}`;
-
    await page.goto(projectHistoryURL);
-

-
    await page.getByText("Add README.md").click();
-
    await expect(page).toHaveURL(
-
      `/#${sourceBrowsingUrl}/commits/${aliceMainHead}`,
-
    );
-

-
    await expectBackAndForwardNavigationWorks(projectHistoryURL, page);
-
    await expectUrlPersistsReload(page);
-
  });
-

-
  test("navigate between tree and commit history", async ({ page }) => {
-
    const projectTreeURL = `/#${sourceBrowsingUrl}/tree/${aliceMainHead}`;
-

-
    await page.goto(projectTreeURL);
-
    await page
-
      .getByRole("progressbar", { name: "Page loading" })
-
      .waitFor({ state: "hidden" });
-
    await expect(page).toHaveURL(projectTreeURL);
-

-
    await page.getByRole("link", { name: "Commits 6" }).click();
-
    await expect(page).toHaveURL(
-
      `/#${sourceBrowsingUrl}/history/${aliceMainHead}`,
-
    );
-

-
    await expectBackAndForwardNavigationWorks(projectTreeURL, page);
-
    await expectUrlPersistsReload(page);
-
  });
-

-
  test("navigate between tree and commit history while a file is selected", async ({
-
    page,
-
  }) => {
-
    const projectTreeURL = `/#${sourceBrowsingUrl}`;
-

-
    await page.goto(projectTreeURL);
-
    await page
-
      .getByRole("progressbar", { name: "Page loading" })
-
      .waitFor({ state: "hidden" });
-
    await expect(page).toHaveURL(projectTreeURL);
-

-
    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/tree/.hidden`);
-

-
    await page.getByRole("link", { name: "Commits 6" }).click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/history`);
-
  });
-

-
  test("navigate project paths", async ({ page }) => {
-
    const projectTreeURL = `/#${sourceBrowsingUrl}/tree/${aliceMainHead}`;
-

-
    await page.goto(projectTreeURL);
-
    await expect(page).toHaveURL(projectTreeURL);
-

-
    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/.hidden`);
-

-
    await page.getByText("bin").click();
-
    await page.getByText("true").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/bin/true`);
-

-
    await expectBackAndForwardNavigationWorks(
-
      `${projectTreeURL}/.hidden`,
-
      page,
-
    );
-
    await expectUrlPersistsReload(page);
-
  });
-

-
  test("navigate project paths with an explicitly selected peer", async ({
-
    page,
-
  }) => {
-
    // If a branch isn't explicitly specified, the code assumes the project
-
    // default branch is selected. We omit showing the default branch in the URL.
-

-
    const projectTreeURL = `/#${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
-
      8,
-
    )}`;
-

-
    await page.goto(projectTreeURL);
-
    await expect(page).toHaveURL(projectTreeURL);
-

-
    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/tree/.hidden`);
-

-
    await page.getByText("bin").click();
-
    await page.getByText("true").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/tree/bin/true`);
-

-
    await expectBackAndForwardNavigationWorks(
-
      `${projectTreeURL}/tree/.hidden`,
-
      page,
-
    );
-
    await expectUrlPersistsReload(page);
-
  });
-

-
  test("navigate project paths with an explicitly selected peer and branch", async ({
-
    page,
-
  }) => {
-
    const projectTreeURL = `/#${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
-
      8,
-
    )}/tree/main`;
-

-
    await page.goto(projectTreeURL);
-
    await expect(page).toHaveURL(projectTreeURL);
-

-
    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/.hidden`);
-

-
    await page.getByText("bin").click();
-
    await page.getByText("true").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/bin/true`);
-

-
    await expectBackAndForwardNavigationWorks(
-
      `${projectTreeURL}/.hidden`,
-
      page,
-
    );
-
    await expectUrlPersistsReload(page);
-
  });
-
});
deleted tests/e2e/historyRouter.spec.ts
@@ -1,190 +0,0 @@
-
import {
-
  aliceMainHead,
-
  aliceRemote,
-
  appConfigWithFixture,
-
  expect,
-
  sourceBrowsingUrl,
-
  test,
-
} from "@tests/support/fixtures.js";
-
import { createProject } from "@tests/support/project";
-
import {
-
  expectBackAndForwardNavigationWorks,
-
  expectUrlPersistsReload,
-
} from "@tests/support/router.js";
-

-
test("navigate between landing and project page", async ({ page }) => {
-
  await page.addInitScript(appConfigWithFixture);
-

-
  await page.goto("/");
-
  await expect(page).toHaveURL("/");
-

-
  await page.getByText("source-browsing").click();
-
  await expect(page).toHaveURL(sourceBrowsingUrl);
-

-
  await expectBackAndForwardNavigationWorks("/", page);
-
  await expectUrlPersistsReload(page);
-
});
-

-
test("navigation between node and project pages", async ({ page }) => {
-
  await page.goto("/nodes/radicle.local");
-

-
  const project = page
-
    .locator(".project-card", { hasText: "source-browsing" })
-
    .nth(0);
-
  await project.click();
-
  await expect(page).toHaveURL(sourceBrowsingUrl);
-

-
  await expectBackAndForwardNavigationWorks("/nodes/radicle.local", page);
-
  await expectUrlPersistsReload(page);
-

-
  await page.getByRole("link", { name: "Local Node" }).click();
-
  await expect(page).toHaveURL("/nodes/127.0.0.1");
-
});
-

-
test.describe("project page navigation", () => {
-
  test("navigation between commit history and single commit", async ({
-
    page,
-
  }) => {
-
    const projectHistoryURL = `${sourceBrowsingUrl}/history/${aliceMainHead}`;
-
    await page.goto(projectHistoryURL);
-

-
    await page.getByText("Add README.md").click();
-
    await expect(page).toHaveURL(
-
      `${sourceBrowsingUrl}/commits/${aliceMainHead}`,
-
    );
-

-
    await expectBackAndForwardNavigationWorks(projectHistoryURL, page);
-
    await expectUrlPersistsReload(page);
-
  });
-

-
  test("navigate between tree and commit history", async ({ page }) => {
-
    const projectTreeURL = `${sourceBrowsingUrl}/tree/${aliceMainHead}`;
-

-
    await page.goto(projectTreeURL);
-
    await page
-
      .getByRole("progressbar", { name: "Page loading" })
-
      .waitFor({ state: "hidden" });
-
    await expect(page).toHaveURL(projectTreeURL);
-

-
    await page.getByRole("link", { name: "Commits 6" }).click();
-
    await expect(page).toHaveURL(
-
      `${sourceBrowsingUrl}/history/${aliceMainHead}`,
-
    );
-

-
    await expectBackAndForwardNavigationWorks(projectTreeURL, page);
-
    await expectUrlPersistsReload(page);
-
  });
-

-
  test("navigate between tree and commit history while a file is selected", async ({
-
    page,
-
  }) => {
-
    const projectTreeURL = `${sourceBrowsingUrl}`;
-

-
    await page.goto(projectTreeURL);
-
    await page
-
      .getByRole("progressbar", { name: "Page loading" })
-
      .waitFor({ state: "hidden" });
-
    await expect(page).toHaveURL(projectTreeURL);
-

-
    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/tree/.hidden`);
-

-
    await page.getByRole("link", { name: "Commits 6" }).click();
-
    await expect(page).toHaveURL(`${sourceBrowsingUrl}/history`);
-
  });
-

-
  test("navigate project paths", async ({ page }) => {
-
    const projectTreeURL = `${sourceBrowsingUrl}/tree/${aliceMainHead}`;
-

-
    await page.goto(projectTreeURL);
-
    await expect(page).toHaveURL(projectTreeURL);
-

-
    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/.hidden`);
-

-
    await page.getByText("bin").click();
-
    await page.getByText("true").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/bin/true`);
-

-
    await expectBackAndForwardNavigationWorks(
-
      `${projectTreeURL}/.hidden`,
-
      page,
-
    );
-
    await expectUrlPersistsReload(page);
-
  });
-

-
  test("page title", async ({ page }) => {
-
    await page.goto(sourceBrowsingUrl, {
-
      waitUntil: "networkidle",
-
    });
-
    const title = await page.title();
-
    expect(title).toBe(
-
      "source-browsing · Git repository for source browsing tests",
-
    );
-
  });
-

-
  test("page title on project with empty description", async ({
-
    page,
-
    authenticatedPeer,
-
  }) => {
-
    const { rid } = await createProject(authenticatedPeer, {
-
      name: "ProjectWithNoDescription",
-
    });
-
    await page.goto(authenticatedPeer.ridUrl(rid), {
-
      waitUntil: "networkidle",
-
    });
-
    const title = await page.title();
-
    expect(title).toBe("ProjectWithNoDescription");
-
  });
-

-
  test("navigate project paths with an explicitly selected peer", async ({
-
    page,
-
  }) => {
-
    // If a branch isn't explicitly specified, the code assumes the project
-
    // default branch is selected. We omit showing the default branch in the URL.
-

-
    const projectTreeURL = `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
-
      8,
-
    )}`;
-

-
    await page.goto(projectTreeURL);
-
    await expect(page).toHaveURL(projectTreeURL);
-

-
    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/tree/.hidden`);
-

-
    await page.getByText("bin").click();
-
    await page.getByText("true").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/tree/bin/true`);
-

-
    await expectBackAndForwardNavigationWorks(
-
      `${projectTreeURL}/tree/.hidden`,
-
      page,
-
    );
-
    await expectUrlPersistsReload(page);
-
  });
-

-
  test("navigate project paths with an explicitly selected peer and branch", async ({
-
    page,
-
  }) => {
-
    const projectTreeURL = `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
-
      8,
-
    )}/tree/main`;
-

-
    await page.goto(projectTreeURL);
-
    await expect(page).toHaveURL(projectTreeURL);
-

-
    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/.hidden`);
-

-
    await page.getByText("bin").click();
-
    await page.getByText("true").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/bin/true`);
-

-
    await expectBackAndForwardNavigationWorks(
-
      `${projectTreeURL}/.hidden`,
-
      page,
-
    );
-
    await expectUrlPersistsReload(page);
-
  });
-
});
modified tests/e2e/project/patch.spec.ts
@@ -101,7 +101,7 @@ test("navigate through revision diffs", async ({ page }) => {
      .getByRole("button")
      .click();
    await expect(
-
      page.getByRole("link", { name: "Compare 88b7fd9..9e4fea" }),
+
      page.getByRole("link", { name: "Compare 88b7fd..9e4fea" }),
    ).toBeVisible();
    await page.goBack();
  }
added tests/e2e/router.ts
@@ -0,0 +1,190 @@
+
import {
+
  aliceMainHead,
+
  aliceRemote,
+
  appConfigWithFixture,
+
  expect,
+
  sourceBrowsingUrl,
+
  test,
+
} from "@tests/support/fixtures.js";
+
import { createProject } from "@tests/support/project";
+
import {
+
  expectBackAndForwardNavigationWorks,
+
  expectUrlPersistsReload,
+
} from "@tests/support/router.js";
+

+
test("navigate between landing and project page", async ({ page }) => {
+
  await page.addInitScript(appConfigWithFixture);
+

+
  await page.goto("/");
+
  await expect(page).toHaveURL("/");
+

+
  await page.getByText("source-browsing").click();
+
  await expect(page).toHaveURL(sourceBrowsingUrl);
+

+
  await expectBackAndForwardNavigationWorks("/", page);
+
  await expectUrlPersistsReload(page);
+
});
+

+
test("navigation between node and project pages", async ({ page }) => {
+
  await page.goto("/nodes/radicle.local");
+

+
  const project = page
+
    .locator(".project-card", { hasText: "source-browsing" })
+
    .nth(0);
+
  await project.click();
+
  await expect(page).toHaveURL(sourceBrowsingUrl);
+

+
  await expectBackAndForwardNavigationWorks("/nodes/radicle.local", page);
+
  await expectUrlPersistsReload(page);
+

+
  await page.getByRole("link", { name: "Local Node" }).click();
+
  await expect(page).toHaveURL("/nodes/127.0.0.1");
+
});
+

+
test.describe("project page navigation", () => {
+
  test("navigation between commit history and single commit", async ({
+
    page,
+
  }) => {
+
    const projectHistoryURL = `${sourceBrowsingUrl}/history/${aliceMainHead}`;
+
    await page.goto(projectHistoryURL);
+

+
    await page.getByText("Add README.md").click();
+
    await expect(page).toHaveURL(
+
      `${sourceBrowsingUrl}/commits/${aliceMainHead}`,
+
    );
+

+
    await expectBackAndForwardNavigationWorks(projectHistoryURL, page);
+
    await expectUrlPersistsReload(page);
+
  });
+

+
  test("navigate between tree and commit history", async ({ page }) => {
+
    const projectTreeURL = `${sourceBrowsingUrl}/tree/${aliceMainHead}`;
+

+
    await page.goto(projectTreeURL);
+
    await page
+
      .getByRole("progressbar", { name: "Page loading" })
+
      .waitFor({ state: "hidden" });
+
    await expect(page).toHaveURL(projectTreeURL);
+

+
    await page.getByRole("link", { name: "Commits 6" }).click();
+
    await expect(page).toHaveURL(
+
      `${sourceBrowsingUrl}/history/${aliceMainHead}`,
+
    );
+

+
    await expectBackAndForwardNavigationWorks(projectTreeURL, page);
+
    await expectUrlPersistsReload(page);
+
  });
+

+
  test("navigate between tree and commit history while a file is selected", async ({
+
    page,
+
  }) => {
+
    const projectTreeURL = `${sourceBrowsingUrl}`;
+

+
    await page.goto(projectTreeURL);
+
    await page
+
      .getByRole("progressbar", { name: "Page loading" })
+
      .waitFor({ state: "hidden" });
+
    await expect(page).toHaveURL(projectTreeURL);
+

+
    await page.getByText(".hidden").click();
+
    await expect(page).toHaveURL(`${projectTreeURL}/tree/.hidden`);
+

+
    await page.getByRole("link", { name: "Commits 6" }).click();
+
    await expect(page).toHaveURL(`${sourceBrowsingUrl}/history`);
+
  });
+

+
  test("navigate project paths", async ({ page }) => {
+
    const projectTreeURL = `${sourceBrowsingUrl}/tree/${aliceMainHead}`;
+

+
    await page.goto(projectTreeURL);
+
    await expect(page).toHaveURL(projectTreeURL);
+

+
    await page.getByText(".hidden").click();
+
    await expect(page).toHaveURL(`${projectTreeURL}/.hidden`);
+

+
    await page.getByText("bin").click();
+
    await page.getByText("true").click();
+
    await expect(page).toHaveURL(`${projectTreeURL}/bin/true`);
+

+
    await expectBackAndForwardNavigationWorks(
+
      `${projectTreeURL}/.hidden`,
+
      page,
+
    );
+
    await expectUrlPersistsReload(page);
+
  });
+

+
  test("page title", async ({ page }) => {
+
    await page.goto(sourceBrowsingUrl, {
+
      waitUntil: "networkidle",
+
    });
+
    const title = await page.title();
+
    expect(title).toBe(
+
      "source-browsing · Git repository for source browsing tests",
+
    );
+
  });
+

+
  test("page title on project with empty description", async ({
+
    page,
+
    authenticatedPeer,
+
  }) => {
+
    const { rid } = await createProject(authenticatedPeer, {
+
      name: "ProjectWithNoDescription",
+
    });
+
    await page.goto(authenticatedPeer.ridUrl(rid), {
+
      waitUntil: "networkidle",
+
    });
+
    const title = await page.title();
+
    expect(title).toBe("ProjectWithNoDescription");
+
  });
+

+
  test("navigate project paths with an explicitly selected peer", async ({
+
    page,
+
  }) => {
+
    // If a branch isn't explicitly specified, the code assumes the project
+
    // default branch is selected. We omit showing the default branch in the URL.
+

+
    const projectTreeURL = `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
+
      8,
+
    )}`;
+

+
    await page.goto(projectTreeURL);
+
    await expect(page).toHaveURL(projectTreeURL);
+

+
    await page.getByText(".hidden").click();
+
    await expect(page).toHaveURL(`${projectTreeURL}/tree/.hidden`);
+

+
    await page.getByText("bin").click();
+
    await page.getByText("true").click();
+
    await expect(page).toHaveURL(`${projectTreeURL}/tree/bin/true`);
+

+
    await expectBackAndForwardNavigationWorks(
+
      `${projectTreeURL}/tree/.hidden`,
+
      page,
+
    );
+
    await expectUrlPersistsReload(page);
+
  });
+

+
  test("navigate project paths with an explicitly selected peer and branch", async ({
+
    page,
+
  }) => {
+
    const projectTreeURL = `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
+
      8,
+
    )}/tree/main`;
+

+
    await page.goto(projectTreeURL);
+
    await expect(page).toHaveURL(projectTreeURL);
+

+
    await page.getByText(".hidden").click();
+
    await expect(page).toHaveURL(`${projectTreeURL}/.hidden`);
+

+
    await page.getByText("bin").click();
+
    await page.getByText("true").click();
+
    await expect(page).toHaveURL(`${projectTreeURL}/bin/true`);
+

+
    await expectBackAndForwardNavigationWorks(
+
      `${projectTreeURL}/.hidden`,
+
      page,
+
    );
+
    await expectUrlPersistsReload(page);
+
  });
+
});