mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(desktop): resolve flaky integration tests via project-level assertion timeout (#812)
This commit is contained in:
@@ -48,6 +48,9 @@ export default defineConfig({
|
||||
use: {
|
||||
...devices["Desktop Chrome"],
|
||||
},
|
||||
expect: {
|
||||
timeout: process.env.CI ? 15_000 : 10_000,
|
||||
},
|
||||
},
|
||||
],
|
||||
webServer: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export function useActiveChannelHeader(
|
||||
currentPubkey?: string,
|
||||
) {
|
||||
const activeDmParticipantPubkeys = React.useMemo(() => {
|
||||
if (!activeChannel || activeChannel.channelType !== "dm") {
|
||||
if (activeChannel?.channelType !== "dm") {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ type TypingIndicatorRowProps = {
|
||||
};
|
||||
|
||||
function resolveFallbackName(channel: Channel | null, pubkey: string) {
|
||||
if (!channel || channel.channelType !== "dm") {
|
||||
if (channel?.channelType !== "dm") {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ test("move up succeeds: middle section swaps order with the one above", () => {
|
||||
const result = swapSectionOrder(store, "b", "up");
|
||||
assert.notEqual(result, null);
|
||||
const byId = Object.fromEntries(result.sections.map((s) => [s.id, s.order]));
|
||||
assert.equal(byId["b"], 0);
|
||||
assert.equal(byId["a"], 1);
|
||||
assert.equal(byId["c"], 2);
|
||||
assert.equal(byId.b, 0);
|
||||
assert.equal(byId.a, 1);
|
||||
assert.equal(byId.c, 2);
|
||||
});
|
||||
|
||||
test("move down succeeds: middle section swaps order with the one below", () => {
|
||||
@@ -34,9 +34,9 @@ test("move down succeeds: middle section swaps order with the one below", () =>
|
||||
const result = swapSectionOrder(store, "b", "down");
|
||||
assert.notEqual(result, null);
|
||||
const byId = Object.fromEntries(result.sections.map((s) => [s.id, s.order]));
|
||||
assert.equal(byId["b"], 2);
|
||||
assert.equal(byId["c"], 1);
|
||||
assert.equal(byId["a"], 0);
|
||||
assert.equal(byId.b, 2);
|
||||
assert.equal(byId.c, 1);
|
||||
assert.equal(byId.a, 0);
|
||||
});
|
||||
|
||||
test("move up at top boundary returns null", () => {
|
||||
@@ -73,7 +73,7 @@ test("non-contiguous orders: swap uses actual order values not indices", () => {
|
||||
const result = swapSectionOrder(store, "b", "up");
|
||||
assert.notEqual(result, null);
|
||||
const byId = Object.fromEntries(result.sections.map((s) => [s.id, s.order]));
|
||||
assert.equal(byId["b"], 0);
|
||||
assert.equal(byId["a"], 5);
|
||||
assert.equal(byId["c"], 10);
|
||||
assert.equal(byId.b, 0);
|
||||
assert.equal(byId.a, 5);
|
||||
assert.equal(byId.c, 10);
|
||||
});
|
||||
|
||||
@@ -90,7 +90,7 @@ export function useUserStatusSubscription() {
|
||||
function handleStatusEvent(event: RelayEvent) {
|
||||
if (isCancelled) return;
|
||||
const dTag = event.tags.find((t) => t[0] === "d");
|
||||
if (!dTag || dTag[1] !== "general") return;
|
||||
if (dTag?.[1] !== "general") return;
|
||||
const parsed = parseUserStatusEvent(event);
|
||||
const status: UserStatus | null =
|
||||
parsed.text || parsed.emoji
|
||||
|
||||
@@ -564,7 +564,7 @@ export class RelayClient {
|
||||
|
||||
return async () => {
|
||||
const active = this.subscriptions.get(subId);
|
||||
if (!active || active.mode !== "live") {
|
||||
if (active?.mode !== "live") {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { resolveFileCard } from "./markdownFileCard.ts";
|
||||
// A generic-file URL (non-media extension) does not match the relay-media
|
||||
// proxy regex, so `rewriteRelayUrl` passes it through unchanged — assertions
|
||||
// can compare hrefs directly.
|
||||
const PDF_URL = "https://relay.example/media/" + "a".repeat(64) + ".pdf";
|
||||
const PDF_URL = `https://relay.example/media/${"a".repeat(64)}.pdf`;
|
||||
|
||||
test("resolveFileCard: returns null when there is no imeta entry", () => {
|
||||
assert.equal(resolveFileCard(undefined, PDF_URL, ""), null);
|
||||
@@ -62,12 +62,12 @@ test("resolveFileCard: falls back to link child text when imeta has no filename"
|
||||
|
||||
test("resolveFileCard: falls back to URL tail when no filename or child text", () => {
|
||||
const card = resolveFileCard({ m: "application/octet-stream" }, PDF_URL, "");
|
||||
assert.equal(card?.filename, "a".repeat(64) + ".pdf");
|
||||
assert.equal(card?.filename, `${"a".repeat(64)}.pdf`);
|
||||
});
|
||||
|
||||
test("resolveFileCard: octet-stream (no magic bytes) is treated as a file", () => {
|
||||
// Text/code/data upload with no magic signature — the Slack-like case.
|
||||
const url = "https://relay.example/media/" + "b".repeat(64) + ".txt";
|
||||
const url = `https://relay.example/media/${"b".repeat(64)}.txt`;
|
||||
const card = resolveFileCard(
|
||||
{ m: "application/octet-stream", filename: "notes.txt" },
|
||||
url,
|
||||
|
||||
@@ -4298,7 +4298,7 @@ function resolveMockUploadDescriptors(
|
||||
if (configured !== undefined) return configured;
|
||||
return [
|
||||
{
|
||||
url: "https://mock.relay/media/" + "a".repeat(64) + ".pdf",
|
||||
url: `https://mock.relay/media/${"a".repeat(64)}.pdf`,
|
||||
sha256: "a".repeat(64),
|
||||
size: 12345,
|
||||
type: "application/pdf",
|
||||
|
||||
@@ -6,7 +6,6 @@ import { assertRelaySeeded } from "../helpers/seed";
|
||||
|
||||
const isCi = Boolean(process.env.CI);
|
||||
const relaySeedHookTimeoutMs = isCi ? 90_000 : 30_000;
|
||||
const relayDeliveryTimeoutMs = isCi ? 15_000 : 10_000;
|
||||
|
||||
async function createStream(
|
||||
page: import("@playwright/test").Page,
|
||||
@@ -276,11 +275,7 @@ test("live mentions refetch the home feed without waiting for polling", async ({
|
||||
message,
|
||||
);
|
||||
|
||||
await expect
|
||||
.poll(() => getLoggedNotificationCount(targetPage), {
|
||||
timeout: relayDeliveryTimeoutMs,
|
||||
})
|
||||
.toBe(1);
|
||||
await expect.poll(() => getLoggedNotificationCount(targetPage)).toBe(1);
|
||||
|
||||
const notifications = await getLoggedNotifications(targetPage);
|
||||
|
||||
@@ -300,14 +295,9 @@ test("live mentions refetch the home feed without waiting for polling", async ({
|
||||
await expect(targetPage.getByTestId("home-inbox-list")).toBeVisible();
|
||||
await expect(targetPage.getByTestId("home-inbox-list")).toContainText(
|
||||
message,
|
||||
{ timeout: relayDeliveryTimeoutMs },
|
||||
);
|
||||
await expect(targetPage.getByTestId("sidebar-home-count")).toHaveCount(0);
|
||||
await expect
|
||||
.poll(() => getLoggedNotificationCount(targetPage), {
|
||||
timeout: relayDeliveryTimeoutMs,
|
||||
})
|
||||
.toBe(1);
|
||||
await expect.poll(() => getLoggedNotificationCount(targetPage)).toBe(1);
|
||||
} finally {
|
||||
await targetContext.close();
|
||||
await senderContext.close();
|
||||
@@ -345,15 +335,9 @@ test("live forum mentions refetch the home feed without waiting for polling", as
|
||||
mentionPubkeys: [TEST_IDENTITIES.tyler.pubkey],
|
||||
});
|
||||
|
||||
await expect(targetPage.getByTestId("sidebar-home-count")).toHaveText("1", {
|
||||
timeout: relayDeliveryTimeoutMs,
|
||||
});
|
||||
await expect(targetPage.getByTestId("sidebar-home-count")).toHaveText("1");
|
||||
|
||||
await expect
|
||||
.poll(() => getLoggedNotificationCount(targetPage), {
|
||||
timeout: relayDeliveryTimeoutMs,
|
||||
})
|
||||
.toBe(1);
|
||||
await expect.poll(() => getLoggedNotificationCount(targetPage)).toBe(1);
|
||||
|
||||
const notifications = await getLoggedNotifications(targetPage);
|
||||
|
||||
@@ -371,11 +355,7 @@ test("live forum mentions refetch the home feed without waiting for polling", as
|
||||
message,
|
||||
);
|
||||
await expect(targetPage.getByTestId("sidebar-home-count")).toHaveCount(0);
|
||||
await expect
|
||||
.poll(() => getLoggedNotificationCount(targetPage), {
|
||||
timeout: relayDeliveryTimeoutMs,
|
||||
})
|
||||
.toBe(1);
|
||||
await expect.poll(() => getLoggedNotificationCount(targetPage)).toBe(1);
|
||||
} finally {
|
||||
await targetContext.close();
|
||||
await senderContext.close();
|
||||
|
||||
@@ -4,13 +4,10 @@ import { installRelayBridge, TEST_IDENTITIES } from "../helpers/bridge";
|
||||
import { assertRelaySeeded } from "../helpers/seed";
|
||||
|
||||
const isCi = Boolean(process.env.CI);
|
||||
const relayDeliveryTimeoutMs = isCi ? 15_000 : 5_000;
|
||||
const relaySeedHookTimeoutMs = isCi ? 90_000 : 30_000;
|
||||
|
||||
async function expectTimelineToContain(page: Page, text: string) {
|
||||
await expect(page.getByTestId("message-timeline")).toContainText(text, {
|
||||
timeout: relayDeliveryTimeoutMs,
|
||||
});
|
||||
await expect(page.getByTestId("message-timeline")).toContainText(text);
|
||||
}
|
||||
|
||||
async function getTimelineMetrics(page: Page) {
|
||||
@@ -178,9 +175,7 @@ test("loads the home feed from the relay", async ({ browser }) => {
|
||||
mentionPubkeys: [TEST_IDENTITIES.tyler.pubkey],
|
||||
});
|
||||
|
||||
await expect(page.getByTestId("home-inbox-list")).toContainText(message, {
|
||||
timeout: relayDeliveryTimeoutMs,
|
||||
});
|
||||
await expect(page.getByTestId("home-inbox-list")).toContainText(message);
|
||||
await expect(page.getByTestId("home-inbox-detail")).toBeVisible();
|
||||
} finally {
|
||||
await targetContext.close();
|
||||
@@ -210,9 +205,7 @@ test("shows sent inbox replies immediately in the inbox detail pane", async ({
|
||||
mentionPubkeys: [TEST_IDENTITIES.tyler.pubkey],
|
||||
});
|
||||
|
||||
await page.getByTestId("home-inbox-list").getByText(message).click({
|
||||
timeout: relayDeliveryTimeoutMs,
|
||||
});
|
||||
await page.getByTestId("home-inbox-list").getByText(message).click();
|
||||
await expect(page.getByTestId("home-inbox-detail")).toBeVisible();
|
||||
await expect(page.getByTestId("message-input")).toBeEnabled();
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ export function useGitTree(
|
||||
return useQuery({
|
||||
queryKey: ["git-tree", owner, repoName, ref, path ?? ""],
|
||||
queryFn: async () => {
|
||||
const { fs, dir } = cloneQuery.data!;
|
||||
if (!cloneQuery.data) throw new Error("unreachable: enabled guards data");
|
||||
const { fs, dir } = cloneQuery.data;
|
||||
const oid = await resolveRef({ fs, dir, ref });
|
||||
const entries = await readTreeEntries(fs, dir, oid, path || undefined);
|
||||
|
||||
@@ -65,7 +66,8 @@ export function useGitLog(owner: string, repoName: string, ref: string) {
|
||||
return useQuery({
|
||||
queryKey: ["git-log", owner, repoName, ref],
|
||||
queryFn: async () => {
|
||||
const { fs, dir } = cloneQuery.data!;
|
||||
if (!cloneQuery.data) throw new Error("unreachable: enabled guards data");
|
||||
const { fs, dir } = cloneQuery.data;
|
||||
return getCommitLog(fs, dir, ref);
|
||||
},
|
||||
enabled: !!cloneQuery.data,
|
||||
@@ -80,7 +82,8 @@ export function useGitReadme(owner: string, repoName: string, ref: string) {
|
||||
return useQuery({
|
||||
queryKey: ["git-readme", owner, repoName, ref],
|
||||
queryFn: async () => {
|
||||
const { fs, dir } = cloneQuery.data!;
|
||||
if (!cloneQuery.data) throw new Error("unreachable: enabled guards data");
|
||||
const { fs, dir } = cloneQuery.data;
|
||||
return findReadme(fs, dir, ref);
|
||||
},
|
||||
enabled: !!cloneQuery.data,
|
||||
@@ -100,7 +103,8 @@ export function useGitBlob(
|
||||
return useQuery({
|
||||
queryKey: ["git-blob", owner, repoName, ref, filepath],
|
||||
queryFn: async () => {
|
||||
const { fs, dir } = cloneQuery.data!;
|
||||
if (!cloneQuery.data) throw new Error("unreachable: enabled guards data");
|
||||
const { fs, dir } = cloneQuery.data;
|
||||
const oid = await resolveRef({ fs, dir, ref });
|
||||
return readBlobView(fs, dir, oid, filepath);
|
||||
},
|
||||
@@ -128,7 +132,8 @@ export function useGitHtmlDoc(
|
||||
return useQuery({
|
||||
queryKey: ["git-html-doc", owner, repoName, ref, filepath],
|
||||
queryFn: async () => {
|
||||
const { fs, dir } = cloneQuery.data!;
|
||||
if (!cloneQuery.data) throw new Error("unreachable: enabled guards data");
|
||||
const { fs, dir } = cloneQuery.data;
|
||||
const oid = await resolveRef({ fs, dir, ref });
|
||||
return resolveHtmlAssets(fs, dir, oid, filepath, html);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user