mirror of
https://github.com/block/buzz.git
synced 2026-10-27 04:30:52 +00:00
feat: remember per-community navigation location (#2629)
Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -116,6 +116,278 @@ test.describe("community rail", () => {
|
||||
.toBe(COMMUNITY_B.id);
|
||||
});
|
||||
|
||||
test("restores the last Home or channel destination per community", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, undefined, { skipCommunitySeed: true });
|
||||
await seedCommunities(page, [COMMUNITY_A, COMMUNITY_B], COMMUNITY_A.id);
|
||||
await page.goto("/");
|
||||
|
||||
await page.getByTestId("channel-general").click();
|
||||
await expect(page).toHaveURL(/#\/channels\//);
|
||||
const generalUrl = page.url();
|
||||
|
||||
await page.getByTestId(`community-rail-button-${COMMUNITY_B.id}`).click();
|
||||
await expect(page).toHaveURL(/#\/$/);
|
||||
|
||||
await page.getByTestId("channel-random").click();
|
||||
await expect(page).toHaveURL(/#\/channels\//);
|
||||
const randomUrl = page.url();
|
||||
|
||||
await page.getByTestId(`community-rail-button-${COMMUNITY_A.id}`).click();
|
||||
await expect(page).toHaveURL(generalUrl);
|
||||
|
||||
await page.getByTestId(`community-rail-button-${COMMUNITY_B.id}`).click();
|
||||
await expect(page).toHaveURL(randomUrl);
|
||||
|
||||
await page.getByRole("button", { name: "Inbox" }).click();
|
||||
await expect(page).toHaveURL(/#\/$/);
|
||||
await page.getByTestId(`community-rail-button-${COMMUNITY_A.id}`).click();
|
||||
await expect(page).toHaveURL(generalUrl);
|
||||
await page.getByTestId(`community-rail-button-${COMMUNITY_B.id}`).click();
|
||||
await expect(page).toHaveURL(/#\/$/);
|
||||
});
|
||||
|
||||
test("enters a remembered channel before live validation completes", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, undefined, { skipCommunitySeed: true });
|
||||
await seedCommunities(page, [COMMUNITY_A, COMMUNITY_B], COMMUNITY_A.id);
|
||||
await page.goto("/");
|
||||
await expect(page.getByTestId("app-sidebar")).toBeVisible();
|
||||
const rememberedChannelId = await page.evaluate((communityId) => {
|
||||
const source = window.localStorage.getItem(
|
||||
"buzz-channels.v1:ws://localhost:3000",
|
||||
);
|
||||
if (!source) throw new Error("missing source channel snapshot");
|
||||
const snapshot = JSON.parse(source) as {
|
||||
channels: Array<{ id: string; name: string }>;
|
||||
};
|
||||
const generalChannel = snapshot.channels.find(
|
||||
(channel) => channel.name === "general",
|
||||
);
|
||||
if (!generalChannel) throw new Error("missing general channel snapshot");
|
||||
window.localStorage.setItem(
|
||||
"buzz-channels.v1:ws://localhost:3001",
|
||||
source,
|
||||
);
|
||||
window.localStorage.setItem(
|
||||
"buzz-community-destinations",
|
||||
JSON.stringify({
|
||||
[communityId]: {
|
||||
kind: "channel",
|
||||
channelId: generalChannel.id,
|
||||
},
|
||||
}),
|
||||
);
|
||||
return generalChannel.id;
|
||||
}, COMMUNITY_B.id);
|
||||
|
||||
await page.evaluate(() => {
|
||||
const testWindow = window as typeof window & {
|
||||
__BUZZ_E2E__?: { mock?: { channelsReadDelayMs?: number } };
|
||||
};
|
||||
if (!testWindow.__BUZZ_E2E__) {
|
||||
throw new Error("missing E2E config");
|
||||
}
|
||||
testWindow.__BUZZ_E2E__.mock = {
|
||||
...testWindow.__BUZZ_E2E__.mock,
|
||||
channelsReadDelayMs: 800,
|
||||
};
|
||||
});
|
||||
await page.getByTestId(`community-rail-button-${COMMUNITY_B.id}`).click();
|
||||
|
||||
await expect(page).toHaveURL(
|
||||
new RegExp(`#/channels/${rememberedChannelId}$`),
|
||||
{ timeout: 700 },
|
||||
);
|
||||
await expect(page.getByTestId("message-timeline")).toBeVisible({
|
||||
timeout: 700,
|
||||
});
|
||||
});
|
||||
|
||||
test("clears a remembered channel that is unavailable after switching", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, undefined, { skipCommunitySeed: true });
|
||||
await seedCommunities(page, [COMMUNITY_A, COMMUNITY_B], COMMUNITY_A.id);
|
||||
await page.addInitScript((communityId) => {
|
||||
window.localStorage.setItem(
|
||||
"buzz-community-destinations",
|
||||
JSON.stringify({
|
||||
[communityId]: { kind: "channel", channelId: "missing-channel" },
|
||||
}),
|
||||
);
|
||||
}, COMMUNITY_B.id);
|
||||
|
||||
await page.goto("/");
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(() =>
|
||||
window.localStorage.getItem("buzz-channels.v1:ws://localhost:3000"),
|
||||
),
|
||||
)
|
||||
.not.toBeNull();
|
||||
await page.evaluate(() => {
|
||||
const source = window.localStorage.getItem(
|
||||
"buzz-channels.v1:ws://localhost:3000",
|
||||
);
|
||||
if (!source) throw new Error("missing source channel snapshot");
|
||||
const snapshot = JSON.parse(source);
|
||||
snapshot.channels = snapshot.channels.map(
|
||||
(channel: Record<string, unknown>, index: number) =>
|
||||
index === 0 ? { ...channel, id: "missing-channel" } : channel,
|
||||
);
|
||||
window.localStorage.setItem(
|
||||
"buzz-channels.v1:ws://localhost:3001",
|
||||
JSON.stringify(snapshot),
|
||||
);
|
||||
});
|
||||
await page.getByTestId(`community-rail-button-${COMMUNITY_B.id}`).click();
|
||||
|
||||
await expect(page).not.toHaveURL(/#\/channels\//);
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate((communityId) => {
|
||||
const raw = window.localStorage.getItem(
|
||||
"buzz-community-destinations",
|
||||
);
|
||||
if (!raw) return null;
|
||||
return JSON.parse(raw)[communityId];
|
||||
}, COMMUNITY_B.id),
|
||||
)
|
||||
.toEqual({ kind: "home" });
|
||||
});
|
||||
|
||||
test("does not repair a remembered channel until live validation succeeds", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(
|
||||
page,
|
||||
{
|
||||
channelsReadDelayMs: 300,
|
||||
channelsReadErrors: [null, "temporary channel read failure"],
|
||||
},
|
||||
{ skipCommunitySeed: true },
|
||||
);
|
||||
await seedCommunities(page, [COMMUNITY_A, COMMUNITY_B], COMMUNITY_A.id);
|
||||
await page.addInitScript((communityId) => {
|
||||
window.localStorage.setItem(
|
||||
"buzz-community-destinations",
|
||||
JSON.stringify({
|
||||
[communityId]: { kind: "channel", channelId: "general" },
|
||||
}),
|
||||
);
|
||||
}, COMMUNITY_B.id);
|
||||
await page.goto("/");
|
||||
await expect(page.getByTestId("app-sidebar")).toBeVisible();
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(() =>
|
||||
window.localStorage.getItem("buzz-channels.v1:ws://localhost:3000"),
|
||||
),
|
||||
)
|
||||
.not.toBeNull();
|
||||
await page.evaluate(() => {
|
||||
const source = window.localStorage.getItem(
|
||||
"buzz-channels.v1:ws://localhost:3000",
|
||||
);
|
||||
if (!source) throw new Error("missing source channel snapshot");
|
||||
const snapshot = JSON.parse(source);
|
||||
snapshot.channels = snapshot.channels.filter(
|
||||
(channel: { id: string }) => channel.id !== "general",
|
||||
);
|
||||
window.localStorage.setItem(
|
||||
"buzz-channels.v1:ws://localhost:3001",
|
||||
JSON.stringify(snapshot),
|
||||
);
|
||||
});
|
||||
|
||||
await page.getByTestId(`community-rail-button-${COMMUNITY_B.id}`).click();
|
||||
await expect(page).toHaveURL(/#\/channels\/general$/);
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate((communityId) => {
|
||||
const raw = window.localStorage.getItem(
|
||||
"buzz-community-destinations",
|
||||
);
|
||||
return raw ? JSON.parse(raw)[communityId] : null;
|
||||
}, COMMUNITY_B.id),
|
||||
)
|
||||
.toEqual({ kind: "channel", channelId: "general" });
|
||||
await page.waitForTimeout(400);
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate((communityId) => {
|
||||
const raw = window.localStorage.getItem(
|
||||
"buzz-community-destinations",
|
||||
);
|
||||
return raw ? JSON.parse(raw)[communityId] : null;
|
||||
}, COMMUNITY_B.id),
|
||||
)
|
||||
.toEqual({ kind: "channel", channelId: "general" });
|
||||
|
||||
await expect(page.getByTestId("channel-general")).toBeVisible();
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate((communityId) => {
|
||||
const raw = window.localStorage.getItem(
|
||||
"buzz-community-destinations",
|
||||
);
|
||||
return raw ? JSON.parse(raw)[communityId] : null;
|
||||
}, COMMUNITY_B.id),
|
||||
)
|
||||
.toEqual({ kind: "channel", channelId: "general" });
|
||||
});
|
||||
|
||||
test("does not restore a remembered destination on cold boot", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, undefined, { skipCommunitySeed: true });
|
||||
await seedCommunities(page, [COMMUNITY_A, COMMUNITY_B], COMMUNITY_A.id);
|
||||
await page.addInitScript((communityId) => {
|
||||
window.localStorage.setItem(
|
||||
"buzz-community-destinations",
|
||||
JSON.stringify({
|
||||
[communityId]: { kind: "channel", channelId: "general" },
|
||||
}),
|
||||
);
|
||||
}, COMMUNITY_A.id);
|
||||
|
||||
await page.goto("/");
|
||||
|
||||
await expect(page).not.toHaveURL(/#\/channels\//);
|
||||
});
|
||||
|
||||
test("removing the active community restores the fallback destination", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, undefined, { skipCommunitySeed: true });
|
||||
await seedCommunities(page, [COMMUNITY_A, COMMUNITY_B], COMMUNITY_A.id);
|
||||
await page.goto("/");
|
||||
|
||||
await page.getByTestId(`community-rail-button-${COMMUNITY_B.id}`).click();
|
||||
await page.getByTestId("channel-random").click();
|
||||
const randomUrl = page.url();
|
||||
await page.getByTestId(`community-rail-button-${COMMUNITY_A.id}`).click();
|
||||
await page.getByTestId("channel-general").click();
|
||||
|
||||
await page
|
||||
.getByTestId(`community-rail-button-${COMMUNITY_A.id}`)
|
||||
.click({ button: "right" });
|
||||
await page.getByRole("menuitem", { name: "Community settings" }).click();
|
||||
await page.getByRole("button", { name: "Remove Community" }).click();
|
||||
|
||||
await expect(page).toHaveURL(randomUrl);
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(() =>
|
||||
window.localStorage.getItem("buzz-active-community-id"),
|
||||
),
|
||||
)
|
||||
.toBe(COMMUNITY_B.id);
|
||||
});
|
||||
|
||||
test("shows the quiet switch gate, not the boot splash, while switching", async ({
|
||||
page,
|
||||
}) => {
|
||||
|
||||
Reference in New Issue
Block a user