99 lines
3.3 KiB
JavaScript
99 lines
3.3 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import {readFileSync} from 'node:fs';
|
|
import test from 'node:test';
|
|
import vm from 'node:vm';
|
|
|
|
class Target {
|
|
listeners = new Map();
|
|
|
|
addEventListener(type, listener) {
|
|
this.listeners.set(type, listener);
|
|
}
|
|
|
|
dispatch(type) {
|
|
this.listeners.get(type)?.({preventDefault() {}, target: this});
|
|
}
|
|
}
|
|
|
|
test('picker searches name and student code, summarizes selection, and cancels safely', () => {
|
|
const open = Object.assign(new Target(), {focus() { this.focused = true; }});
|
|
const cancel = new Target();
|
|
const apply = new Target();
|
|
const search = Object.assign(new Target(), {value: '', focus() { this.focused = true; }});
|
|
const summary = {textContent: ''};
|
|
const empty = {hidden: true};
|
|
const firstInput = Object.assign(new Target(), {checked: false, type: 'checkbox'});
|
|
const secondInput = Object.assign(new Target(), {checked: false, type: 'checkbox'});
|
|
const options = [
|
|
option('Nguyen An STU-020', 'Nguyen An (STU-020)', firstInput),
|
|
option('Tran Binh STU-021', 'Tran Binh (STU-021)', secondInput),
|
|
];
|
|
const dialog = Object.assign(new Target(), {
|
|
showModal() { this.open = true; },
|
|
close() { this.open = false; this.dispatch('close'); },
|
|
});
|
|
const picker = {
|
|
querySelector(selector) {
|
|
return new Map([
|
|
['[data-picker-open]', open], ['[data-picker-dialog]', dialog],
|
|
['[data-picker-search]', search], ['[data-picker-summary]', summary],
|
|
['[data-picker-empty]', empty], ['[data-picker-cancel]', cancel],
|
|
['[data-picker-apply]', apply],
|
|
]).get(selector) ?? null;
|
|
},
|
|
querySelectorAll(selector) {
|
|
return selector === '[data-picker-option]' ? options : [];
|
|
},
|
|
};
|
|
let ready;
|
|
const document = {
|
|
documentElement: {dataset: {}, style: {}},
|
|
addEventListener(type, listener) { if (type === 'DOMContentLoaded') ready = listener; },
|
|
querySelector() { return null; },
|
|
querySelectorAll(selector) { return selector === '[data-intern-picker]' ? [picker] : []; },
|
|
};
|
|
vm.runInNewContext(readFileSync('src/main/resources/static/assets/app.js', 'utf8'), {
|
|
document,
|
|
localStorage: {getItem() { return null; }, setItem() {}, removeItem() {}},
|
|
matchMedia() { return {matches: false}; },
|
|
});
|
|
ready();
|
|
|
|
open.dispatch('click');
|
|
assert.equal(dialog.open, true);
|
|
assert.equal(search.focused, true);
|
|
|
|
search.value = 'stu-021';
|
|
search.dispatch('input');
|
|
assert.equal(options[0].hidden, true);
|
|
assert.equal(options[1].hidden, false);
|
|
assert.equal(empty.hidden, true);
|
|
|
|
secondInput.checked = true;
|
|
secondInput.dispatch('change');
|
|
assert.equal(summary.textContent, '1 Intern selected: Tran Binh (STU-021)');
|
|
|
|
cancel.dispatch('click');
|
|
assert.equal(secondInput.checked, false);
|
|
assert.equal(summary.textContent, 'No Interns selected');
|
|
assert.equal(open.focused, true);
|
|
|
|
open.dispatch('click');
|
|
secondInput.checked = true;
|
|
secondInput.dispatch('change');
|
|
apply.dispatch('click');
|
|
assert.equal(secondInput.checked, true);
|
|
});
|
|
|
|
function option(searchValue, label, input) {
|
|
return {
|
|
hidden: false,
|
|
dataset: {pickerSearch: searchValue},
|
|
querySelector(selector) {
|
|
if (selector === 'input') return input;
|
|
if (selector === '[data-picker-label]') return {textContent: label};
|
|
return null;
|
|
},
|
|
};
|
|
}
|