feat: articles pagination
This commit is contained in:
1 parent
a2d224240c
commit
73f4b539fe
45 files changed
+3528
-317
No files matched your search
@@ -8,9 +8,10 @@ import { useSessionStore } from '@/stores/session'
|
||||
import type { ActivityItem } from '@/lib/activity'
|
||||
import HomeView from '../HomeView.vue'
|
||||
import { anonymous, makeItem, target } from './activityFixtures'
|
||||
import { articleEnvelope, articleListRoute } from './articleEnvelope'
|
||||
|
||||
const ACTIVITY_ROUTE = 'GET /v1/activity?size=5'
|
||||
const ARTICLES_ROUTE = 'GET /v1/article/?format=html'
|
||||
const ARTICLES_ROUTE = articleListRoute({ size: 5, sort: 'updated_at:desc' })
|
||||
|
||||
type Handler = () => Response | Promise<Response>
|
||||
|
||||
@@ -95,7 +96,7 @@ describe('Home, owner or admin, the last five events with the actor name', () =>
|
||||
it.each(['owner', 'admin'] as const)('shows five rows with names for %s', async (role) => {
|
||||
await mountHome(role, {
|
||||
[ACTIVITY_ROUTE]: () => page(recentItems(5)),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
expect(card().find('h2').text()).toBe('Recent activity')
|
||||
@@ -125,7 +126,7 @@ describe('Home, regular user, own events only and no actor name', () => {
|
||||
it.each([['editor' as const], [undefined]])('shows only the time for %s', async (role) => {
|
||||
await mountHome(role as undefined, {
|
||||
[ACTIVITY_ROUTE]: () => page(recentItems(3)),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
expect(card().find('h2').text()).toBe('Your recent activity')
|
||||
@@ -146,7 +147,7 @@ describe('Home rows, failure and security markers', () => {
|
||||
]
|
||||
await mountHome('owner', {
|
||||
[ACTIVITY_ROUTE]: () => page(items),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
const marks = rows().map((row) => ({
|
||||
@@ -177,7 +178,7 @@ describe('Home rows, unknown action, failed login and not interactive', () => {
|
||||
]
|
||||
await mountHome('owner', {
|
||||
[ACTIVITY_ROUTE]: () => page(items),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
expect(rows()[0]!.text()).toContain('article.archive')
|
||||
@@ -188,7 +189,7 @@ describe('Home rows, unknown action, failed login and not interactive', () => {
|
||||
it('has no button or link inside a row and keeps the route on a click', async () => {
|
||||
await mountHome('owner', {
|
||||
[ACTIVITY_ROUTE]: () => page(recentItems(2)),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
const row = rows()[0]!
|
||||
@@ -202,7 +203,7 @@ describe('Home rows, unknown action, failed login and not interactive', () => {
|
||||
const items = [makeItem({ id: 1, target: target('article', '8', 'T'.repeat(150)) })]
|
||||
await mountHome('owner', {
|
||||
[ACTIVITY_ROUTE]: () => page(items),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
expect(rows()[0]!.find('[data-testid="recent-activity-sentence"]').classes()).toContain(
|
||||
@@ -223,7 +224,7 @@ describe('Home card, skeleton rows only after 150 ms', () => {
|
||||
new Promise((done) => {
|
||||
resolve = () => done(page(recentItems(5)))
|
||||
}),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
expect(card().attributes('aria-busy')).toBeUndefined()
|
||||
@@ -246,7 +247,7 @@ describe('Home card, skeleton rows only after 150 ms', () => {
|
||||
vi.useFakeTimers()
|
||||
await mountHome('owner', {
|
||||
[ACTIVITY_ROUTE]: () => page(recentItems(5)),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
await vi.advanceTimersByTimeAsync(200)
|
||||
|
||||
@@ -267,7 +268,7 @@ describe('Home card, error shows a retryable alert that leaves the page alone',
|
||||
attempt += 1
|
||||
return attempt === 1 ? (failure() as Response) : page(recentItems(2))
|
||||
},
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
const alert = card().find('[role="alert"]')
|
||||
@@ -292,7 +293,7 @@ describe('Home card, empty when there are no events yet', () => {
|
||||
])('says so for %s', async (role, text) => {
|
||||
await mountHome(role as 'owner', {
|
||||
[ACTIVITY_ROUTE]: () => page([], 0),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
const empty = card().find('[data-testid="recent-activity-empty"]')
|
||||
@@ -316,7 +317,7 @@ describe('Home card and article list are independent', () => {
|
||||
it('shows the articles empty state and the card error together', async () => {
|
||||
await mountHome('owner', {
|
||||
[ACTIVITY_ROUTE]: () => response(500),
|
||||
[ARTICLES_ROUTE]: () => response(200, []),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope([], { size: 5 })),
|
||||
})
|
||||
|
||||
expect(wrapper!.text()).toContain('Write your first article')
|
||||
@@ -328,7 +329,7 @@ describe('Home layout puts Recent activity full width below Recently updated', (
|
||||
it('renders the section after the recent list inside the same single column', async () => {
|
||||
await mountHome('owner', {
|
||||
[ACTIVITY_ROUTE]: () => page(recentItems(1)),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
const column = card().element.parentElement!
|
||||
@@ -344,7 +345,7 @@ describe('Home card, the request URL', () => {
|
||||
it('asks for exactly /v1/activity?size=5 and nothing else', async () => {
|
||||
await mountHome('owner', {
|
||||
[ACTIVITY_ROUTE]: () => page(recentItems(5)),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
const activityCalls = calls.filter((call) => call.includes('/v1/activity'))
|
||||
@@ -356,7 +357,7 @@ describe('Home card, "View all" opens the activity page', () => {
|
||||
it('navigates to /activity', async () => {
|
||||
await mountHome('owner', {
|
||||
[ACTIVITY_ROUTE]: () => page(recentItems(1)),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
const push = vi.spyOn(router, 'push')
|
||||
@@ -373,7 +374,7 @@ describe('Home card, the French interface', () => {
|
||||
setLocale('fr')
|
||||
await mountHome('owner', {
|
||||
[ACTIVITY_ROUTE]: () => page([], 0),
|
||||
[ARTICLES_ROUTE]: () => response(200, articles),
|
||||
[ARTICLES_ROUTE]: () => response(200, articleEnvelope(articles, { size: 5 })),
|
||||
})
|
||||
|
||||
expect(card().find('h2').text()).toBe('Activité récente')
|
||||
|
||||
Reference in new issue
Block a user