Reject invalid uploads and expand flow tests.

This commit is contained in:
tim
2026-09-26 15:27:51 +02:00
parent 716a609f4e
commit 8f4851e576
9 changed files with 427 additions and 11 deletions
+117
View File
@@ -297,6 +297,18 @@ test("the source button swaps the editor for the textarea and back", () => {
assert.equal(env.textarea.value, "<p>edited</p>");
});
test("submitting in source mode sends the source edits", (t) => {
const env = editorWindow("<p>Old story</p>");
t.after(() => env.window.close());
button(env.document, "Source code").click();
const source = "<p>Source edit</p>\n<p>Second paragraph.</p>";
env.textarea.value = source;
env.textarea.form.dispatchEvent(new env.window.Event("submit", { cancelable: true }));
assert.equal(env.textarea.value, source);
assert.equal(env.editor.getContent(), source);
assert.equal(new env.window.FormData(env.textarea.form).get("story"), source);
});
test("setContent leaves source mode", () => {
const env = editorWindow("<p>a</p>");
button(env.document, "Source code").click();
@@ -327,6 +339,111 @@ test("undo keeps a run of typing as one step", () => {
assert.equal(env.textarea.value, "<p>a</p>");
});
for (const pause of [999, 1000, 1001]) {
test(`undo groups typing only when the pause is below one second (${pause} ms)`, (t) => {
const env = editorWindow("<p>a</p>");
t.after(() => env.window.close());
let now = 10000;
t.mock.method(env.window.Date, "now", () => now);
type(env, "<p>ab</p>");
now += pause;
type(env, "<p>abc</p>");
key(env.window, env.box, "z", { ctrlKey: true });
assert.equal(env.textarea.value, pause < 1000 ? "<p>a</p>" : "<p>ab</p>");
key(env.window, env.box, "y", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>abc</p>");
});
}
test("a change of input type starts a separate undo step", (t) => {
const env = editorWindow("<p>a</p>");
t.after(() => env.window.close());
t.mock.method(env.window.Date, "now", () => 10000);
type(env, "<p>abc</p>", "insertText");
type(env, "<p>ab</p>", "deleteContentBackward");
key(env.window, env.box, "z", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>abc</p>");
key(env.window, env.box, "z", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>a</p>");
});
test("a new edit after undo clears the old redo history", (t) => {
const env = editorWindow("<p>a</p>");
t.after(() => env.window.close());
let now = 10000;
t.mock.method(env.window.Date, "now", () => now);
type(env, "<p>ab</p>");
now += 1000;
type(env, "<p>abc</p>");
key(env.window, env.box, "z", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>ab</p>");
type(env, "<p>abX</p>");
key(env.window, env.box, "y", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>abX</p>");
key(env.window, env.box, "z", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>ab</p>");
key(env.window, env.box, "y", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>abX</p>");
});
test("undo keeps the latest 100 steps and redo restores them", (t) => {
const env = editorWindow("<p>0</p>");
t.after(() => env.window.close());
let now = 10000;
t.mock.method(env.window.Date, "now", () => now);
for (let i = 1; i <= 105; i++) {
now += 1000;
type(env, `<p>${i}</p>`);
}
for (let i = 104; i >= 5; i--) {
key(env.window, env.box, "z", { ctrlKey: true });
assert.equal(env.textarea.value, `<p>${i}</p>`);
}
key(env.window, env.box, "z", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>5</p>", "the oldest five steps are discarded");
for (let i = 6; i <= 105; i++) {
key(env.window, env.box, "y", { ctrlKey: true });
assert.equal(env.textarea.value, `<p>${i}</p>`);
}
key(env.window, env.box, "y", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>105</p>");
});
test("undo restores a selection across nodes and redo restores the caret", (t) => {
const original = "<p>alpha<em>beta</em></p>";
const env = editorWindow(original);
t.after(() => env.window.close());
select(env.window, env.box.querySelector("p").firstChild, 2, env.box.querySelector("em").firstChild, 3);
type(env, "<p>altered</p>");
select(env.window, env.box.querySelector("p").firstChild, 4);
key(env.window, env.box, "z", { ctrlKey: true });
assert.equal(env.textarea.value, original);
let range = env.window.getSelection().getRangeAt(0);
assert.equal(range.startContainer, env.box.querySelector("p").firstChild);
assert.equal(range.startOffset, 2);
assert.equal(range.endContainer, env.box.querySelector("em").firstChild);
assert.equal(range.endOffset, 3);
assert.equal(range.toString(), "phabet");
key(env.window, env.box, "y", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>altered</p>");
range = env.window.getSelection().getRangeAt(0);
assert.equal(range.startContainer, env.box.querySelector("p").firstChild);
assert.equal(range.startOffset, 4);
assert.equal(range.collapsed, true);
});
test("redo from the browser's history input", (t) => {
const env = editorWindow("<p>a</p>");
t.after(() => env.window.close());
type(env, "<p>b</p>");
key(env.window, env.box, "z", { ctrlKey: true });
assert.equal(env.textarea.value, "<p>a</p>");
const event = new env.window.InputEvent("beforeinput", { inputType: "historyRedo", bubbles: true, cancelable: true });
env.box.dispatchEvent(event);
assert.ok(event.defaultPrevented);
assert.equal(env.textarea.value, "<p>b</p>");
});
test("undo from the browser's history input", () => {
const env = editorWindow("<p>a</p>");
type(env, "<p>b</p>");