diff --git a/dashboard/src/components/UserMenu.vue b/dashboard/src/components/UserMenu.vue index 5d8a233a..f26a9a6c 100644 --- a/dashboard/src/components/UserMenu.vue +++ b/dashboard/src/components/UserMenu.vue @@ -1,15 +1,14 @@ - - + + @@ -51,69 +97,22 @@ function openSettings(closeMenu: () => void) { class="flex min-w-0 flex-col text-left transition-opacity duration-150 ease-out" :class="isCollapsed ? 'w-0 flex-none overflow-hidden opacity-0' : 'flex-1 opacity-100'" > - + {{ session.fullName }} - {{ session.user }} + + {{ session.user }} + + + {{ __("Account menu") }} - - - - - {{ session.fullName }} - {{ session.user }} - - - - - - - - - - - - - - Theme - - - - - - - - - - - + diff --git a/dashboard/src/data/session.ts b/dashboard/src/data/session.ts index 25ad2cb4..dc9db01e 100644 --- a/dashboard/src/data/session.ts +++ b/dashboard/src/data/session.ts @@ -1,4 +1,4 @@ -import { createResource } from "frappe-ui" +import { createResource, toast } from "frappe-ui" import { computed, reactive } from "vue" import { clearBookingCache } from "@/utils" @@ -40,6 +40,10 @@ export const session = reactive({ clearBookingCache() window.location.reload() }, + // A silent failure leaves the menu open on a session that is still live. + onError() { + toast.error(__("Could not sign you out. Check your connection and try again.")) + }, }), user: sessionUser(), fullName: computed((): string => userResource.data?.full_name || session.user), diff --git a/e2e/tests/user-settings.spec.ts b/e2e/tests/user-settings.spec.ts index 43726604..308f3152 100644 --- a/e2e/tests/user-settings.spec.ts +++ b/e2e/tests/user-settings.spec.ts @@ -10,10 +10,14 @@ const unique = (prefix: string) => `${prefix} ${Date.now()}` // getByLabel("Email") also matches an event card's "Open E2E Guest Email OTP" button. const settings = (page: Page) => page.getByRole("dialog") +// By test id, not by role: the open settings dialog hides the sidebar from the +// accessibility tree, and the name assertion below runs while it is open. +const accountMenu = (page: Page) => page.getByTestId("account-menu") + async function openSettings(page: Page) { await expect(page.getByRole("heading", { name: "Events", level: 1 })).toBeVisible() - await page.getByLabel("Account menu").click() - await page.getByRole("button", { name: "Settings" }).click() + await accountMenu(page).click() + await page.getByRole("menuitem", { name: "Settings" }).click() await expect(settings(page).getByRole("heading", { name: "Profile" })).toBeVisible() } @@ -42,7 +46,7 @@ test.describe("User settings", () => { await save.click() // The sidebar reads full_name, which the server derives on save. - await expect(page.getByLabel("Account menu")).toContainText(edited) + await expect(accountMenu(page)).toContainText(edited) await firstName.fill(SETTINGS_FIRST_NAME) await save.click()