import router from '@/router' import { expect, vi } from 'vitest' import { flushPromises, type VueWrapper } from '@vue/test-utils' import EntryField from '@/components/EntryField.vue' import { addCollection } from '@iconify/vue' import lucide from 'virtual:lucide-subset' import { mountAt, text, type EntryWrite, type SchemaMount } from './schemaTestKit' export { button, calls, customTypes, entryWrites, failWith, failWithBody, networkFailure, pending, text, unmountAll, } from './schemaTestKit' export { MOBILE_WIDTH } from '@/components/__tests__/viewport' export { eventsFields } from '@/lib/__tests__/schemaFixtures' addCollection(lucide) export const MARTA = 3 export const INES = 4 export const JONAS = 5 export const entry42 = { id: 42, content_type: 'events', data: { title: 'Lime plaster workshop', starts_on: '2026-11-21', ends_on: '2026-11-22', online: false, capacity: 18, category: 'Workshop', description: 'Two days of hands-on work with **lime putty** and old stone.\n\n- Bring work clothes\n- Lunch is included', }, created_by: INES, updated_by: MARTA, created_at: '2026-10-12T09:14:00', updated_at: '2026-10-15T11:02:00', } export const userNames = [ { id: INES, display_name: 'Inès Duarte' }, { id: MARTA, display_name: 'Marta Alves' }, { id: JONAS, display_name: 'Jonas Pereira' }, ] export function lookupNames(ids: number[]) { return userNames.filter((user) => ids.includes(user.id)) } export function entryWith(data: Record, rest: Record = {}) { return { ...entry42, ...rest, data: { ...entry42.data, ...data } } } export function answerWrite(write: EntryWrite) { const data = write.body.data as Record const base = write.method === 'POST' ? { ...entry42, id: 43 } : entry42 return { ...base, data, updated_by: MARTA, updated_at: '2026-10-19T11:02:00', } } export function mountEditor(path: string, options: SchemaMount = {}) { return mountAt(path, { entry: () => entry42, writeEntry: answerWrite, lookup: lookupNames, ...options, }) } export async function settle() { await flushPromises() } export function fieldWrapper(key: string) { return document.body.querySelector(`[data-entry-field="${key}"]`)! } export function control(key: string) { return fieldWrapper(key).querySelector( 'input, textarea', )! } export async function typeInto(key: string, value: string) { const element = control(key) element.value = value element.dispatchEvent(new Event('input', { bubbles: true })) await flushPromises() } export function chip() { return document.body.querySelector('[data-testid="builder-chip"]') } export async function save() { document.body.querySelector('button[type="submit"]')!.click() await flushPromises() } export function setField(wrapper: VueWrapper, key: string, value: unknown) { const owner = wrapper .findAllComponents(EntryField) .find((candidate) => candidate.props('field').key === key)! owner.vm.$emit('update', key, value) return flushPromises() } export function main() { return document.body.querySelector('#dashboard-content')! } export function toast() { return text(document.body.querySelector('[data-part="root"], [role="status"][data-state]')) } export function hasText(value: string) { return text(document.body).includes(value) } export function messageUnder(key: string) { return text(fieldWrapper(key).querySelector('[role="alert"]')) } export async function arrived(path: string) { await vi.waitFor(() => expect(router.currentRoute.value.fullPath).toBe(path)) } export function installSelectPolyfills() { Element.prototype.scrollIntoView = vi.fn() Element.prototype.hasPointerCapture = vi.fn(() => false) Element.prototype.releasePointerCapture = vi.fn() } export async function openChoices(key: string) { const trigger = fieldWrapper(key).querySelector('[role="combobox"]')! trigger.dispatchEvent( Object.assign(new MouseEvent('pointerdown', { bubbles: true, button: 0 }), { pointerType: 'mouse', }), ) await flushPromises() return [...document.body.querySelectorAll('[role="option"]')] }