# QA: DashboardShell branding (wordmark, sidebar collapse, UserMenu) ## Automated (Vitest + Vue Test Utils, `task test:web`) Mount DashboardShell (or a verified route rendered inside it) with a resolved session (username "marta") and a test router. Mock `useApi`'s `/v1/auth/logout` call per case; no real backend, no httptest server. Stub `useColorMode()` so its `preference` can be asserted and set. 1. **Header renders AppLogo and the wordmark** — mount DashboardShell expanded; assert the sidebar's #header slot renders an AppLogo followed by the text "RenewCMS"; assert neither is a link. 2. **Sidebar collapse trigger toggles the rail and aria-expanded** — mount DashboardShell expanded; activate UDashboardSidebarCollapse; assert the sidebar reaches its :collapsed-size="3.5" state and the trigger's aria-expanded reflects it; activate it again; assert the sidebar returns to :default-size="14" and aria-expanded flips back. 3. **UserMenu dropdown groups and order** — mount with username "marta" and `useColorMode().preference` set to each of "system", "light", "dark" in turn; open the UserMenu dropdown; assert the avatar shows initials "MA"; assert the trigger shows "marta"; assert the first group is the account label "marta"; assert the second group has System, Light and Dark checkbox items with exactly the current preference's item checked; assert the third, separate group contains only "Log out". 4. **Selecting a color-mode item updates the preference** — Examples-driven: (system → light), (light → dark), (dark → system). Open the dropdown, activate the target item, assert `useColorMode().preference` is set to the target and its checkbox item is checked while the previous one is not. 5. **Successful logout clears the session and navigates** — mock `POST /v1/auth/logout` resolving 200; open the UserMenu dropdown; activate "Log out"; assert the mock was called; assert the session store's `clear()` is called once it resolves; assert the router navigates to /login. 6. **Collapsed sidebar hides wordmark/username text but keeps an accessible name** — mount DashboardShell and collapse the sidebar to :collapsed-size="3.5"; assert the AppLogo icon is still present but the "RenewCMS" text node is not rendered (or is visually hidden, e.g. sr-only) while an accessible name for the logo (aria-label or sr-only text reading "RenewCMS") is still present in the accessibility tree; assert the UserMenu trigger still renders the UAvatar but not the visible "marta" text node, while the trigger's accessible name still includes "marta" (via aria-label or a tooltip plus aria-label); activate the collapsed trigger and assert the same dropdown (account label, color-mode group, Log out) opens as in the expanded state. ## Visual (manual verification — desktop and mobile, light and dark) Reference: `docs/design/components.md`'s DashboardShell section and `docs/design/source/RenewCMS Screens Back-office.dc.html`. Run `task visual:check -- ` for each state and compare the sidebar header/footer against the board frame. - [ ] Expanded sidebar: AppLogo plus "RenewCMS" wordmark in the header; UserMenu in the footer shows the avatar and username, matching the board exactly at desktop and mobile. - [ ] UserMenu dropdown: opens above the trigger (`side: 'top'`), left-aligned (`align: 'start'`), with the account label, the System/Light/Dark checkbox group and Log out visually separated as in the board. - [ ] Color mode selection: choosing Light/Dark/System visibly re-themes the app and moves the checkmark to the selected item. - [ ] Collapsed sidebar (icon-only rail): the AppLogo icon and the avatar remain visible; the "RenewCMS" wordmark and the username text are hidden; nothing overflows or clips awkwardly at the :collapsed-size="3.5" width, matching the board's collapsed rail treatment. - [ ] Keyboard/focus: Tab reaches UDashboardSidebarCollapse, then the UserMenu trigger; the dropdown opens with Enter/Space, arrow keys move through the checkbox group, and Esc closes it and returns focus to the trigger, in both the expanded and collapsed rail. ## Manual verification - **Real POST /v1/auth/logout against a running server** — Vitest only mocks `useApi`; confirm the real 200 round-trip against `task dev` with a live SQLite file, since these automated tests never exercise the actual Go handler. - **Real useColorMode persistence across reload** — confirm a selected preference survives a full page reload via the plugin's `colorMode: true` storage, since Vitest only asserts the in-memory preference value.