Files
xxx/tests/js/helpers.js
T
tim b7022ab486 Add JavaScript tests.
Run "npm install", then "npm test".
2026-09-26 03:48:09 +02:00

90 lines
3.2 KiB
JavaScript

/*
* Load the site's JavaScript into a jsdom window. jsdom has no editing
* commands, so document.execCommand records its calls in window.commands
* (and does nothing else), and queryCommandState throws, as it does in
* some browsers.
*/
"use strict";
const fs = require("node:fs");
const path = require("node:path");
const { JSDOM } = require("jsdom");
const ROOT = path.resolve(__dirname, "..", "..");
// The story field of publish/write.inc.php, in a form
const STORY_FORM = `
<form id="form">
<label for="title">Title:</label><input id="title" name="title">
<label for="author">Author:</label><input id="author" name="author">
<label for="email">Email address:</label><input id="email" name="email">
<label for="story">Story:</label>
<div id="textparent"><textarea id="story" name="story"></textarea></div>
<div id="uploadparent" style="display: none;"><input type="file" id="upload" name="upload"></div>
<span id="wordcounter" class="counter" style="display: none;">0 words</span>
</form>`;
function load(scripts, body, story) {
const dom = new JSDOM(`<!DOCTYPE html><html><body>${body}</body></html>`, {
runScripts: "outside-only",
url: "https://xxx.org.za/publish/",
pretendToBeVisual: true,
});
const window = dom.window;
window.commands = [];
window.document.execCommand = function (command, ui, value) {
window.commands.push([command, value]);
return true;
};
window.document.queryCommandState = function () {
throw new Error("not supported");
};
if (story !== undefined) window.document.getElementById("story").value = story;
for (const script of scripts) window.eval(fs.readFileSync(path.join(ROOT, script), "utf8"));
return window;
}
// A window with the story form and publish/editor.js, and the editor attached
function editorWindow(story = "") {
const window = load(["publish/editor.js"], STORY_FORM, story);
const textarea = window.document.getElementById("story");
const editor = window.XxxEditor.attach(textarea);
const box = window.document.querySelector(".xed-area");
return { window, document: window.document, textarea, editor, box };
}
// Select from (node, offset) to (endNode, endOffset), or put the caret there
function select(window, node, offset, endNode = node, endOffset = offset) {
const range = window.document.createRange();
range.setStart(node, offset);
range.setEnd(endNode, endOffset);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
return range;
}
// Select all the text of an element
function selectText(window, element) {
const range = window.document.createRange();
range.selectNodeContents(element);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
return range;
}
function button(document, label) {
const found = document.querySelector(`.xed-btn[aria-label="${label}"]`);
if (!found) throw new Error(`No button "${label}"`);
return found;
}
function key(window, target, key, options = {}) {
const event = new window.KeyboardEvent("keydown", Object.assign({ key, bubbles: true, cancelable: true }, options));
target.dispatchEvent(event);
return event;
}
module.exports = { ROOT, STORY_FORM, load, editorWindow, select, selectText, button, key };