fix(SPA): save article list pagination in query url
This commit is contained in:
1 parent
54f27ac98f
commit
9d9453c1b3
7 files changed
+535
-2
No files matched your search
@@ -0,0 +1,115 @@
|
||||
Feature: Articles list remembers the chosen page size
|
||||
|
||||
As a verified RenewCMS user
|
||||
I want the page size I choose on the Articles list to be remembered
|
||||
So that I do not have to pick it again each time I come back or refresh
|
||||
|
||||
Background:
|
||||
Given this slice amends features/articles_pagination_screen.feature; the URL keeps ?size= as in that spec and no visual or API change is made (docs/design/ is untouched)
|
||||
And the size options stay "5 per page", "25 per page", "50 per page", "100 per page" and the default stays 25
|
||||
And the chosen size is stored in localStorage under the key renewcms-page-size-articles as the bare number (for example 5), one key per paginated list; only the Articles list uses it today
|
||||
And only choosing a size in the page-size select writes the stored value; loading a URL never writes it
|
||||
And an explicit valid ?size= in the URL is authoritative for that load and does not change the stored value
|
||||
And an invalid ?size= in the URL falls back to 25, never to the stored value, and is replaced in the URL (features/articles_pagination_screen.feature scenario 10b)
|
||||
And a stored value that is not 5, 25, 50 or 100 is treated as absent
|
||||
And localStorage that is unavailable or throws on read or write never raises an error or breaks the page: reads act as absent and writes are ignored
|
||||
And logout does not clear the stored size
|
||||
And a size change still resets page to 1 and drops page from the URL
|
||||
And the requests are GET /v1/article/?format=html&page=P&size=S&q=Q&status=T as in features/articles_pagination_api.feature
|
||||
|
||||
Scenario Outline: Choosing a size stores it
|
||||
Given nothing is stored and the user is on /article
|
||||
When the user chooses "<label>" in the page-size select
|
||||
Then localStorage renewcms-page-size-articles is "<stored>"
|
||||
And on success the URL is <url>
|
||||
|
||||
Examples:
|
||||
| label | stored | url |
|
||||
| 5 per page | 5 | /article?size=5 |
|
||||
| 25 per page | 25 | /article |
|
||||
| 50 per page | 50 | /article?size=50 |
|
||||
| 100 per page | 100 | /article?size=100 |
|
||||
|
||||
Scenario: The stored size is restored when the list is opened without a size
|
||||
Given localStorage renewcms-page-size-articles is "5"
|
||||
When the user navigates to /article
|
||||
Then GET ...&page=1&size=5 is sent
|
||||
And the page-size select reads "5 per page"
|
||||
And on success the URL is replaced (no history entry) by /article?size=5
|
||||
|
||||
Scenario: The size survives leaving the list and coming back
|
||||
Given the user chose "5 per page" on /article
|
||||
When the user navigates to /, then back to /article
|
||||
Then GET ...&size=5 is sent and the select reads "5 per page"
|
||||
|
||||
Scenario: The size survives a full page refresh
|
||||
Given the user chose "5 per page" on /article
|
||||
When the page is reloaded on /article?size=5, or on /article with the URL typed in without a size
|
||||
Then GET ...&size=5 is sent and the select reads "5 per page"
|
||||
|
||||
Scenario: The stored size is kept across paging, search, tabs and sort
|
||||
Given localStorage renewcms-page-size-articles is "50" and the user is on /article?size=50
|
||||
When the user activates Next, switches to the "Drafts" tab, sorts by Title or searches "plaster"
|
||||
Then every request carries size=50 and the stored value stays "50"
|
||||
|
||||
Scenario: Changing the size again replaces the stored one
|
||||
Given localStorage renewcms-page-size-articles is "5"
|
||||
When the user chooses "100 per page"
|
||||
Then localStorage renewcms-page-size-articles is "100"
|
||||
And the next visit to /article without a size sends size=100
|
||||
|
||||
Scenario: Returning to 25 is remembered too
|
||||
Given localStorage renewcms-page-size-articles is "5"
|
||||
When the user chooses "25 per page"
|
||||
Then localStorage renewcms-page-size-articles is "25"
|
||||
And the next visit to /article sends size=25 and the URL stays /article
|
||||
|
||||
Scenario: An explicit size in the URL wins and is not stored
|
||||
Given localStorage renewcms-page-size-articles is "5"
|
||||
When the user navigates to /article?size=100
|
||||
Then GET ...&size=100 is sent and the select reads "100 per page"
|
||||
And localStorage renewcms-page-size-articles is still "5"
|
||||
And a later visit to /article sends size=5
|
||||
|
||||
Scenario: An explicit page with no size uses the stored size
|
||||
Given localStorage renewcms-page-size-articles is "5"
|
||||
When the user navigates to /article?page=3
|
||||
Then GET ...&page=3&size=5 is sent and on success the URL is replaced by /article?page=3&size=5
|
||||
|
||||
Scenario Outline: An invalid stored value falls back to 25
|
||||
Given localStorage renewcms-page-size-articles is "<stored>"
|
||||
When the user navigates to /article
|
||||
Then GET ...&page=1&size=25 is sent, the select reads "25 per page" and the URL is /article
|
||||
|
||||
Examples:
|
||||
| stored |
|
||||
| 10 |
|
||||
| abc |
|
||||
| 0 |
|
||||
| -5 |
|
||||
| 25.5 |
|
||||
| |
|
||||
|
||||
Scenario: An invalid size in the URL ignores the stored one
|
||||
Given localStorage renewcms-page-size-articles is "5"
|
||||
When the user navigates to /article?size=10
|
||||
Then GET ... is sent with size=25 and the URL is replaced by /article
|
||||
And localStorage renewcms-page-size-articles is still "5"
|
||||
|
||||
Scenario Outline: Unavailable storage never breaks the list
|
||||
Given localStorage <failure>
|
||||
When the user navigates to /article
|
||||
Then GET ...&page=1&size=25 is sent, the list renders and no error is shown
|
||||
When the user chooses "50 per page"
|
||||
Then GET ...&page=1&size=50 is sent and the URL is /article?size=50
|
||||
|
||||
Examples:
|
||||
| failure |
|
||||
| throws on getItem |
|
||||
| throws on setItem (quota) |
|
||||
| is undefined |
|
||||
|
||||
Scenario: Logging out keeps the stored size
|
||||
Given localStorage renewcms-page-size-articles is "5"
|
||||
When the user logs out and logs in again and opens /article
|
||||
Then GET ...&size=5 is sent
|
||||
@@ -0,0 +1,33 @@
|
||||
# QA: Articles page-size memory (SPA)
|
||||
|
||||
No Go or HTTP test applies: nothing outside web/ changes.
|
||||
|
||||
## Automated (Vitest, task test:web)
|
||||
|
||||
Extend or sit beside web/src/views/__tests__/ArticlesPagination.spec.ts and reuse articleEnvelope.ts for the mocked GET /v1/article/ envelope (total 312, size from the query). localStorage.clear() in beforeEach; fresh router per test. Assert on the mocked request query string, the select label, the router URL and localStorage.
|
||||
|
||||
1. Choosing 5 / 25 / 50 / 100 writes "5" / "25" / "50" / "100" under renewcms-page-size-articles; URLs /article?size=5, /article, ?size=50, ?size=100.
|
||||
2. Stored "5", open /article: request carries size=5 and page=1, select reads "5 per page", URL replaced (router.replace, no history entry added) with ?size=5.
|
||||
3. Choose 5, navigate to another route and back (mount again): size=5 requested.
|
||||
4. Choose 5, remount the app on /article and on /article?size=5 (simulated refresh): size=5 requested.
|
||||
5. Stored "50", on ?size=50: Next, Drafts tab, sort Title, search "plaster" (fake timers for the 120 ms debounce, not the system date): every request has size=50, stored value unchanged.
|
||||
6. Stored "5", choose 100: stored "100"; remount sends size=100.
|
||||
7. Stored "5", choose 25: stored "25"; remount sends size=25, URL /article.
|
||||
8. Stored "5", open /article?size=100: size=100 requested, stored still "5"; remount on /article sends size=5.
|
||||
9. Stored "5", open /article?page=3: request page=3&size=5, URL replaced by ?page=3&size=5.
|
||||
10. Invalid stored values 10, abc, 0, -5, 25.5, "": size=25 requested, select "25 per page", URL /article.
|
||||
11. Stored "5", open /article?size=10: size=25 requested, URL /article, stored still "5".
|
||||
12. Storage failures (Storage.prototype.getItem throwing; setItem throwing; window.localStorage undefined): no exception, list renders, size=25 on load, choosing 50 requests size=50 and URL ?size=50.
|
||||
13. Logout (session store reset) leaves the stored value; the next /article sends size=5.
|
||||
14. Unit tests for any read/write helper added next to web/src/lib/pagination.ts: valid values accepted, invalid rejected, errors swallowed.
|
||||
|
||||
## Visual (task visual:check -- articles)
|
||||
|
||||
No visual change is intended. Run the full articles group as a regression and require every capture within 10 %. Setups use the board's own sample data and must not depend on a stored size. Clear localStorage before each capture so a leftover value cannot change the default 25 frame. No state is clock-sensitive for this slice.
|
||||
|
||||
## Manual
|
||||
|
||||
- In a real browser, choose 5 per page, navigate away and back, then hard-refresh: it stays at 5.
|
||||
- Private-window or storage-blocked browser: the list still works at 25 with no error.
|
||||
- Keyboard: the page-size select behaves as before (ArrowDown, Enter, Esc, focus ring), and focus returns to the select after choosing.
|
||||
- Open a copied /article?size=100 link in a profile that has 5 stored: the link shows 100 and the next plain visit shows 5.
|
||||
Reference in new issue
Block a user