158 lines
4.1 KiB
TypeScript
158 lines
4.1 KiB
TypeScript
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<string, unknown>, rest: Record<string, unknown> = {}) {
|
|
return { ...entry42, ...rest, data: { ...entry42.data, ...data } }
|
|
}
|
|
|
|
export function answerWrite(write: EntryWrite) {
|
|
const data = write.body.data as Record<string, unknown>
|
|
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<HTMLElement>(`[data-entry-field="${key}"]`)!
|
|
}
|
|
|
|
export function control(key: string) {
|
|
return fieldWrapper(key).querySelector<HTMLInputElement | HTMLTextAreaElement>(
|
|
'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<HTMLButtonElement>('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<HTMLElement>('[role="option"]')]
|
|
}
|