fix(SPA): activity list saves pagination too
This commit is contained in:
1 parent
9d9453c1b3
commit
c41e6dbca5
5 files changed
+193
-4
No files matched your search
@@ -0,0 +1,129 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { flushPromises } from '@vue/test-utils'
|
||||
import router from '@/router'
|
||||
import { useApi } from '@/composables/useApi'
|
||||
import { initializeLocale } from '@/i18n'
|
||||
import ActivityPager from '@/components/ActivityPager.vue'
|
||||
import {
|
||||
harness,
|
||||
lastListQuery,
|
||||
mountActivity,
|
||||
queryObject,
|
||||
unmountActivity,
|
||||
} from './activityHarness'
|
||||
import { activityItems, pageOf } from './activityFixtures'
|
||||
|
||||
vi.mock('@/composables/useApi', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@/composables/useApi')>()
|
||||
return { ...actual, useApi: vi.fn() }
|
||||
})
|
||||
|
||||
vi.mock('@nuxt/ui/composables', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@nuxt/ui/composables')>()
|
||||
return { ...actual, useToast: () => ({ add: vi.fn() }) }
|
||||
})
|
||||
|
||||
const KEY = 'renewcms-page-size-activity'
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear()
|
||||
initializeLocale()
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
vi.restoreAllMocks()
|
||||
unmountActivity()
|
||||
vi.mocked(useApi).mockReset()
|
||||
await router.push('/login')
|
||||
})
|
||||
|
||||
function list(query: URLSearchParams) {
|
||||
return pageOf(activityItems, {
|
||||
page: Number(query.get('page')),
|
||||
size: Number(query.get('size')),
|
||||
})
|
||||
}
|
||||
|
||||
async function chooseSize(size: number) {
|
||||
harness.wrapper!.findComponent(ActivityPager).vm.$emit('update:size', size)
|
||||
await flushPromises()
|
||||
}
|
||||
|
||||
function url() {
|
||||
return router.currentRoute.value.fullPath
|
||||
}
|
||||
|
||||
describe('Activity list remembers the chosen page size', () => {
|
||||
it('stores the size, shows it in the URL and restores it on the next visit', async () => {
|
||||
await mountActivity({ list })
|
||||
expect(queryObject(lastListQuery()).size).toBe('25')
|
||||
expect(url()).toBe('/activity')
|
||||
|
||||
await chooseSize(50)
|
||||
expect(localStorage.getItem(KEY)).toBe('50')
|
||||
expect(queryObject(lastListQuery())).toMatchObject({ page: '1', size: '50' })
|
||||
expect(url()).toBe('/activity?size=50')
|
||||
|
||||
unmountActivity()
|
||||
await mountActivity({ list })
|
||||
expect(queryObject(lastListQuery()).size).toBe('50')
|
||||
expect(harness.wrapper!.findComponent(ActivityPager).props('size')).toBe(50)
|
||||
expect(url()).toBe('/activity?size=50')
|
||||
})
|
||||
|
||||
it('drops size from the URL and stores 25 when returning to the default', async () => {
|
||||
localStorage.setItem(KEY, '100')
|
||||
await mountActivity({ list })
|
||||
expect(url()).toBe('/activity?size=100')
|
||||
await chooseSize(25)
|
||||
expect(localStorage.getItem(KEY)).toBe('25')
|
||||
expect(url()).toBe('/activity')
|
||||
})
|
||||
|
||||
it('lets a valid size in the URL win without storing it', async () => {
|
||||
localStorage.setItem(KEY, '50')
|
||||
await mountActivity({ list, path: '/activity?size=100' })
|
||||
expect(queryObject(lastListQuery()).size).toBe('100')
|
||||
expect(localStorage.getItem(KEY)).toBe('50')
|
||||
expect(url()).toBe('/activity?size=100')
|
||||
})
|
||||
|
||||
it('falls back to 25 for an invalid size in the URL, ignoring the stored one', async () => {
|
||||
localStorage.setItem(KEY, '50')
|
||||
await mountActivity({ list, path: '/activity?size=10' })
|
||||
expect(queryObject(lastListQuery()).size).toBe('25')
|
||||
expect(localStorage.getItem(KEY)).toBe('50')
|
||||
expect(url()).toBe('/activity')
|
||||
})
|
||||
|
||||
it('keeps other query parameters when the size changes', async () => {
|
||||
await mountActivity({ list, path: '/activity?foo=bar' })
|
||||
await chooseSize(50)
|
||||
expect(url()).toBe('/activity?foo=bar&size=50')
|
||||
})
|
||||
|
||||
it.each(['10', 'abc', '5', '0', '-25', '25.5', ''])(
|
||||
'ignores the stored value %j and uses 25',
|
||||
async (stored) => {
|
||||
localStorage.setItem(KEY, stored)
|
||||
await mountActivity({ list })
|
||||
expect(queryObject(lastListQuery()).size).toBe('25')
|
||||
expect(url()).toBe('/activity')
|
||||
},
|
||||
)
|
||||
|
||||
it('keeps working when storage throws on read or write', async () => {
|
||||
vi.spyOn(Storage.prototype, 'getItem').mockImplementation(() => {
|
||||
throw new Error('blocked')
|
||||
})
|
||||
vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {
|
||||
throw new Error('quota')
|
||||
})
|
||||
await mountActivity({ list })
|
||||
expect(queryObject(lastListQuery()).size).toBe('25')
|
||||
|
||||
await chooseSize(100)
|
||||
expect(queryObject(lastListQuery())).toMatchObject({ page: '1', size: '100' })
|
||||
expect(url()).toBe('/activity?size=100')
|
||||
})
|
||||
})
|
||||
@@ -28,6 +28,7 @@ export interface MountOptions extends ActivityApiMock {
|
||||
role?: string
|
||||
desktop?: boolean
|
||||
verified?: boolean
|
||||
path?: string
|
||||
}
|
||||
|
||||
export interface RecordedCall {
|
||||
@@ -69,7 +70,7 @@ export function callsTo(path: string) {
|
||||
}
|
||||
|
||||
export async function mountActivity(options: MountOptions = {}) {
|
||||
const { desktop = true, verified = true } = options
|
||||
const { desktop = true, verified = true, path = '/activity' } = options
|
||||
const role = 'role' in options ? options.role : 'owner'
|
||||
const api: ActivityApiMock = {
|
||||
list: () => pageOf(activityItems),
|
||||
@@ -126,7 +127,7 @@ export async function mountActivity(options: MountOptions = {}) {
|
||||
requestBlob,
|
||||
} as unknown as ReturnType<typeof useApi>)
|
||||
|
||||
await router.push('/activity')
|
||||
await router.push(path)
|
||||
harness.wrapper = mount(ActivityView, {
|
||||
attachTo: document.body,
|
||||
global: { plugins: [router, uiPlugin] },
|
||||
|
||||
Reference in new issue
Block a user