feat: PrimeVue replaced by Nuxt UI using token files from web/src/theme, with AuthShell, DashboardShell, AppBoot and the route guards from routes.md
This commit is contained in:
1 parent
24f95a8fd7
commit
eed661bb24
38 files changed
+2365
-108
No files matched your search
@@ -0,0 +1,146 @@
|
||||
Feature: Nuxt UI shell foundation and router guards
|
||||
|
||||
As the maintainer of RenewCMS
|
||||
I want the SPA to run on Nuxt UI instead of PrimeVue, with AuthShell and DashboardShell layouts,
|
||||
an AppBoot skeleton, and a router guard that resolves and caches the session once per app load
|
||||
So that every later screen slice can build on a themed, guarded shell instead of an unguarded router
|
||||
with no layout
|
||||
|
||||
Background:
|
||||
Given web/src/main.ts wires the app through the @nuxt/ui/vite plugin, and no longer imports
|
||||
primevue, @primeuix/themes, primeicons or tailwindcss-primeui
|
||||
And web/src/theme/ui.config.ts and web/src/assets/main.css hold the token files copied from
|
||||
docs/design/source/tokens/ (ui.config.ts, renewcms.css), and public/favicon.svg is the file
|
||||
copied from docs/design/source/brand/favicon.svg
|
||||
And the router declares route meta.auth as one of "public", "session", "verified" or "any", and
|
||||
meta.title for every verified route
|
||||
And a global router.beforeEach guard runs on every navigation, and on the first navigation of the
|
||||
app it resolves the session by calling GET /v1/auth/me once and caches the result (session or
|
||||
"no session") in a session Pinia store; later navigations in the same app load reuse that
|
||||
cached result instead of calling GET /v1/auth/me again
|
||||
And /home, /article and /integration currently render only a trivial placeholder view inside
|
||||
DashboardShell; later screen slices (Home, Articles, Integration) replace that placeholder
|
||||
content with the real screens
|
||||
|
||||
Scenario: A public route never triggers a session check
|
||||
Given the target route is /login, whose meta.auth is "public"
|
||||
When the router navigates to it as the first navigation of the app
|
||||
Then GET /v1/auth/me is not called
|
||||
And AuthShell renders immediately, with no AppBoot skeleton shown
|
||||
|
||||
Scenario: The first navigation to a non-public route resolves the session and shows AppBoot meanwhile
|
||||
Given the target route is /home, whose meta.auth is "verified"
|
||||
And GET /v1/auth/me has not resolved yet
|
||||
When the router navigates to /home as the first navigation of the app
|
||||
Then DashboardShell renders with the AppBoot skeleton in place of the page content
|
||||
When GET /v1/auth/me then resolves 200 with is_verified true
|
||||
Then the AppBoot skeleton is replaced by the routed page's content
|
||||
And the navigation is not redirected
|
||||
|
||||
Scenario: A second navigation reuses the cached session instead of calling GET /v1/auth/me again
|
||||
Given GET /v1/auth/me has already resolved 200 with is_verified true during the first navigation
|
||||
When the router navigates from /home to /article, whose meta.auth is also "verified"
|
||||
Then GET /v1/auth/me is not called a second time
|
||||
And no AppBoot skeleton is shown for this navigation
|
||||
|
||||
Scenario: A verified-only route admits a verified session
|
||||
Given the target route is /article, whose meta.auth is "verified"
|
||||
And GET /v1/auth/me resolves 200 with is_verified true
|
||||
When the router navigates to /article
|
||||
Then the navigation completes to /article
|
||||
And there is no redirect
|
||||
|
||||
Scenario: A verified-only route redirects an unverified session to the pending page
|
||||
Given the target route is /article, whose meta.auth is "verified"
|
||||
And GET /v1/auth/me resolves 200 with is_verified false
|
||||
When the router navigates to /article
|
||||
Then the router redirects to /register/pending
|
||||
And the navigation to /article does not complete
|
||||
|
||||
Scenario: A session-only route admits an unverified session
|
||||
Given the target route is /register/pending, whose meta.auth is "session"
|
||||
And GET /v1/auth/me resolves 200 with is_verified false
|
||||
When the router navigates to /register/pending
|
||||
Then the navigation completes to /register/pending
|
||||
And there is no redirect
|
||||
|
||||
Scenario: No session redirects to login with the original path and an expired reason
|
||||
Given the target route is /article/12/edit, whose meta.auth is "verified"
|
||||
And GET /v1/auth/me resolves 401
|
||||
When the router navigates to /article/12/edit
|
||||
Then the router redirects to "/login?redirect=/article/12/edit&reason=expired"
|
||||
And the navigation to /article/12/edit does not complete
|
||||
|
||||
Scenario Outline: The root path resolves to /home, /login or /register/pending depending on the session
|
||||
Given GET /v1/auth/me resolves <response>
|
||||
When the router navigates to /
|
||||
Then the router redirects to <destination>
|
||||
|
||||
Examples:
|
||||
| response | destination |
|
||||
| 200 with is_verified true | /home |
|
||||
| 401 | /login |
|
||||
| 200 with is_verified false | /register/pending |
|
||||
|
||||
Scenario: A session check that fails with a server error renders the Generic error view instead of redirecting
|
||||
Given the target route is /, whose meta.auth is "any"
|
||||
And GET /v1/auth/me fails with a 500 response
|
||||
When the router navigates to /
|
||||
Then the router does not redirect anywhere
|
||||
And the Generic error view renders in place, with breadcrumb "Home", title "Something went wrong",
|
||||
text "This page couldn't load. Your saved work is safe. Try again, and if it keeps happening,
|
||||
restart the RenewCMS server.", a primary action "Try again" and a secondary action "Go to Home"
|
||||
When "Try again" is activated
|
||||
Then GET /v1/auth/me is called again to re-run the session check
|
||||
|
||||
Scenario: A session check that fails with a network error on a non-root verified route also renders the Generic error view
|
||||
Given the target route is /article, whose meta.auth is "verified"
|
||||
And GET /v1/auth/me fails with a network error
|
||||
When the router navigates to /article
|
||||
Then the router does not redirect to /login or /register/pending
|
||||
And DashboardShell renders the Generic error view in place of the AppBoot skeleton and the page
|
||||
content, with title "Something went wrong" and a primary action "Try again"
|
||||
When "Try again" is activated
|
||||
Then GET /v1/auth/me is called again to re-run the session check
|
||||
|
||||
Scenario Outline: Each verified placeholder route renders inside DashboardShell with its own heading, breadcrumb and active nav item
|
||||
Given GET /v1/auth/me resolves 200 with is_verified true
|
||||
When the router navigates to <path>
|
||||
Then the route renders inside DashboardShell
|
||||
And the page heading is <title>
|
||||
And the breadcrumb is <title>
|
||||
And the nav item for <title> has aria-current="page"
|
||||
|
||||
Examples:
|
||||
| path | title |
|
||||
| /home | "Home" |
|
||||
| /article | "Articles" |
|
||||
| /integration | "Integration" |
|
||||
|
||||
Scenario: AuthShell renders its title as the page heading and sets the document title
|
||||
Given a screen renders AuthShell with title "Log in" and no description
|
||||
When AuthShell mounts
|
||||
Then AuthShell renders an h1 containing "Log in"
|
||||
And document.title is "Log in · RenewCMS"
|
||||
|
||||
Scenario: AuthShell renders its notice and footer slots
|
||||
Given a screen renders AuthShell with a "notice" slot containing "Your session expired." and a
|
||||
"footer" slot containing a "Forgot password?" link
|
||||
When AuthShell mounts
|
||||
Then the alert above the title contains "Your session expired."
|
||||
And the footer area outside the card contains a "Forgot password?" link
|
||||
|
||||
Scenario: DashboardShell renders the three navigation destinations
|
||||
Given the current route is /article
|
||||
When DashboardShell mounts
|
||||
Then the sidebar navigation lists exactly three destinations: "Home" linking to /home, "Articles"
|
||||
linking to /article, and "Integration" linking to /integration
|
||||
And the "Articles" destination has aria-current="page"
|
||||
And neither "Home" nor "Integration" has aria-current set
|
||||
|
||||
Scenario: DashboardShell shows the offline banner when the browser reports offline
|
||||
Given navigator.onLine is false
|
||||
When DashboardShell mounts
|
||||
Then an offline banner is shown
|
||||
When navigator.onLine becomes true
|
||||
Then the offline banner is hidden
|
||||
Reference in new issue
Block a user