The helpers take the active element and body as arguments, so the cases (focus into the box, keep a control that took focus, restore only when focus was lost, find the trigger) run under node's test runner.
83 lines
2.3 KiB
JavaScript
83 lines
2.3 KiB
JavaScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { focusInto, restoreFocus, triggerOf } from "../src/ui/popover/focus.ts";
|
|
|
|
// Stand-ins for DOM elements: only the members the helpers call.
|
|
function el({ contains = () => false, first = null, matches = false } = {}) {
|
|
const calls = { focus: 0 };
|
|
return {
|
|
calls,
|
|
focus() {
|
|
calls.focus += 1;
|
|
},
|
|
contains,
|
|
matches: () => matches,
|
|
querySelector: () => first,
|
|
};
|
|
}
|
|
|
|
test("focusInto: focuses the first control in the box", () => {
|
|
const control = el();
|
|
const box = el({ first: control });
|
|
focusInto(box, null);
|
|
assert.equal(control.calls.focus, 1);
|
|
assert.equal(box.calls.focus, 0);
|
|
});
|
|
|
|
test("focusInto: focuses the box when it has no control", () => {
|
|
const box = el();
|
|
focusInto(box, null);
|
|
assert.equal(box.calls.focus, 1);
|
|
});
|
|
|
|
test("focusInto: keeps focus a control inside the box took itself", () => {
|
|
const inner = el();
|
|
const control = el();
|
|
const box = el({ first: control, contains: (n) => n === inner });
|
|
focusInto(box, inner);
|
|
assert.equal(control.calls.focus, 0);
|
|
assert.equal(box.calls.focus, 0);
|
|
});
|
|
|
|
test("focusInto: a missing box does nothing", () => {
|
|
focusInto(null, null);
|
|
});
|
|
|
|
test("restoreFocus: focus on body goes back to the trigger", () => {
|
|
const body = el();
|
|
const trigger = el();
|
|
restoreFocus(trigger, body, body);
|
|
assert.equal(trigger.calls.focus, 1);
|
|
});
|
|
|
|
test("restoreFocus: no focused element goes back to the trigger", () => {
|
|
const trigger = el();
|
|
restoreFocus(trigger, null, el());
|
|
assert.equal(trigger.calls.focus, 1);
|
|
});
|
|
|
|
test("restoreFocus: another focused control keeps focus", () => {
|
|
const trigger = el();
|
|
restoreFocus(trigger, el(), el());
|
|
assert.equal(trigger.calls.focus, 0);
|
|
});
|
|
|
|
test("restoreFocus: a missing trigger does nothing", () => {
|
|
const body = el();
|
|
restoreFocus(null, body, body);
|
|
});
|
|
|
|
test("triggerOf: the anchor itself when Tab reaches it", () => {
|
|
const anchor = el({ matches: true, first: el() });
|
|
assert.equal(triggerOf(anchor), anchor);
|
|
});
|
|
|
|
test("triggerOf: the first control inside a wrapper", () => {
|
|
const inner = el();
|
|
const anchor = el({ first: inner });
|
|
assert.equal(triggerOf(anchor), inner);
|
|
});
|
|
|
|
test("triggerOf: a missing anchor has no trigger", () => {
|
|
assert.equal(triggerOf(null), null);
|
|
});
|