Files
tickte-system/tests/unit/workersFocus.test.mjs
ClaudeandClaude Sonnet 5.5 c48d1834f4 Endprüfung Nachrunde R8: restoreFocus fokussiert mit preventScroll
Ohne die Option springt die Seite beim Zurückgeben des Fokus zum Ziel: bei einer Zeile weit unten in
einer langen Liste zur Meldung oben, und die Person verliert ihre Stelle. restoreFocus ruft jetzt
target.focus({ preventScroll: true }); der Fokus (und damit die Ansage) wandert, die Ansicht bleibt stehen.
Die Attrappe in workersFocus.test.mjs merkt sich die Argumente, ein neuer Test pinnt genau einen Aufruf
mit dieser Option.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 23:53:22 +00:00

69 lines
4.0 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { loadModule } from './load.mjs'
// Fokus nach Pult-Aktionen (Endprüfung P4, W3): ein gesperrter Knopf verliert den Fokus an <body>; die Zeile gibt ihn danach zurück,
// aber nur, wenn er wirklich verloren ging. Reine Logik mit einer document-Attrappe, kein DOM nötig.
const { activeControl, focusLost, restoreFocus } = await loadModule('src/lib/workersFocus.js')
function fakeDoc() {
const body = { name: 'body' }
const doc = { body, documentElement: { name: 'html' }, activeElement: body }
const el = (name, extra = {}) => ({ name, isConnected: true, disabled: false, focusCalls: 0, focusArgs: [], focus(...args) { this.focusCalls += 1; this.focusArgs.push(args); doc.activeElement = this }, ...extra })
return { doc, body, el }
}
test('focusLost: body, Wurzel, nichts, gesperrtes oder ausgehängtes Element gelten als verloren, ein bedienbares Element nicht', () => {
const { doc, body, el } = fakeDoc()
assert.equal(focusLost(doc), true) // activeElement = body
doc.activeElement = doc.documentElement; assert.equal(focusLost(doc), true)
for (const nothing of [null, undefined]) { doc.activeElement = nothing; assert.equal(focusLost(doc), true, String(nothing)) }
doc.activeElement = el('a', { disabled: true }); assert.equal(focusLost(doc), true) // der Browser lässt es erst beim nächsten Takt los
doc.activeElement = el('b', { isConnected: false }); assert.equal(focusLost(doc), true)
doc.activeElement = el('c'); assert.equal(focusLost(doc), false)
// ohne document (Node, Server) gibt es nichts zurückzugeben
for (const none of [null, undefined]) assert.equal(focusLost(none), false)
assert.equal(body.name, 'body')
})
test('activeControl: das fokussierte Bedienelement, sonst null (body und Wurzel zählen nicht)', () => {
const { doc, el } = fakeDoc()
assert.equal(activeControl(doc), null)
doc.activeElement = doc.documentElement; assert.equal(activeControl(doc), null)
doc.activeElement = null; assert.equal(activeControl(doc), null)
const button = el('button'); doc.activeElement = button
assert.equal(activeControl(doc), button)
assert.equal(activeControl(null), null); assert.equal(activeControl(undefined), null)
})
test('restoreFocus: nimmt den ersten Kandidaten, der noch da und frei ist; greift nur ein, wenn der Fokus verloren ging', () => {
const { doc, body, el } = fakeDoc()
const gone = el('gone', { isConnected: false })
const locked = el('locked', { disabled: true })
const first = el('first')
const second = el('second')
assert.equal(restoreFocus(doc, [null, undefined, gone, locked, first, second]), true)
assert.equal(doc.activeElement, first); assert.deepEqual([first.focusCalls, second.focusCalls, gone.focusCalls, locked.focusCalls], [1, 0, 0, 0])
// der Fokus liegt woanders (die Person hat inzwischen selbst gewählt): nichts wird angefasst
const other = el('other'); doc.activeElement = other
assert.equal(restoreFocus(doc, [first]), false)
assert.equal(doc.activeElement, other); assert.equal(first.focusCalls, 1)
// kein brauchbarer Kandidat, kein document, keine Liste: false, nichts passiert
doc.activeElement = body
assert.equal(restoreFocus(doc, [null, gone, locked]), false); assert.equal(doc.activeElement, body)
assert.equal(restoreFocus(null, [first]), false); assert.equal(restoreFocus(doc, []), false)
// Dinge ohne focus() (Attrappen, Textknoten) werden übersprungen
assert.equal(restoreFocus(doc, [{ isConnected: true }, 'text', 7, second]), true); assert.equal(doc.activeElement, second)
})
// Die Meldung oben (oder eine Zeile weit unten in einer langen Liste) darf den Fokus bekommen, ohne dass die Seite dorthin springt (Nachrunde R8)
test('restoreFocus: fokussiert mit preventScroll, damit die Seite nicht zur Meldung oder Zeile springt', () => {
const { doc, el } = fakeDoc()
const target = el('meldung')
assert.equal(restoreFocus(doc, [target]), true)
assert.equal(doc.activeElement, target)
assert.deepEqual(target.focusArgs, [[{ preventScroll: true }]]) // genau ein Aufruf, genau diese Option
})