import type { Page } from 'playwright' import { accessFor } from '../src/test/access' import { siteLanguagesBody, storyAuthorsBody, storyPageFor, type StoryViewer, } from '../src/test/storyLists' import type { ApiMock, VisualState } from './states' const ok = (body: unknown): ApiMock => ({ status: 200, body }) function site(id: number, key: string, name: string, isDefault = false) { return { id, name, key, site_name: name, title_template: '%title% | %site%', default_description: '', base_url: `https://${key}.example.com`, default_social_image_id: null, default_robots: 'index', locale: 'en', is_default: isDefault, article_count: 0, public_url_pattern: null, } } const sites = [ site(1, 'journal', 'Journal', true), site(2, 'atelier', 'Atelier'), site(3, 'press', 'Press'), ] function session(access: unknown): ApiMock { return { status: 200, body: { id: 1, is_verified: true, username: 'marta', email: 'marta@renew.example', display_name: 'Marta Alves', access, }, } } export function listApi( overrides: Record = {}, viewer: StoryViewer = {}, access: unknown = accessFor('owner'), ): Record { return { 'GET /v1/auth/me': session(access), 'GET /v1/site/': ok(sites), 'GET /v1/site/journal/languages': { status: 200, bodyFor: () => siteLanguagesBody('journal'), }, 'GET /v1/site/atelier/languages': { status: 200, bodyFor: () => siteLanguagesBody('atelier'), }, 'GET /v1/site/press/languages': { status: 200, bodyFor: () => siteLanguagesBody('press') }, 'GET /v1/author/': { status: 200, bodyFor: () => storyAuthorsBody() }, 'GET /v1/article/': { status: 200, bodyFor: (url) => storyPageFor(url, viewer) }, ...overrides, } } const clockSensitive = (path: string): VisualState => ({ path, skip: 'clock-sensitive' }) async function scrollTabsRight(page: Page) { const button = page.getByRole('button', { name: 'Scroll tabs right', exact: true }) if (await button.isVisible()) { await button.click() await page.mouse.move(0, 0) } } export const articleListStates: Record = { 'loc.l7.all': clockSensitive('/article?site=journal&size=5'), 'loc.l7.page2': { path: '/article?site=journal&page=2&size=5', api: listApi() }, 'loc.l7.fr': clockSensitive('/article?site=journal&lang=fr&size=5'), 'loc.l7.frMissing': { path: '/article?site=journal&lang=fr&tab=missing&size=5', api: listApi(), }, 'loc.l7.emptyMissing': { path: '/article?site=press&lang=fr&tab=missing&size=5', api: listApi(), }, 'loc.l7.noResults': { path: '/article?site=journal&q=zinc&size=5', api: listApi() }, 'loc.l7.frLoading': { path: '/article?site=journal&lang=fr&size=5', api: listApi({ 'GET /v1/article/': { status: 200, hang: true } }), steps: async (page) => { await page.waitForTimeout(400) }, }, 'loc.l7.listFail': { path: '/article?site=journal&size=5', api: listApi({ 'GET /v1/article/': { status: 500, body: 'Failed to retrieve articles' } }), }, 'loc.l7.limited': clockSensitive('/article?site=journal&size=5'), 'loc.l7.review': { path: '/article?site=journal&size=5', skip: 'pending' }, 'loc.l7.author': clockSensitive('/article?site=journal&author=1&size=5'), 'loc.l7.langFilter': clockSensitive('/article?site=journal&size=5'), 'loc.l7.rowMenu': clockSensitive('/article?site=journal&size=5'), 'loc.l7.filters': clockSensitive('/article?site=journal&lang=fr&status=draft&size=5'), 'loc.l7.tabsScroll': { path: '/article?site=journal&lang=fr&tab=missing&size=5', api: listApi(), steps: scrollTabsRight, }, 'loc.l7.long': clockSensitive('/article?site=atelier&status=draft&seo=suggestions&size=5'), }