Add JavaScript tests.
Run "npm install", then "npm test".
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 };
|
||||
Reference in New Issue
Block a user