You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/sema/verbs.test.ts

211 lines
6.8 KiB

import { describe, expect, it } from 'vitest'
import { SEMA_VERBS, isSemaVerb, validateEventName, familyForVerb } from './verbs'
describe('SEMA_VERBS', () => {
it('groups verbs by family per book canon', () => {
// Canonical verbs per «Diseñando lo que ocurre» cap. 22-29
expect(SEMA_VERBS.contact).toContain('press')
expect(SEMA_VERBS.commit).toContain('toggle')
expect(SEMA_VERBS.commit).toContain('save')
expect(SEMA_VERBS.signal).toContain('announce')
expect(SEMA_VERBS.signal).toContain('warn')
expect(SEMA_VERBS.signal).toContain('inform') // cap. 24
expect(SEMA_VERBS.handle).toContain('drag')
expect(SEMA_VERBS.emerge).toContain('present')
expect(SEMA_VERBS.emerge).toContain('dismiss')
expect(SEMA_VERBS.shift).toContain('enter-mode')
expect(SEMA_VERBS.sustain).toContain('progress')
})
it('exposes the delegate family (book cap. 29)', () => {
// Eighth family: who acts. Required for workflows, IA, macros,
// rule-based automation. Per book Apéndice C case 3.
expect(SEMA_VERBS.delegate).toContain('offer')
expect(SEMA_VERBS.delegate).toContain('plan')
expect(SEMA_VERBS.delegate).toContain('authorize')
expect(SEMA_VERBS.delegate).toContain('act')
expect(SEMA_VERBS.delegate).toContain('review')
expect(SEMA_VERBS.delegate).toContain('escalate')
expect(SEMA_VERBS.delegate).toContain('return')
})
it('exposes contextual commit verbs used in the book case studies', () => {
// cap. 29 + cap. 30 + apéndice C
expect(SEMA_VERBS.commit).toContain('apply')
expect(SEMA_VERBS.commit).toContain('partial')
expect(SEMA_VERBS.commit).toContain('block')
expect(SEMA_VERBS.commit).toContain('upload')
})
it('has no internal duplicates per family', () => {
for (const verbs of Object.values(SEMA_VERBS)) {
expect(new Set(verbs).size).toBe(verbs.length)
}
})
it('moved select / toggle / acknowledge to commit (per doctrine)', () => {
// These were `contact` / `handle` in pre-doctrina shape.
expect(SEMA_VERBS.commit).toContain('select')
expect(SEMA_VERBS.commit).toContain('toggle')
expect(SEMA_VERBS.commit).toContain('acknowledge')
expect(SEMA_VERBS.contact as readonly string[]).not.toContain('select')
expect(SEMA_VERBS.contact as readonly string[]).not.toContain('toggle')
expect(SEMA_VERBS.handle as readonly string[]).not.toContain('acknowledge')
})
})
describe('isSemaVerb', () => {
it('accepts canonical verbs', () => {
expect(isSemaVerb('present')).toBe(true)
expect(isSemaVerb('toggle')).toBe(true)
expect(isSemaVerb('save')).toBe(true)
})
it('rejects non-canonical strings', () => {
expect(isSemaVerb('frob')).toBe(false)
expect(isSemaVerb('commit-save')).toBe(false) // composite, not a verb
})
it('rejects family names (they are not verbs)', () => {
expect(isSemaVerb('commit')).toBe(false)
expect(isSemaVerb('emerge')).toBe(false)
expect(isSemaVerb('signal')).toBe(false)
expect(isSemaVerb('delegate')).toBe(false)
})
it('rejects non-strings', () => {
expect(isSemaVerb(undefined)).toBe(false)
expect(isSemaVerb(42)).toBe(false)
expect(isSemaVerb(null)).toBe(false)
})
})
describe('familyForVerb', () => {
it('resolves the family of a canonical verb', () => {
expect(familyForVerb('press')).toBe('contact')
expect(familyForVerb('toggle')).toBe('commit')
expect(familyForVerb('dismiss')).toBe('emerge')
expect(familyForVerb('warn')).toBe('signal')
expect(familyForVerb('inform')).toBe('signal')
expect(familyForVerb('drag')).toBe('handle')
expect(familyForVerb('enter-mode')).toBe('shift')
expect(familyForVerb('progress')).toBe('sustain')
expect(familyForVerb('authorize')).toBe('delegate')
expect(familyForVerb('escalate')).toBe('delegate')
})
it('returns undefined for non-canonical strings', () => {
expect(familyForVerb('frob')).toBeUndefined()
expect(familyForVerb('commit')).toBeUndefined() // family name, not a verb
})
})
describe('validateEventName', () => {
it('matches a bare canonical verb', () => {
expect(validateEventName('dismiss')).toEqual({
name: 'dismiss',
head: 'dismiss',
matchesCanonical: true,
variant: undefined,
family: 'emerge',
verb: 'dismiss'
})
})
it('extracts head + variant from verb-variant composites', () => {
expect(validateEventName('dismiss-outside')).toEqual({
name: 'dismiss-outside',
head: 'dismiss',
matchesCanonical: true,
variant: 'outside',
family: 'emerge',
verb: 'dismiss'
})
expect(validateEventName('close-cancel')).toEqual({
name: 'close-cancel',
head: 'close',
matchesCanonical: true,
variant: 'cancel',
family: 'emerge',
verb: 'close'
})
})
it('parses family-verb naming (doctrinal shape)', () => {
expect(validateEventName('commit-toggle')).toEqual({
name: 'commit-toggle',
head: 'commit',
matchesCanonical: true,
variant: 'toggle',
family: 'commit',
verb: 'toggle'
})
expect(validateEventName('commit-save')).toEqual({
name: 'commit-save',
head: 'commit',
matchesCanonical: true,
variant: 'save',
family: 'commit',
verb: 'save'
})
})
it('flags drift when neither head nor family.verb is canonical', () => {
expect(validateEventName('frob-glob')).toEqual({
name: 'frob-glob',
head: 'frob',
matchesCanonical: false,
variant: 'glob',
family: undefined,
verb: undefined
})
})
it('flags drift when family is canonical but the verb is not', () => {
expect(validateEventName('commit-frob').matchesCanonical).toBe(false)
expect(validateEventName('commit-frob').family).toBe('commit')
})
it('recognises multi-word canonical verbs (enter-mode, exit-mode)', () => {
// Family-verb shape with multi-word verb.
expect(validateEventName('shift-enter-mode')).toEqual({
name: 'shift-enter-mode',
head: 'shift',
matchesCanonical: true,
variant: 'enter-mode',
family: 'shift',
verb: 'enter-mode'
})
expect(validateEventName('shift-exit-mode').matchesCanonical).toBe(true)
// With trailing variant.
expect(validateEventName('shift-enter-mode-edit').matchesCanonical).toBe(true)
expect(validateEventName('shift-enter-mode-edit').verb).toBe('enter-mode')
// Bare verb shape — `enter-mode` alone is canonical.
expect(validateEventName('enter-mode').matchesCanonical).toBe(true)
expect(validateEventName('enter-mode').verb).toBe('enter-mode')
expect(validateEventName('enter-mode').family).toBe('shift')
})
it('reports the existing dialog event names against the catalog', () => {
const dialogEvents = [
'open',
'close-save',
'close-cancel',
'close-dismiss',
'close-dismiss-outside',
'close-after-fail'
]
for (const name of dialogEvents) {
const v = validateEventName(name)
expect(v.matchesCanonical).toBe(true)
}
})
it('reports the existing toast event names against the catalog', () => {
for (const name of ['present', 'announce', 'dismiss']) {
expect(validateEventName(name).matchesCanonical).toBe(true)
}
})
})

Powered by TurnKey Linux.