64 lines
3.3 KiB
JavaScript
64 lines
3.3 KiB
JavaScript
|
|
const {test} = require('node:test');
|
||
|
|
const assert = require('node:assert/strict');
|
||
|
|
const vm = require('node:vm');
|
||
|
|
const fs = require('node:fs');
|
||
|
|
const source = fs.readFileSync('static/js/case-slot-resize.js', 'utf8');
|
||
|
|
function setup(responses = [{ok: true}]) {
|
||
|
|
const handlers = {}, calls = [], messages = [];
|
||
|
|
let reloads = 0;
|
||
|
|
const label = {textContent: ''};
|
||
|
|
const button = {
|
||
|
|
dataset: {allocationId: '42', version: '3', start: '2026-10-21T06:00:00Z', end: '2026-10-21T06:30:00Z'},
|
||
|
|
closest: selector => selector === '.case-slot-resize' ? button : {querySelector: () => label},
|
||
|
|
classList: {add() {}, remove() {}}, setPointerCapture() {}, hasPointerCapture: () => true, releasePointerCapture() {},
|
||
|
|
};
|
||
|
|
vm.runInNewContext(source, {
|
||
|
|
document: {getElementById: () => ({addEventListener: (type, fn) => {handlers[type] = fn;}})},
|
||
|
|
window: {confirm: () => true, showCaseFeedback: (...args) => messages.push(args), loadEmbeddedCasePlanner: async () => {reloads++;}},
|
||
|
|
fetch: async (url, options) => {calls.push({url, payload: JSON.parse(options.body)});const response = responses.shift();return {...response, json: async () => response.body || {}};},
|
||
|
|
});
|
||
|
|
const event = values => ({target: button, pointerId: 1, button: 0, clientY: 100, preventDefault() {}, stopPropagation() {}, ...values});
|
||
|
|
return {handlers, calls, messages, label, event, reloads: () => reloads};
|
||
|
|
}
|
||
|
|
const settle = () => new Promise(resolve => setImmediate(resolve));
|
||
|
|
test('drag changes end time in 15 minute steps and sends current version', async () => {
|
||
|
|
const s = setup();
|
||
|
|
s.handlers.pointerdown(s.event());
|
||
|
|
s.handlers.pointermove(s.event({clientY: 124}));
|
||
|
|
assert.match(s.label.textContent, /60 min/);
|
||
|
|
s.handlers.pointerup(s.event());
|
||
|
|
await settle();
|
||
|
|
assert.deepEqual(s.calls, [{url: '/api/v1/planner/allocations/42', payload: {version: 3, ends_at: '2026-10-21T07:00:00.000Z'}}]);
|
||
|
|
assert.equal(s.reloads(), 1);
|
||
|
|
});
|
||
|
|
test('cancel and an unchanged drag do not write', async () => {
|
||
|
|
const s = setup();
|
||
|
|
s.handlers.pointerdown(s.event());
|
||
|
|
s.handlers.pointermove(s.event({clientY: 124}));
|
||
|
|
s.handlers.pointercancel(s.event());
|
||
|
|
assert.match(s.label.textContent, /30 min/);
|
||
|
|
s.handlers.pointerdown(s.event());
|
||
|
|
s.handlers.pointerup(s.event());
|
||
|
|
await settle();
|
||
|
|
assert.equal(s.calls.length, 0);
|
||
|
|
});
|
||
|
|
test('keyboard clamps duration to 15 minutes', async () => {
|
||
|
|
const s = setup();
|
||
|
|
s.handlers.keydown(s.event({key: 'ArrowUp'}));
|
||
|
|
await settle();
|
||
|
|
assert.equal(s.calls[0].payload.ends_at, '2026-10-21T06:15:00.000Z');
|
||
|
|
});
|
||
|
|
test('overlap requires confirmation before retry; stale version never retries', async () => {
|
||
|
|
const overlap = setup([{ok: false, status: 409, body: {detail: {message: 'Overlap', conflict_status: 'overlap'}}}, {ok: true}]);
|
||
|
|
overlap.handlers.keydown(overlap.event({key: 'ArrowDown'}));
|
||
|
|
await settle();
|
||
|
|
assert.equal(overlap.calls.length, 2);
|
||
|
|
assert.equal(overlap.calls[1].payload.confirm_conflicts, true);
|
||
|
|
const stale = setup([{ok: false, status: 409, body: {detail: {message: 'Ændret af en anden bruger', current: {version: 4}}}}]);
|
||
|
|
stale.handlers.keydown(stale.event({key: 'ArrowDown'}));
|
||
|
|
await settle();
|
||
|
|
assert.equal(stale.calls.length, 1);
|
||
|
|
assert.equal(stale.messages[0][0], 'Ændret af en anden bruger');
|
||
|
|
assert.equal(stale.reloads(), 1);
|
||
|
|
});
|