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, setLocale } from '@/i18n' import { EXPORT_PATH, LIST_PATH, SUMMARY_PATH, callsTo, days, findButton, mountActivity, queryObject, rows, stripCards, textOf, unmountActivity, } from './activityHarness' import { activityItems, makeItem, pageOf, summaryDefault } from './activityFixtures' vi.mock('@/composables/useApi', async (importOriginal) => { const actual = await importOriginal() return { ...actual, useApi: vi.fn() } }) let toastAdd: ReturnType vi.mock('@nuxt/ui/composables', async (importOriginal) => { const actual = await importOriginal() return { ...actual, useToast: () => ({ add: toastAdd }) } }) beforeEach(() => { toastAdd = vi.fn() localStorage.clear() initializeLocale() }) afterEach(async () => { unmountActivity() vi.mocked(useApi).mockReset() localStorage.clear() initializeLocale() await router.push('/login') }) describe('My activity: a role that is not owner or admin sees its own events', () => { it.each([['editor'], [undefined]])('role %s', async (role) => { await mountActivity({ role, list: () => pageOf(activityItems, { total: 41 }), }) expect(textOf(document.body.querySelector('h1'))).toBe('My activity') expect(textOf(document.body.querySelector('nav[aria-label="breadcrumb"]'))).toBe( 'My activity', ) expect(textOf(document.body)).toContain("Everything you've done on this site.") expect(stripCards()).toHaveLength(0) expect(textOf(document.body)).not.toContain('All people') expect(findButton('Export')).toBeUndefined() const headers = Array.from(document.body.querySelectorAll('[role="columnheader"]')).map( textOf, ) expect(headers).toEqual(['When', 'Action', 'Target', 'Outcome']) expect(document.body.querySelector('[data-testid="activity-actor"]')).toBeNull() expect(callsTo(SUMMARY_PATH)).toHaveLength(0) expect(callsTo(EXPORT_PATH)).toHaveLength(0) expect(queryObject(callsTo(LIST_PATH)[0])).toEqual({ range: '7d', page: '1', size: '25', }) expect(textOf(document.body.querySelector('[data-testid="activity-pager"]'))).toContain( 'Showing 1–25 of 41', ) }) it('shows no actor line on the cards below md', async () => { await mountActivity({ role: 'editor', desktop: false }) expect(rows()).toHaveLength(activityItems.length) expect(document.body.querySelector('[data-testid="activity-actor"]')).toBeNull() }) it('shows its own empty copy', async () => { await mountActivity({ role: 'editor', list: () => pageOf([], { total: 0 }), }) expect(textOf(document.body)).toContain('No activity yet') expect(textOf(document.body)).toContain( 'Your actions will appear here once you start working on the site.', ) }) it('shows the same details panel with the user position', async () => { await mountActivity({ role: 'editor', list: () => pageOf(activityItems, { total: 41 }), }) rows()[0]!.click() await flushPromises() await vi.waitFor(() => expect(document.body.querySelector('[role="dialog"]')).toBeTruthy()) expect(textOf(document.body.querySelector('[role="dialog"]'))).toContain('Event 1 of 41') expect((findButton('Previous event') as HTMLButtonElement).disabled).toBe(true) expect(textOf(document.body.querySelector('[data-testid="activity-actor"]'))).toBe( 'MAMarta Alves', ) }) }) describe('The French interface', () => { it('composes the chrome, the strip, the sentences and the day separators in French', async () => { setLocale('fr') await mountActivity({ summary: () => summaryDefault, list: () => pageOf([ makeItem({ id: 1, created_at: '2026-10-03T12:30:00Z' }), makeItem({ id: 2, created_at: '2026-10-03T12:20:00Z', outcome: 'failed', target: { type: 'article', id: '8', name: 'Spring release', exists: true, }, }), ]), }) expect(textOf(document.body.querySelector('h1'))).toBe('Activité') expect(textOf(findButton('Exporter'))).toBe('Exporter') const strip = stripCards().map(textOf) expect(strip[0]).toContain('Actions au total') expect(strip[1]).toContain('Personnes actives') expect(strip[1]).toContain('7 personnes') expect(strip[2]).toContain('Actions en échec') expect(strip[3]).toContain('Événements de sécurité') expect(strip[3]).toContain('11 signalés') expect(days()).toEqual(['3 oct. 2026']) const sentences = Array.from( document.body.querySelectorAll('[data-testid="activity-sentence"]'), ).map(textOf) expect(sentences).toEqual([ 'Article publié : Spring release', "Échec de la publication de l'article Spring release", ]) const search = document.body.querySelector('input[type="text"]')! expect(search.placeholder).toBe("Rechercher dans l'activité") expect(textOf(document.body.querySelector('[data-testid="activity-pager"]'))).toContain( 'Lignes par page', ) expect(textOf(rows()[0]!)).toContain('Réussie') expect(textOf(rows()[1]!)).toContain('Échec') }) it('shows the French My activity title', async () => { setLocale('fr') await mountActivity({ role: 'editor' }) expect(textOf(document.body.querySelector('h1'))).toBe('Mon activité') }) })