feat: article editor core

This commit is contained in:
fsylvain committed 2026-09-27 02:11:38 +02:00
1 parent d493a181e1
commit a4734b2c91
55 files changed
+4186 -496

No files matched your search

+25 -8
View File
@@ -7,7 +7,11 @@ import { useSessionStore } from '@/stores/session'
import type { Article } from '@/composables/useArticles'
import HomeView from '../HomeView.vue'
function mockResponse(status: number, body: unknown = null, headers: Record<string, string> = {}) {
function mockResponse(
status: number,
body: unknown = null,
headers: Record<string, string> = {},
) {
return {
ok: status >= 200 && status < 300,
status,
@@ -21,7 +25,9 @@ function routeFor(url: string, init?: RequestInit) {
return `${method} ${url}`
}
function fetchRouter(handlers: Record<string, () => Response | Promise<Response>>) {
function fetchRouter(
handlers: Record<string, () => Response | Promise<Response>>,
) {
return vi.fn((url: string, init?: RequestInit) => {
const key = routeFor(url, init)
const handler = handlers[key]
@@ -91,7 +97,9 @@ const sixArticles: Article[] = [
let currentWrapper: Awaited<ReturnType<typeof mount>> | null = null
async function mountHome(handlers: Record<string, () => Response | Promise<Response>>) {
async function mountHome(
handlers: Record<string, () => Response | Promise<Response>>,
) {
setActivePinia(createPinia())
const session = useSessionStore()
session.session = { verified: true, username: 'marta' }
@@ -149,7 +157,8 @@ describe('Skeletons appear only after 150 ms, never for a fast response', () =>
it('never shows a skeleton when the response resolves in under 150 ms', async () => {
vi.useFakeTimers()
const wrapper = await mountHome({
'GET /v1/article/': () => Promise.resolve(mockResponse(200, sixArticles)),
'GET /v1/article/': () =>
Promise.resolve(mockResponse(200, sixArticles)),
})
await vi.advanceTimersByTimeAsync(0)
@@ -166,7 +175,9 @@ describe('Default — the list loaded with a mix of online and draft articles',
'GET /v1/article/': () => mockResponse(200, sixArticles),
})
expect(wrapper.text()).toContain("Here's where things stand on your site.")
expect(wrapper.text()).toContain(
"Here's where things stand on your site.",
)
const rows = wrapper.find('[data-testid="recent-list"]').findAll('li')
expect(rows).toHaveLength(5)
@@ -185,7 +196,9 @@ describe('Default — the list loaded with a mix of online and draft articles',
expect(wrapper.text()).toContain('2')
expect(wrapper.text()).toContain('drafts')
const guideLink = wrapper.findAll('a').find((a) => a.text() === 'Open the guide')
const guideLink = wrapper
.findAll('a')
.find((a) => a.text() === 'Open the guide')
expect(guideLink?.attributes('href')).toBe('/integration')
await findButton(wrapper, 'New article')?.trigger('click')
@@ -226,7 +239,9 @@ describe('Error — a 500 or a network failure shows the same inline alert', ()
'GET /v1/article/': handler,
})
expect(wrapper.text()).toContain("Here's where things stand on your site.")
expect(wrapper.text()).toContain(
"Here's where things stand on your site.",
)
expect(wrapper.text()).toContain('Good')
const alert = wrapper.find('[role="alert"]')
expect(alert.exists()).toBe(true)
@@ -267,7 +282,9 @@ describe('The list is fetched exactly once per navigation', () => {
expect(listCall).toHaveBeenCalledTimes(1)
expect(wrapper.text()).toContain('6')
expect(wrapper.find('[data-testid="recent-list"]').findAll('li')).toHaveLength(5)
expect(
wrapper.find('[data-testid="recent-list"]').findAll('li'),
).toHaveLength(5)
})
})