a66bd2b05c
deleteWithUndo in ux.js: onDelete ausführen, Undo-Toast anzeigen. Birthdays migriert; Contacts/Notes/Meals haben bereits optimistische Undo-Logik.
76 lines
2.4 KiB
JavaScript
76 lines
2.4 KiB
JavaScript
/**
|
|
* Tests: UX Utilities (stagger, vibrate)
|
|
* Läuft im Node-Kontext - kein DOM verfügbar, daher nur Pure-Logic-Tests.
|
|
*/
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
// Minimales Window/Navigator-Mock für Node
|
|
const { stagger, vibrate, deleteWithUndo } = await (async () => {
|
|
global.window = {
|
|
matchMedia: () => ({ matches: false }),
|
|
oikos: { showToast: () => {} },
|
|
};
|
|
global.t = (k) => k;
|
|
Object.defineProperty(global, 'navigator', {
|
|
value: { vibrate: null },
|
|
writable: true,
|
|
configurable: true,
|
|
});
|
|
return import('./public/utils/ux.js');
|
|
})();
|
|
|
|
test('stagger: setzt opacity:0 auf alle Elemente', () => {
|
|
const els = [{ style: {} }, { style: {} }, { style: {} }];
|
|
stagger(els, { delay: 0, duration: 0 });
|
|
assert.equal(els[0].style.opacity, '0');
|
|
assert.equal(els[1].style.opacity, '0');
|
|
assert.equal(els[2].style.opacity, '0');
|
|
});
|
|
|
|
test('stagger: tut nichts bei prefers-reduced-motion', () => {
|
|
global.window.matchMedia = () => ({ matches: true });
|
|
const els = [{ style: {} }];
|
|
stagger(els);
|
|
assert.equal(els[0].style.opacity, undefined); // unverändert
|
|
global.window.matchMedia = () => ({ matches: false }); // reset
|
|
});
|
|
|
|
test('vibrate: tut nichts wenn API nicht vorhanden', () => {
|
|
Object.defineProperty(global, 'navigator', { value: { vibrate: null }, writable: true, configurable: true });
|
|
assert.doesNotThrow(() => vibrate(10));
|
|
});
|
|
|
|
test('vibrate: ruft navigator.vibrate auf wenn vorhanden', () => {
|
|
let called = null;
|
|
Object.defineProperty(global, 'navigator', { value: { vibrate: (p) => { called = p; } }, writable: true, configurable: true });
|
|
vibrate(15);
|
|
assert.equal(called, 15);
|
|
});
|
|
|
|
test('deleteWithUndo: ruft onDelete auf', async () => {
|
|
let deleteCalled = false;
|
|
global.window.oikos = { showToast: () => {} };
|
|
await deleteWithUndo({
|
|
onDelete: async () => { deleteCalled = true; },
|
|
toastMessage: 'Gelöscht',
|
|
});
|
|
assert.equal(deleteCalled, true);
|
|
});
|
|
|
|
test('deleteWithUndo: übergibt onUndo an showToast', async () => {
|
|
let undoCalled = false;
|
|
let capturedUndo = null;
|
|
global.window.oikos = {
|
|
showToast: (_msg, _type, _duration, undoFn) => { capturedUndo = undoFn; },
|
|
};
|
|
await deleteWithUndo({
|
|
onDelete: async () => {},
|
|
onUndo: async () => { undoCalled = true; },
|
|
toastMessage: 'Gelöscht',
|
|
});
|
|
assert.ok(capturedUndo, 'showToast muss eine Undo-Funktion erhalten haben');
|
|
await capturedUndo();
|
|
assert.equal(undoCalled, true);
|
|
});
|