bmc_hub/tests/js/case-slot-resize.test.cjs

64 lines
3.3 KiB
JavaScript
Raw Normal View History

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);
});