WP-02: contracts and failing tests for settings, mail, jobs and scheduler
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / ui (push) Has been cancelled

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-09-02 22:08:23 +02:00
parent 12269051c4
commit 6113af0a19
21 changed files with 1115 additions and 0 deletions

View File

@ -0,0 +1,33 @@
import { mount } from '@vue/test-utils'
import SmtpForm from './SmtpForm.vue'
const current = {
host: 'mail.example.com',
port: 587,
security: 'starttls' as const,
username: 'bot',
from: 'mon@example.com',
notify_to: ['ops@example.com', 'dev@example.com'],
password_set: true,
}
describe('SmtpForm', () => {
it('prefills current settings and emits the payload with recipients as a list', async () => {
const w = mount(SmtpForm, { props: { current } })
expect((w.find('input[name=host]').element as HTMLInputElement).value).toBe('mail.example.com')
expect((w.find('input[name=notify_to]').element as HTMLInputElement).value).toBe(
'ops@example.com, dev@example.com',
)
await w.find('input[name=notify_to]').setValue('a@x.de; b@x.de')
await w.find('form').trigger('submit')
const payload = w.emitted('submit')![0][0] as Record<string, unknown>
expect(payload.notify_to).toEqual(['a@x.de', 'b@x.de'])
expect(payload.password).toBe('')
expect(payload.port).toBe(587)
})
it('shows a hint that a password is stored', () => {
const w = mount(SmtpForm, { props: { current } })
expect(w.text()).toContain('leave empty to keep')
})
})

View File

@ -0,0 +1,52 @@
import { mount, flushPromises } from '@vue/test-utils'
import { createPinia, setActivePinia } from 'pinia'
import JobsPage from './JobsPage.vue'
import { useAuthStore } from '../stores/auth'
import { api } from '../api/client'
vi.mock('../api/client', () => ({
api: { get: vi.fn(), post: vi.fn(), patch: vi.fn() },
ApiError: class extends Error {},
}))
const run = {
id: 'r1',
kind: 'package_refresh',
status: 'success',
started_at: '2026-09-02T10:00:00Z',
finished_at: '2026-09-02T10:00:05Z',
log: 'hello\n',
triggered_by: 'admin@example.com',
}
beforeEach(() => {
setActivePinia(createPinia())
vi.mocked(api.get).mockImplementation(async (path: string) => {
if (path.startsWith('/api/jobs/kinds')) return ['package_refresh']
return [run]
})
})
describe('JobsPage', () => {
it('lists runs and lets an admin run a job', async () => {
const auth = useAuthStore()
auth.user = { id: '1', email: 'a', display_name: 'A', role: 'admin', is_active: true }
vi.mocked(api.post).mockResolvedValue({ ...run, id: 'r2', status: 'running' })
const w = mount(JobsPage)
await flushPromises()
expect(w.text()).toContain('package_refresh')
expect(w.text()).toContain('success')
await w.find('select[name=kind]').setValue('package_refresh')
await w.find('button[name=run]').trigger('click')
await flushPromises()
expect(api.post).toHaveBeenCalledWith('/api/jobs/run', { kind: 'package_refresh' })
})
it('hides the run control for non-admins', async () => {
const auth = useAuthStore()
auth.user = { id: '1', email: 'a', display_name: 'A', role: 'user', is_active: true }
const w = mount(JobsPage)
await flushPromises()
expect(w.find('button[name=run]').exists()).toBe(false)
})
})