mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
## Summary - move Settings section labels outside their framed containers and centralize the spacing - apply the shared hierarchy across Appearance, Notifications, Voice, Agents, Shortcuts, Members, and Profile - give Identity and Sign out complete section treatments while removing redundant in-cell labels ## Testing - desktop pre-push checks, including 4,791 tests - focused Settings layout and sign-out Playwright coverage --------- Signed-off-by: kenny lopez <klopez4212@gmail.com> Signed-off-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz> Co-authored-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
130 lines
4.3 KiB
TypeScript
130 lines
4.3 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
import { installMockBridge } from "../helpers/bridge";
|
|
import { openSettings } from "../helpers/settings";
|
|
|
|
test("settings sections share the Appearance rhythm", async ({ page }) => {
|
|
await installMockBridge(page);
|
|
await page.goto("/");
|
|
await openSettings(page, "appearance");
|
|
|
|
const appearanceList = page
|
|
.getByTestId("settings-theme")
|
|
.locator('[data-slot="settings-section-list"]');
|
|
const [referenceGap] = await appearanceList
|
|
.locator(":scope > *")
|
|
.evaluateAll((elements) =>
|
|
elements.slice(1).map((element, index) => {
|
|
const previous = elements[index];
|
|
return (
|
|
element.getBoundingClientRect().top -
|
|
previous.getBoundingClientRect().bottom
|
|
);
|
|
}),
|
|
);
|
|
|
|
expect(referenceGap).toBeGreaterThan(0);
|
|
|
|
for (const section of [
|
|
"notifications",
|
|
"voice",
|
|
"agents",
|
|
"shortcuts",
|
|
"profile",
|
|
] as const) {
|
|
await page.getByTestId(`settings-nav-${section}`).click();
|
|
|
|
const list = page
|
|
.getByTestId(`settings-${section}`)
|
|
.locator('[data-slot="settings-section-list"]');
|
|
await expect(list).toBeVisible();
|
|
|
|
const gaps = await list.locator(":scope > *").evaluateAll((elements) =>
|
|
elements.slice(1).map((element, index) => {
|
|
const previous = elements[index];
|
|
return (
|
|
element.getBoundingClientRect().top -
|
|
previous.getBoundingClientRect().bottom
|
|
);
|
|
}),
|
|
);
|
|
expect(gaps.length).toBeGreaterThan(0);
|
|
expect(gaps.every((gap) => Math.abs(gap - referenceGap) <= 1)).toBe(true);
|
|
}
|
|
|
|
await page.getByTestId("settings-nav-agents").click();
|
|
const headerToCardGap = async (testId: string) => {
|
|
const group = page.getByTestId(testId);
|
|
return group.evaluate((element) => {
|
|
const lastHeaderLine = element.querySelector(
|
|
'[data-slot="settings-section-header"] > div:first-child > :last-child',
|
|
);
|
|
const card = element.querySelector('[data-slot="settings-section-card"]');
|
|
if (
|
|
!(lastHeaderLine instanceof HTMLElement) ||
|
|
!(card instanceof HTMLElement)
|
|
) {
|
|
throw new Error("Missing section header or card");
|
|
}
|
|
return (
|
|
card.getBoundingClientRect().top -
|
|
lastHeaderLine.getBoundingClientRect().bottom
|
|
);
|
|
});
|
|
};
|
|
const [titleOnlyGap, subtitleGap] = await Promise.all([
|
|
headerToCardGap("agents-preferences-card"),
|
|
headerToCardGap("settings-harnesses"),
|
|
]);
|
|
expect(titleOnlyGap).toBeGreaterThan(0);
|
|
expect(Math.abs(titleOnlyGap - subtitleGap)).toBeLessThanOrEqual(1);
|
|
});
|
|
|
|
test("Profile sections keep visible cards and aligned actions", async ({
|
|
page,
|
|
}) => {
|
|
await installMockBridge(page);
|
|
await page.goto("/");
|
|
await openSettings(page, "profile");
|
|
|
|
const identity = page.getByTestId("profile-identity-card");
|
|
const identityCard = identity.locator(
|
|
'xpath=ancestor::*[@data-slot="settings-section-card"][1]',
|
|
);
|
|
await expect(identityCard).toBeVisible();
|
|
await expect(
|
|
page.getByText("Identity details", { exact: true }),
|
|
).toBeVisible();
|
|
await expect(page.getByTestId("profile-identity-details")).toBeHidden();
|
|
|
|
const signOut = page.getByTestId("settings-signout");
|
|
const signOutCard = signOut.locator('[data-slot="settings-section-card"]');
|
|
await expect(signOutCard).toBeVisible();
|
|
await expect(
|
|
signOutCard.getByRole("button", { name: "Delete my data" }),
|
|
).toBeVisible();
|
|
await expect(signOut.getByText("Sign out", { exact: true })).toHaveCount(1);
|
|
await expect(
|
|
signOut.getByText("Sign out of Buzz", { exact: true }),
|
|
).toHaveCount(0);
|
|
|
|
const profileInfo = page.getByTestId("profile-metadata-card");
|
|
await profileInfo.scrollIntoViewIfNeeded();
|
|
const [titleBottom, editBottom] = await Promise.all([
|
|
profileInfo
|
|
.getByRole("heading", { name: "Profile info" })
|
|
.evaluate((element) => element.getBoundingClientRect().bottom),
|
|
page
|
|
.getByTestId("profile-metadata-edit")
|
|
.evaluate((element) => element.getBoundingClientRect().bottom),
|
|
]);
|
|
expect(Math.abs(titleBottom - editBottom)).toBeLessThanOrEqual(1);
|
|
|
|
await page.getByTestId("settings-nav-updates").click();
|
|
await expect(
|
|
page
|
|
.getByTestId("settings-updates")
|
|
.getByText("Update status", { exact: true }),
|
|
).toHaveCount(1);
|
|
});
|