Skip to content

Commit

Permalink
added support for form validation of textareas
Browse files Browse the repository at this point in the history
  • Loading branch information
joelabrahamsson committed Oct 27, 2023
1 parent 76ad330 commit f491ce8
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 12 deletions.
5 changes: 2 additions & 3 deletions lib/HTMLFormElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const HTMLElement = require("./HTMLElement.js");
const HTMLFormControlsCollection = require("./HTMLFormControlsCollection.js");
const HTMLInputElement = require("./HTMLInputElement.js");
const HTMLSelectElement = require("./HTMLSelectElement.js");
const HTMLTextAreaElement = require("./HTMLTextAreaElement.js");

const originSymbol = Symbol.for("origin");

Expand Down Expand Up @@ -93,9 +94,7 @@ module.exports = class HTMLFormElement extends HTMLElement {
reportValidity() {
return [ ...this.elements ]
.map((el) => {
if (el instanceof HTMLInputElement) {
return el.reportValidity();
} else if (el instanceof HTMLSelectElement) {
if (el instanceof HTMLInputElement || el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement) {
return el.reportValidity();
}
return true;
Expand Down
35 changes: 34 additions & 1 deletion lib/HTMLTextAreaElement.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
"use strict";

const { InputEvent } = require("./Events.js");
const { Event, InputEvent } = require("./Events.js");
const HTMLElement = require("./HTMLElement.js");
const ValidityState = require("./ValidityState.js");

const kValidity = Symbol.for("validity");
const kValidationMessage = Symbol.for("validation message");
module.exports = class HTMLTextAreaElement extends HTMLElement {
constructor(...args) {
super(...args);

this[kValidationMessage] = "";
this[kValidity] = new ValidityState(this);
}

get disabled() {
return this.$elm.prop("disabled");
}
Expand All @@ -25,6 +35,29 @@ module.exports = class HTMLTextAreaElement extends HTMLElement {
if (value === true) return this.setAttribute("required", "required");
this.removeAttribute("required");
}
get validationMessage() {
return this[kValidationMessage];
}
get validity() {
return this[kValidity];
}
get willValidate() {
if (this.readOnly) return false;
if (this.disabled) return false;
return this.type !== "hidden";
}
reportValidity() {
return this.checkValidity();
}
checkValidity() {
const validity = this[kValidity];
if (!validity.valid) this.dispatchEvent(new Event("invalid", { bubbles: true }));
return validity.valid;
}
setCustomValidity(...args) {
if (!args.length) throw new TypeError(`Failed to execute 'setCustomValidity' on '${this.constructor.name}': 1 argument required, but only 0 present.`);
this[kValidationMessage] = `${args[0]}`;
}
get value() {
const value = this.getAttribute("value");
if (value === null) return "";
Expand Down
118 changes: 110 additions & 8 deletions test/HTMLTextAreaElement-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,125 @@
const { Document } = require("../lib/index.js");

describe("HTMLTextAreaElement", () => {
let document;
beforeEach(() => {
document = new Document({
text: `
describe("innertText", () => {
let document;
beforeEach(() => {
document = new Document({
text: `
<html>
<body>
<form>
<textarea name="novel"></textarea>
</form>
</body>
</html>`,
});
});

it("innerText is empty if value is set", () => {
const elm = document.forms[0].elements.novel;
elm.value = "a";
expect(elm.textContent).to.equal("");
});
});

it("innerText is empty if value is set", () => {
const elm = document.forms[0].elements.novel;
elm.value = "a";
expect(elm.textContent).to.equal("");
describe("validation", () => {
let document;
beforeEach(() => {
document = new Document({
text: `
<html>
<body>
<form id="get-form" type="get" action="/">
<textarea name="req" required></textarea>
<textarea name="optional"></textarea>
<button type="submit">Submit</button>
</form>
</body>
</html>`,
});
});

it("should not submit if form is not valid", () => {
const form = document.forms[0];
const button = document.getElementsByTagName("button")[0];

let submitted = false;
form.addEventListener("submit", () => {
submitted = true;
});

button.click();
expect(submitted).to.equal(false);

form.elements.req.value = "test";
button.click();
expect(submitted).to.equal(true);
});

it("should get validity on form", () => {
const form = document.forms[0];
expect(form.reportValidity()).to.equal(false);

form.elements.req.value = "test";
expect(form.reportValidity()).to.equal(true);
});

it("should get validity on element", () => {
const el = document.forms[0].elements.req;
expect(el.reportValidity()).to.equal(false);

el.value = "test";
expect(el.reportValidity()).to.equal(true);
});
});

describe("custom validity", () => {
let document;
beforeEach(() => {
document = new Document({
text: `
<html>
<body>
<form id="get-form" type="get" action="/">
<textarea name="pets" id="pet-select" required oninvalid="setCustomValidity('Required')"></textarea>
<input id="submit-form" type="submit">
</form>
</body>
</html>`,
});
});

it("setCustomValidity() without argument throws TypeError", () => {
const form = document.forms[0];
expect(() => form.elements.pets.setCustomValidity()).to.throw(TypeError, "Failed to execute 'setCustomValidity' on 'HTMLTextAreaElement': 1 argument required, but only 0 present.");
});

it("shows custom error message", () => {
const form = document.forms[0];
document.getElementById("submit-form").click();

expect(form.elements.pets.validationMessage).to.equal("Required");
expect(form.elements.pets.validity).to.have.property("customError", true);
});

it("checkValidity() returns true if required textarea is disabled", () => {
const form = document.forms[0];
form.elements.pets.disabled = true;
expect(form.elements.pets.checkValidity()).to.equal(true);
});

it("disabled required input is ignored", () => {
const form = document.forms[0];

let submitted = false;
document.addEventListener("submit", () => (submitted = true));

form.elements.pets.disabled = true;
document.getElementById("submit-form").click();
expect(submitted).to.be.true;

expect(form.elements.pets.validationMessage).to.equal("");
});
});
});

0 comments on commit f491ce8

Please sign in to comment.