diff --git a/src/pat/validation/documentation.md b/src/pat/validation/documentation.md
index 394e82c65..a3dc74fdd 100644
--- a/src/pat/validation/documentation.md
+++ b/src/pat/validation/documentation.md
@@ -1,7 +1,9 @@
## Description
-This pattern provides form validation based on the HTML standard and offers extended functionality like custom error messages and extra validation rules.
-
+This pattern provides form validation with standard HTML validation attributes,
+extra validation rules, custom error messages and a custom error template. It
+is based HTML form validation framework and therefor supports form state
+checking via CSS peudo classes like `:valid` and `:invalid`.
## Documentation
@@ -10,13 +12,23 @@ The rest is handled mostly with standard HTML validation attributes.
This patterns offers:
-- extra validation rules like checking for equality or checking is one date it after another.
-- custom error messages.
+- Custom error messages for the standard HTML validation attributes.
+- Custom error template to display error messages.
+- Extra validation rules where the standard HTML validation attributes are not enough.
+
+These extra validation rules are:
+
+- Equality checking between two fields (e.g. password confirmation).
+- Date and datetime validation for before and after a given date or another input field.
-Since it is based on the HTML standard you can still use the `:valid`, `:invalid` and `:out-of-range` CSS pseudo classes.
-You can use any HTML form validation attributes but here are some examples:
+### HTML form validation framework integration.
+This pattern uses the [JavaScript Constraint Validation API](https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Constraint_validation).
+Valid formns or inputs can be selected with the `:valid` pseudo class, invalid ones with the `:invalid` pseudo class.
+
+
+### Validation rules
| Name | Syntax | Description |
| ------------- | -------------------------- | ------------------------------------------------------------ |
@@ -31,64 +43,94 @@ You can use any HTML form validation attributes but here are some examples:
> **_NOTE:_** The form inputs must have a `name` attribute, otherwise the validation would not happen.
-### Error messages
+### Custom error messages
-Error messages are inserted into the DOM as `em` elements with a `message warning` class.
-For most input elements error messages are inserted immediately after the input element.
-In addition both the input element and its label will get an `warning` class.
+Error messages are unique per type of validation (e.g. `required`, `email` or `number`) and can be overridden:
-
+```html
+
+```
-Checkboxes and radio buttons are treated differently: if they are contained in a fieldset with class `checklist` error messages are added at the end of the fieldset.
+Error messages can also be overridden on a per-field basis, for example:
-
+```html
+
+```
-#### Overriding error messages
+For a list of all available error messages see the [Options reference](#options-reference).
-Error messages are unique per type of validation (e.g. `required`, `email` or `number`) and can be overridden:
-
+```html
+
+```
-Error messages can also be overridden on a per-field basis, for example:
+Checkboxes and radio buttons are treated differently: if they are contained in a fieldset with class `checklist` error messages are added at the end of the fieldset.
+
+```html
+
+```
-
+The error message template is be overridden via JavaScript by customizing the error_template method of the Pattern API.
+This is an [example taken from Mockup](https://github.com/plone/mockup/blob/6c93b810b2c07b5bd58eec80cd03f700c9447d8c/src/patterns.js#L67):
+
+```javascript
+import { Pattern as ValidationPattern } from "@patternslib/patternslib/src/pat/validation/validation";
+
+ValidationPattern.prototype.error_template = (message) =>
+ `${message}`;
+```
### Options reference
-> **_NOTE:_** The form inputs must have a `name` attribute, otherwise the validation would not happen.
+> **_NOTE:_** The form inputs must have a `name` attribute, otherwise the
+> validation would not happen.
-> **_NOTE:_** If you need to exclude a submit button from form validation - like a cancel button which actually submits - add the `formnovalidate` attribute to the button.
+> **_NOTE:_** If you need to exclude a submit button from form validation -
+> like a cancel button which actually submits - add the `formnovalidate`
+> attribute to the button.
| Property | Description | Default | Type |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | -------------------------------------- |
| disable-selector | A selector for elements that should be disabled when there are errors in the form. | | CSS Selector |
-| equality | Field-specific. The name of another input this input should equal to (useful for password confirmation). | | String |
| message-date | The error message for date fields. | This value must be a valid date | String |
| message-datetime | The error message for datetime fields. | This value must be a valid date and time | String |
| message-email | The error message for email fields. | This value must be a valid email address | String |
-| message-equality | The error message for fields required to be equal | is not equal to %{attribute} | String |
-| message-max | The error message for max number values. | This value must be less than or equal to %{count} | String |
-| message-min | The error message for min number values. | This value must be greater than or equal to %{count} | String |
+| message-max | The error message for number values which are higher than max. | This value must be less than or equal to %{count} | String |
+| message-min | The error message for number values which are lower than min. | This value must be greater than or equal to %{count} | String |
| message-number | The error message for numbers. | This value must be a number. | String |
| message-required | The error message for required fields. | This field is required. | String |
-| not-after | Field-specific. A lower time limit restriction for date and datetime fields. | | CSS Selector or a ISO8601 date string. |
-| not-before | Field-specific. An upper time limit restriction for date and datetime fields. | | CSS Selector or a ISO8601 date string. |
+| message-equality | The error message for fields required to be equal | is not equal to %{attribute} | String |
+| equality | Field-specific extra rule. The name of another input this input should equal to (useful for password confirmation). | | String |
+| not-after | Field-specific extra rule. A lower time limit restriction for date and datetime fields. | | CSS Selector or a ISO8601 date string. |
+| not-before | Field-specific extra rule. An upper time limit restriction for date and datetime fields. | | CSS Selector or a ISO8601 date string. |
+| delay | Time in milliseconds before validation starts to avoid validating while typing. | 100 | Integer |
diff --git a/src/pat/validation/validation.js b/src/pat/validation/validation.js
index 53421d41d..2070a7652 100644
--- a/src/pat/validation/validation.js
+++ b/src/pat/validation/validation.js
@@ -10,27 +10,25 @@ import utils from "../../core/utils";
import registry from "../../core/registry";
const logger = logging.getLogger("pat-validation");
-//logger.setLevel(logging.Level.DEBUG);
+
export const parser = new Parser("validation");
parser.addArgument("disable-selector", "[type=submit], button:not([type=button])"); // Elements which must be disabled if there are errors
-parser.addArgument("message-date", ""); // "This value must be a valid date");
-parser.addArgument("message-datetime", ""); // "This value must be a valid date and time");
-parser.addArgument("message-email", ""); // "This value must be a valid email address");
-parser.addArgument("message-max", ""); // "This value must be less than or equal to %{count}");
-parser.addArgument("message-min", ""); // "This value must be greater than or equal to %{count}"); // prettier-ignore
-parser.addArgument("message-number", ""); // "This value must be a number");
-parser.addArgument("message-required", ""); // "This field is required");
+parser.addArgument("message-date", ""); // "This value must be a valid date"
+parser.addArgument("message-datetime", ""); // "This value must be a valid date and time"
+parser.addArgument("message-email", ""); // "This value must be a valid email address"
+parser.addArgument("message-max", ""); // "This value must be less than or equal to %{count}"
+parser.addArgument("message-min", ""); // "This value must be greater than or equal to %{count}"
+parser.addArgument("message-number", ""); // "This value must be a number"
+parser.addArgument("message-required", ""); // "This field is required"
parser.addArgument("message-equality", "is not equal to %{attribute}.");
parser.addArgument("not-after", null);
parser.addArgument("not-before", null);
parser.addArgument("equality", null);
parser.addArgument("delay", 100); // Delay before validation is done to avoid validating while typing.
-// BBB
-// TODO: deprecated. Will be removed with next major version.
+// Aliases
parser.addAlias("message-integer", "message-number");
-parser.addArgument("error-template");
const KEY_ERROR_EL = "__patternslib__input__error__el";
const KEY_ERROR_MSG = "__patternslib__input__error__msg";
@@ -121,19 +119,7 @@ class Pattern extends BasePattern {
return;
}
- logger.debug(`
- validity_state.badInput ${validity_state.badInput}
- validity_state.customError ${validity_state.customError}
- validity_state.patternMismatch ${validity_state.patternMismatch}
- validity_state.rangeOverflow ${validity_state.rangeOverflow}
- validity_state.rangeUnderflow ${validity_state.rangeUnderflow}
- validity_state.stepMismatch ${validity_state.stepMismatch}
- validity_state.tooLong ${validity_state.tooLong}
- validity_state.tooShort ${validity_state.tooShort}
- validity_state.typeMismatch ${validity_state.typeMismatch}
- validity_state.valid ${validity_state.valid}
- validity_state.valueMissing ${validity_state.valueMissing}
- `);
+ logger.debug(`validity_state: `, validity_state);
const input_options = parser.parse(input);
diff --git a/src/pat/validation/validation.test.js b/src/pat/validation/validation.test.js
index b50f5e15c..f9a0eaa62 100644
--- a/src/pat/validation/validation.test.js
+++ b/src/pat/validation/validation.test.js
@@ -18,1481 +18,1495 @@ describe("pat-validation", function () {
parser.parameters.delay.value = orig_delay;
});
- it("1.1 - validates with no constraints", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=name]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ describe("1 - general tests", function () {
+ it("1.1 - validates with no constraints", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=name]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("1.2 - adds an error when validation fails", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=name]");
+ it("1.2 - adds an error when validation fails", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=name]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ });
- it("1.3 - removes the error when the field becomes valid.", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=name]");
+ it("1.3 - removes the error when the field becomes valid.", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=name]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
- inp.value = "abc";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = "abc";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("1.4 - multiple error messages on multiple errors.", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp1 = el.querySelector("[name=name1]");
- const inp2 = el.querySelector("[name=name2]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- inp1.value = "";
- inp1.dispatchEvent(events.change_event());
- inp2.value = "";
- inp2.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(2);
- });
+ it("1.4 - multiple error messages on multiple errors.", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp1 = el.querySelector("[name=name1]");
+ const inp2 = el.querySelector("[name=name2]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp1.value = "";
+ inp1.dispatchEvent(events.change_event());
+ inp2.value = "";
+ inp2.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+ });
- it("1.5 - removes one error message but keeps the other", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp1 = el.querySelector("[name=name1]");
- const inp2 = el.querySelector("[name=name2]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- inp1.value = "";
- inp1.dispatchEvent(events.change_event());
- inp2.value = "";
- inp2.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(2);
-
- inp2.value = "abc";
- inp2.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
-
- inp1.value = "abc";
- inp1.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ it("1.5 - removes one error message but keeps the other", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp1 = el.querySelector("[name=name1]");
+ const inp2 = el.querySelector("[name=name2]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp1.value = "";
+ inp1.dispatchEvent(events.change_event());
+ inp2.value = "";
+ inp2.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+
+ inp2.value = "abc";
+ inp2.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+
+ inp1.value = "abc";
+ inp1.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("1.6 - can use a globally configured error message and overwrite on a per field basis.", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp1 = el.querySelector("[name=name1]");
- const inp2 = el.querySelector("[name=name2]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- inp1.value = "";
- inp1.dispatchEvent(events.change_event());
- inp2.value = "";
- inp2.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(2);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe("need this 1");
- expect(el.querySelectorAll("em.warning")[1].textContent).toBe("need this 2");
- });
+ it("1.6 - can use a globally configured error message and overwrite on a per field basis.", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp1 = el.querySelector("[name=name1]");
+ const inp2 = el.querySelector("[name=name2]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp1.value = "";
+ inp1.dispatchEvent(events.change_event());
+ inp2.value = "";
+ inp2.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe("need this 1");
+ expect(el.querySelectorAll("em.warning")[1].textContent).toBe("need this 2");
+ });
- it("1.7 - doesn't validate disabled elements", async function () {
- document.body.innerHTML = `
-
- `;
+ it("1.7 - doesn't validate disabled elements", async function () {
+ document.body.innerHTML = `
+
+ `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=input]");
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=input]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("1.8 - can disable certain form elements when validation fails", async function () {
- // Tests the disable-selector argument
- document.body.innerHTML = `
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=input]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- inp.value = 4.5;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "This value must be an integer."
- );
- expect(el.querySelector("#form-buttons-create").disabled).toBe(true);
-
- inp.value = 5;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- expect(el.querySelector("#form-buttons-create").disabled).toBe(false);
- });
+ it("1.8 - can disable certain form elements when validation fails", async function () {
+ // Tests the disable-selector argument
+ document.body.innerHTML = `
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=input]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp.value = 4.5;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "This value must be an integer."
+ );
+ expect(el.querySelector("#form-buttons-create").disabled).toBe(true);
+
+ inp.value = 5;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ expect(el.querySelector("#form-buttons-create").disabled).toBe(false);
+ });
- it("1.9 - can define a custom error message template by subclassing.", async function () {
- class CustomValidation extends Pattern {
- error_template(message) {
- return `
${message}
`;
+ it("1.9 - can define a custom error message template by subclassing.", async function () {
+ class CustomValidation extends Pattern {
+ error_template(message) {
+ return `
${message}
`;
+ }
}
- }
-
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=name]");
-
- const instance = new CustomValidation(el);
- await events.await_pattern_init(instance);
-
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("div.validation-error").length).toBe(1);
- expect(el.querySelectorAll("div.validation-error")[0].textContent).toBe(
- "need this"
- );
- });
- it("1.10 - Adds a novalidate attribute to not show the browsers validation bubbles.", async function () {
- // See: https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation#a_more_detailed_example
- // The ``novalidate`` attribute does not deactivate the validation API
- // but prevents the browser from showing validation messages by itself.
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- expect(el.hasAttribute("novalidate")).toBe(true);
- });
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=name]");
+
+ const instance = new CustomValidation(el);
+ await events.await_pattern_init(instance);
+
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("div.validation-error").length).toBe(1);
+ expect(el.querySelectorAll("div.validation-error")[0].textContent).toBe(
+ "need this"
+ );
+ });
- it("1.11 - Prevents submit when invalid.", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- el.querySelector("button").click();
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- });
+ it("1.10 - Adds a novalidate attribute to not show the browsers validation bubbles.", async function () {
+ // See: https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation#a_more_detailed_example
+ // The ``novalidate`` attribute does not deactivate the validation API
+ // but prevents the browser from showing validation messages by itself.
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ expect(el.hasAttribute("novalidate")).toBe(true);
+ });
- it("1.12 - Allows submit with ``formnovalidate``.", async function () {
- // Buttons with ``formnovalidate`` should prevent validation.
+ it("1.11 - Prevents submit when invalid.", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ el.querySelector("button").click();
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ });
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ it("1.12 - Allows submit with ``formnovalidate``.", async function () {
+ // Buttons with ``formnovalidate`` should prevent validation.
- el.querySelector("button").click();
- await utils.timeout(1); // wait a tick for async to settle.
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ el.querySelector("button").click();
+ await utils.timeout(1); // wait a tick for async to settle.
- it("1.13 - Prevents other event handlers when invalid.", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- let submit_called = false;
- let click_called = false;
-
- // Note: the handlers must be registered after Pattern initialization.
- // Otherwise the pattern will not be able to prevent the event.
- // In case of other patterns, the validation pattern will be reordered
- // first and submit prevention does work.
- el.addEventListener("submit", () => (submit_called = true));
- el.addEventListener("click", () => (click_called = true));
-
- el.querySelector("button").click();
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(submit_called).toBe(false);
- expect(click_called).toBe(true);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("1.14 - Prevents pat-inject form submission when invalid.", async function () {
- const pat_inject = (await import("../inject/inject")).default;
- const registry = (await import("../../core/registry")).default;
+ it("1.13 - Prevents other event handlers when invalid.", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ let submit_called = false;
+ let click_called = false;
+
+ // Note: the handlers must be registered after Pattern initialization.
+ // Otherwise the pattern will not be able to prevent the event.
+ // In case of other patterns, the validation pattern will be reordered
+ // first and submit prevention does work.
+ el.addEventListener("submit", () => (submit_called = true));
+ el.addEventListener("click", () => (click_called = true));
+
+ el.querySelector("button").click();
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(submit_called).toBe(false);
+ expect(click_called).toBe(true);
+ });
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
+ it("1.14 - Prevents pat-inject form submission when invalid.", async function () {
+ const pat_inject = (await import("../inject/inject")).default;
+ const registry = (await import("../../core/registry")).default;
- const spy_inject_submit = jest.spyOn(pat_inject, "onTrigger");
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
- registry.scan(document.body);
- await utils.timeout(1); // wait a tick for async to settle.
+ const spy_inject_submit = jest.spyOn(pat_inject, "onTrigger");
- el.querySelector("button").click();
- await utils.timeout(1); // wait a tick for async to settle.
+ registry.scan(document.body);
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(spy_inject_submit).not.toHaveBeenCalled();
- });
+ el.querySelector("button").click();
+ await utils.timeout(1); // wait a tick for async to settle.
- it("1.15 - Prevents pat-modal closing with a pat-inject when invalid.", async function () {
- await import("../close-panel/close-panel");
- const pat_inject = (await import("../inject/inject")).default;
- const pat_modal = (await import("../modal/modal")).default;
- const registry = (await import("../../core/registry")).default;
-
- document.body.innerHTML = `
-
+ `;
+ const el = document.querySelector("form");
- registry.scan(document.body);
- await utils.timeout(1); // wait a tick for async to settle.
- await utils.timeout(1); // wait another tick
+ const spy_destroy_modal = jest.spyOn(pat_modal.prototype, "destroy");
- el.querySelector("button").click();
- await utils.timeout(1); // wait a tick for async to settle.
+ registry.scan(document.body);
+ await utils.timeout(1); // wait a tick for async to settle.
+ await utils.timeout(1); // wait another tick
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(spy_destroy_modal).not.toHaveBeenCalled();
- });
+ el.querySelector("button").click();
+ await utils.timeout(1); // wait a tick for async to settle.
- it("1.17 - Prevents pat-modal closing when invalid with custom validation rule.", async function () {
- await import("../close-panel/close-panel");
- const pat_modal = (await import("../modal/modal")).default;
- const registry = (await import("../../core/registry")).default;
-
- const spy_destroy_modal = jest.spyOn(pat_modal.prototype, "destroy");
-
- document.body.innerHTML = `
-
-
-
- `;
- const el = document.querySelector("form");
- const inp_ok = document.querySelector("input[name=ok]");
- inp_ok.value = "foo";
-
- registry.scan(document.body);
- await utils.timeout(1); // wait a tick for async to settle.
- await utils.timeout(1); // wait another tick
-
- el.querySelector("button.submit").click();
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(spy_destroy_modal).not.toHaveBeenCalled();
-
- // A non-submit close-panel button does not check for validity.
- el.querySelector("button.cancel").click();
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(spy_destroy_modal).toHaveBeenCalled();
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(spy_destroy_modal).not.toHaveBeenCalled();
+ });
- it("1.18 - validates all inputs after submit", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
+ it("1.17 - Prevents pat-modal closing when invalid with custom validation rule.", async function () {
+ await import("../close-panel/close-panel");
+ const pat_modal = (await import("../modal/modal")).default;
+ const registry = (await import("../../core/registry")).default;
+
+ const spy_destroy_modal = jest.spyOn(pat_modal.prototype, "destroy");
+
+ document.body.innerHTML = `
+
+
+
+ `;
+ const el = document.querySelector("form");
+ const inp_ok = document.querySelector("input[name=ok]");
+ inp_ok.value = "foo";
+
+ registry.scan(document.body);
+ await utils.timeout(1); // wait a tick for async to settle.
+ await utils.timeout(1); // wait another tick
+
+ el.querySelector("button.submit").click();
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(spy_destroy_modal).not.toHaveBeenCalled();
+
+ // A non-submit close-panel button does not check for validity.
+ el.querySelector("button.cancel").click();
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(spy_destroy_modal).toHaveBeenCalled();
+ });
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ it("1.18 - validates all inputs after submit", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
- document.querySelector("button").click();
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- expect(el.querySelectorAll("em.warning").length).toBe(2);
- });
+ document.querySelector("button").click();
- it("1.19 - validates all inputs after one failed check and disabled button", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- document.querySelector("[name=i1]").dispatchEvent(events.blur_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(2);
- expect(el.querySelector("[name=b1]").disabled).toBe(true);
- expect(el.querySelector("[name=b2]").disabled).toBe(false);
- expect(el.querySelector("[name=b3]").disabled).toBe(true);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+ });
- it("1.20 - does not validate all inputs after one failed check and no disabled button", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
+ it("1.19 - validates all inputs after one failed check and disabled button", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ document.querySelector("[name=i1]").dispatchEvent(events.blur_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+ expect(el.querySelector("[name=b1]").disabled).toBe(true);
+ expect(el.querySelector("[name=b2]").disabled).toBe(false);
+ expect(el.querySelector("[name=b3]").disabled).toBe(true);
+ });
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ it("1.20 - does not validate all inputs after one failed check and no disabled button", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
- document.querySelector("[name=i1]").dispatchEvent(events.blur_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- });
+ document.querySelector("[name=i1]").dispatchEvent(events.blur_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- it("1.21 - Emits an update event when the validation state changes", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=name]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- let event;
- el.addEventListener("pat-update", (e) => {
- event = e;
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
});
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(event.detail.pattern).toBe("validation");
- expect(event.detail.dom).toBe(el);
- expect(event.detail.action).toBe("invalid");
-
- inp.value = "okay";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(event.detail.pattern).toBe("validation");
- expect(event.detail.dom).toBe(el);
- expect(event.detail.action).toBe("valid");
+ it("1.21 - Emits an update event when the validation state changes", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=name]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ let event;
+ el.addEventListener("pat-update", (e) => {
+ event = e;
+ });
+
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(event.detail.pattern).toBe("validation");
+ expect(event.detail.dom).toBe(el);
+ expect(event.detail.action).toBe("invalid");
+
+ inp.value = "okay";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(event.detail.pattern).toBe("validation");
+ expect(event.detail.dom).toBe(el);
+ expect(event.detail.action).toBe("valid");
+ });
});
- it("2.1 - validates required inputs", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=name]");
+ describe("2 - required inputs", function () {
+ it("2.1 - validates required inputs", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=name]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
- // Check validation passes with some input.
- inp.value = "123";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ // Check validation passes with some input.
+ inp.value = "123";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("2.2 - validates required pat-autosuggest inputs on form submit", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=name]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- el.dispatchEvent(events.submit_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
-
- // Check validation passes with some input.
- inp.value = "one";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ it("2.2 - validates required pat-autosuggest inputs on form submit", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=name]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ el.dispatchEvent(events.submit_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+
+ // Check validation passes with some input.
+ inp.value = "one";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("2.3 - validates required inputs with HTML5 required attribute style", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=name]");
+ it("2.3 - validates required inputs with HTML5 required attribute style", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=name]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ });
- it("2.4 - can show custom validation messages", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=name]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelector("em.warning").textContent).toBe(
- "I'm sorry Dave, I can't let you do that."
- );
- });
+ it("2.4 - can show custom validation messages", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=name]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelector("em.warning").textContent).toBe(
+ "I'm sorry Dave, I can't let you do that."
+ );
+ });
- it("2.5 - can show custom per-field validation messages", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=name]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelector("em.warning").textContent).toBe("Computer says no.");
+ it("2.5 - can show custom per-field validation messages", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=name]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelector("em.warning").textContent).toBe("Computer says no.");
+ });
});
- it("3.1 - validates email inputs", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=email]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- inp.value = "invalid email";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelector("em.warning").textContent).toBe(
- "This value must be a valid email address."
- );
-
- inp.value = "person@mail.com";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
+ describe("3 - email inputs", function () {
+ it("3.1 - validates email inputs", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=email]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp.value = "invalid email";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelector("em.warning").textContent).toBe(
+ "This value must be a valid email address."
+ );
+
+ inp.value = "person@mail.com";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
});
- it("4.1 - validates number limits", async function () {
- document.body.innerHTML = `
-
- `;
- const el = document.querySelector(".pat-validation");
- const inp_min = el.querySelector("[name=min]");
- const inp_max = el.querySelector("[name=max]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- // min
-
- inp_min.value = 4;
- inp_min.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelector("em.warning").textContent).toBe(
- "This value must be greater than or equal to 5"
- );
-
- inp_min.value = 6;
- inp_min.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- // max
-
- inp_max.value = 6;
- inp_max.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelector("em.warning").textContent).toBe(
- "This value must be less than or equal to 5"
- );
-
- inp_max.value = 5;
- inp_max.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ describe("4 - number inputs", function () {
+ it("4.1 - validates number limits", async function () {
+ document.body.innerHTML = `
+
+ `;
+ const el = document.querySelector(".pat-validation");
+ const inp_min = el.querySelector("[name=min]");
+ const inp_max = el.querySelector("[name=max]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ // min
+
+ inp_min.value = 4;
+ inp_min.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelector("em.warning").textContent).toBe(
+ "This value must be greater than or equal to 5"
+ );
+
+ inp_min.value = 6;
+ inp_min.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ // max
+
+ inp_max.value = 6;
+ inp_max.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelector("em.warning").textContent).toBe(
+ "This value must be less than or equal to 5"
+ );
+
+ inp_max.value = 5;
+ inp_max.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("4.2 - validates integers", async function () {
- document.body.innerHTML = `
-
- `;
+ it("4.2 - validates integers", async function () {
+ document.body.innerHTML = `
+
+ `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=testing]");
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=testing]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.value = 4.5;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = 4.5;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
- inp.value = 4;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = 4;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("4.3 - validates real numbers within steps", async function () {
- document.body.innerHTML = `
-
- `;
+ it("4.3 - validates real numbers within steps", async function () {
+ document.body.innerHTML = `
+
+ `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=testing]");
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=testing]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.value = 4.55;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = 4.55;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
- inp.value = 4.5;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = 4.5;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
- inp.value = 4;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = 4;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("4.4 - validates real number with any number of decimal places.", async function () {
- document.body.innerHTML = `
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=testing]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- // Let's provoke an error first.
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
-
- inp.value = 3.14159265359;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- inp.value = 3.14;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- inp.value = 3;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ it("4.4 - validates real number with any number of decimal places.", async function () {
+ document.body.innerHTML = `
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=testing]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ // Let's provoke an error first.
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+
+ inp.value = 3.14159265359;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ inp.value = 3.14;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ inp.value = 3;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("4.5 - Number: Checks for correct usage of error messages.", async function () {
- document.body.innerHTML = `
-
- `;
+ it("4.5 - Number: Checks for correct usage of error messages.", async function () {
+ document.body.innerHTML = `
+
+ `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=testing]");
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=testing]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.value = 4.5;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = 4.5;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "The value must be an integer."
- );
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "The value must be an integer."
+ );
- inp.value = 5;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = 5;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("4.6 - Number: Checks for the message-integer message alias for message-number.", async function () {
- document.body.innerHTML = `
-
- `;
+ it("4.6 - Number: Checks for the message-integer message alias for message-number.", async function () {
+ document.body.innerHTML = `
+
+ `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=testing]");
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=testing]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.value = 4.5;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = 4.5;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "The value must be an integer."
- );
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "The value must be an integer."
+ );
- inp.value = 5;
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = 5;
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
});
- // Using ``type="text"`` for date validation as Constraints API
- // ``ValidityState`` information is not updated after programmatically
- // setting values.
- // See: https://twitter.com/thetetet/status/1285239806205755393
- it.skip("5.1 - validates dates with before/after constraints", async function () {
- document.body.innerHTML = `
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=date]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ describe("5 - date inputs", function () {
+ // Using ``type="text"`` for date validation as Constraints API
+ // ``ValidityState`` information is not updated after programmatically
+ // setting values.
+ // See: https://twitter.com/thetetet/status/1285239806205755393
+ it.skip("5.1 - validates dates with before/after constraints", async function () {
+ document.body.innerHTML = `
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=date]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp.value = "2020-02-30";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe("Wong date!");
+ });
- inp.value = "2020-02-30";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe("Wong date!");
- });
+ it("5.2 - validates dates with before/after as min/max attributes with default error message.", async function () {
+ document.body.innerHTML = `
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=date]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ // No error when left empty and not required.
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ // No error when left empty and not required.
+ inp.value = "2010-10-10";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ });
- it("5.2 - validates dates with before/after as min/max attributes with default error message.", async function () {
- document.body.innerHTML = `
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=date]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- // No error when left empty and not required.
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- // No error when left empty and not required.
- inp.value = "2010-10-10";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- });
+ it("5.3 - validates dates with before/after as min/max attributes with custom error message.", async function () {
+ document.body.innerHTML = `
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=date]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ // No error when left empty and not required.
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ inp.value = "2010-10-10";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe("Wong date!");
+
+ inp.value = "2023-02-23";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe("Wong date!");
+
+ inp.value = "2022-01-01";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("5.3 - validates dates with before/after as min/max attributes with custom error message.", async function () {
- document.body.innerHTML = `
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=date]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- // No error when left empty and not required.
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- inp.value = "2010-10-10";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe("Wong date!");
-
- inp.value = "2023-02-23";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe("Wong date!");
-
- inp.value = "2022-01-01";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ it("5.4.1 - validates dates with before/after as pattern config attributes with custom error message.", async function () {
+ document.body.innerHTML = `
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=date]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ // No error when left empty and not required.
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ inp.value = "2010-10-10";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe("Wong date!");
+
+ inp.value = "2023-02-23";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe("Wong date!");
+
+ inp.value = "2022-01-01";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("5.4.1 - validates dates with before/after as pattern config attributes with custom error message.", async function () {
- document.body.innerHTML = `
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=date]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- // No error when left empty and not required.
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- inp.value = "2010-10-10";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe("Wong date!");
-
- inp.value = "2023-02-23";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe("Wong date!");
-
- inp.value = "2022-01-01";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ it("5.4.2 - validates dates with before/after as pattern config attributes with NO custom error message, using fixed dates.", async function () {
+ document.body.innerHTML = `
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=date]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ // No error when left empty and not required.
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ inp.value = "2010-10-10";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "The date must be after 2011-11-11"
+ );
+
+ inp.value = "2023-02-23";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "The date must be before 2022-02-22"
+ );
+
+ inp.value = "2022-01-01";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("5.4.2 - validates dates with before/after as pattern config attributes with NO custom error message, using fixed dates.", async function () {
- document.body.innerHTML = `
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=date]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- // No error when left empty and not required.
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- inp.value = "2010-10-10";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "The date must be after 2011-11-11"
- );
-
- inp.value = "2023-02-23";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "The date must be before 2022-02-22"
- );
-
- inp.value = "2022-01-01";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ it("5.4.3 - validates dates with before/after as pattern config attributes with NO custom error message, using labels.", async function () {
+ document.body.innerHTML = `
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp1 = el.querySelector("[name=date1]");
+ const inp2 = el.querySelector("[name=date2]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp1.value = "2010-10-10";
+ inp2.value = "2001-01-01";
+
+ inp1.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "The date must be before woo date"
+ );
+
+ expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
+ "The date must be after ye date"
+ );
+ });
- it("5.4.3 - validates dates with before/after as pattern config attributes with NO custom error message, using labels.", async function () {
- document.body.innerHTML = `
-
- `;
+
+ `;
- const el = document.querySelector(".pat-validation");
- const inp1 = el.querySelector("[name=date1]");
- const inp2 = el.querySelector("[name=date2]");
+ const el = document.querySelector(".pat-validation");
+ const inp1 = el.querySelector("[name=date1]");
+ const inp2 = el.querySelector("[name=date2]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp1.value = "2010-10-10";
- inp2.value = "2001-01-01";
+ inp1.value = "2010-10-10";
+ inp2.value = "2001-01-01";
- inp1.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(2);
+ inp1.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "The date must be before woo date"
- );
-
- expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
- "The date must be after ye date"
- );
- });
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "The date must be before date2"
+ );
- it("5.4.4 - validates dates with before/after as pattern config attributes with NO custom error message, using input names.", async function () {
- document.body.innerHTML = `
-
-
-
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp1 = el.querySelector("[name=date1]");
- const inp2 = el.querySelector("[name=date2]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- inp1.value = "2010-10-10";
- inp2.value = "2001-01-01";
-
- inp1.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(2);
-
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "The date must be before date2"
- );
-
- expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
- "The date must be after date1"
- );
- });
+ expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
+ "The date must be after date1"
+ );
+ });
- it("5.5 - validates dates with before/after constraints", async function () {
- document.body.innerHTML = `
-
-
-
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp_start = el.querySelector("[name=start]");
- const inp_end = el.querySelector("[name=end]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- // Before/after without required allows for empty dates of the
- // relation.
- inp_start.value = "2020-10-10";
- inp_start.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- // Violate the before/after constraint
- inp_end.value = "2020-10-05";
- inp_end.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(2);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "The start date must on or before the end date."
- );
- expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
- "The end date must on or before the start date."
- );
-
- // Fulfill the before/after constraint - same date
- inp_start.value = "2020-10-10";
- inp_start.dispatchEvent(events.change_event());
- inp_end.value = "2020-10-10";
- inp_end.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- // Violate the before/after constraint
- inp_start.value = "2020-10-11";
- inp_start.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(2);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "The start date must on or before the end date."
- );
- expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
- "The end date must on or before the start date."
- );
-
- // Fulfill the before/after constraint - start before end
- inp_start.value = "2020-10-01";
- inp_start.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- // Before/after without required allows for empty dates of the
- // relation.
- inp_start.value = "";
- inp_start.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- // Violate the constraint again...
- inp_start.value = "2020-10-11";
- inp_start.dispatchEvent(events.change_event());
- inp_end.value = "2020-10-10";
- inp_end.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(2);
-
- // Clearing one of the optional values should clear all errors.
- inp_start.value = "";
- inp_start.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ it("5.5 - validates dates with before/after constraints", async function () {
+ document.body.innerHTML = `
+
+
+
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp_start = el.querySelector("[name=start]");
+ const inp_end = el.querySelector("[name=end]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ // Before/after without required allows for empty dates of the
+ // relation.
+ inp_start.value = "2020-10-10";
+ inp_start.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ // Violate the before/after constraint
+ inp_end.value = "2020-10-05";
+ inp_end.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "The start date must on or before the end date."
+ );
+ expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
+ "The end date must on or before the start date."
+ );
+
+ // Fulfill the before/after constraint - same date
+ inp_start.value = "2020-10-10";
+ inp_start.dispatchEvent(events.change_event());
+ inp_end.value = "2020-10-10";
+ inp_end.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ // Violate the before/after constraint
+ inp_start.value = "2020-10-11";
+ inp_start.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "The start date must on or before the end date."
+ );
+ expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
+ "The end date must on or before the start date."
+ );
+
+ // Fulfill the before/after constraint - start before end
+ inp_start.value = "2020-10-01";
+ inp_start.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ // Before/after without required allows for empty dates of the
+ // relation.
+ inp_start.value = "";
+ inp_start.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ // Violate the constraint again...
+ inp_start.value = "2020-10-11";
+ inp_start.dispatchEvent(events.change_event());
+ inp_end.value = "2020-10-10";
+ inp_end.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+
+ // Clearing one of the optional values should clear all errors.
+ inp_start.value = "";
+ inp_start.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("5.6 - doesn't validate empty optional dates", async function () {
- document.body.innerHTML = `
-
+ `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=date]");
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=date]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("5.7 - do require-validate non-empty required dates", async function () {
- document.body.innerHTML = `
-
-
-
- `;
+ it("5.7 - do require-validate non-empty required dates", async function () {
+ document.body.innerHTML = `
+
+
+
+ `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=input]");
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=input]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.value = "";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = "";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "This field is required"
- );
- });
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "This field is required"
+ );
+ });
- it("5.8 - validates datetime-local with before/after constraints", async function () {
- document.body.innerHTML = `
-
-
-
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp_start = el.querySelector("[name=start]");
- const inp_end = el.querySelector("[name=end]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- // Before/after without required allows for empty dates of the
- // relation.
- inp_start.value = "2022-01-05T10:00";
- inp_start.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- // Violate the before/after constraint
- inp_end.value = "2022-01-05T09:00";
- inp_end.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(2);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "The start date/time must on or before the end date/time."
- );
- expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
- "The end date/time must on or before the start date/time."
- );
-
- // Fulfill the before/after constraint - same date
- inp_start.value = "2022-01-05T10:00";
- inp_start.dispatchEvent(events.change_event());
- inp_end.value = "2022-01-05T10:00";
- inp_end.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- // Violate the before/after constraint
- inp_start.value = "2022-01-05T11:00";
- inp_start.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(2);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "The start date/time must on or before the end date/time."
- );
- expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
- "The end date/time must on or before the start date/time."
- );
-
- // Fulfill the before/after constraint - start before end
- inp_start.value = "2022-01-04T10:00";
- inp_start.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
-
- // Before/after without required allows for empty dates of the
- // relation.
- inp_start.value = "";
- inp_start.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- });
+ it("5.8 - validates datetime-local with before/after constraints", async function () {
+ document.body.innerHTML = `
+
+
+
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp_start = el.querySelector("[name=start]");
+ const inp_end = el.querySelector("[name=end]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ // Before/after without required allows for empty dates of the
+ // relation.
+ inp_start.value = "2022-01-05T10:00";
+ inp_start.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ // Violate the before/after constraint
+ inp_end.value = "2022-01-05T09:00";
+ inp_end.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "The start date/time must on or before the end date/time."
+ );
+ expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
+ "The end date/time must on or before the start date/time."
+ );
+
+ // Fulfill the before/after constraint - same date
+ inp_start.value = "2022-01-05T10:00";
+ inp_start.dispatchEvent(events.change_event());
+ inp_end.value = "2022-01-05T10:00";
+ inp_end.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ // Violate the before/after constraint
+ inp_start.value = "2022-01-05T11:00";
+ inp_start.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(2);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "The start date/time must on or before the end date/time."
+ );
+ expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
+ "The end date/time must on or before the start date/time."
+ );
+
+ // Fulfill the before/after constraint - start before end
+ inp_start.value = "2022-01-04T10:00";
+ inp_start.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+
+ // Before/after without required allows for empty dates of the
+ // relation.
+ inp_start.value = "";
+ inp_start.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
- it("5.9 - Do not interpret ``ok-1`` as a valid date.", async function () {
- // This issue popped up in Chrome but not in Firefox.
- // A date like ``ok-1`` was interpreted as ``2000-12-31T23:00:00.000Z``.
- // Explicitly checking for a valid ISO 8601 date fixes this.
+ it("5.9 - Do not interpret ``ok-1`` as a valid date.", async function () {
+ // This issue popped up in Chrome but not in Firefox.
+ // A date like ``ok-1`` was interpreted as ``2000-12-31T23:00:00.000Z``.
+ // Explicitly checking for a valid ISO 8601 date fixes this.
- document.body.innerHTML = `
-
-
-
- `;
+ document.body.innerHTML = `
+
+
+
+ `;
- const el = document.querySelector(".pat-validation");
- const inp = el.querySelector("[name=date]");
+ const el = document.querySelector(".pat-validation");
+ const inp = el.querySelector("[name=date]");
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
- inp.value = "2022-01-01";
- inp.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
+ inp.value = "2022-01-01";
+ inp.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ });
});
- it("6.1 - validates radio buttons", async function () {
- document.body.innerHTML = `
-
-
-
-
-
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inps = el.querySelectorAll("[name=colour]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- el.dispatchEvent(events.submit_event());
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "This field is required"
- );
-
- inps[0].checked = true;
- el.addEventListener("submit", (e) => {
- e.preventDefault();
- e.stopPropagation();
+ describe("6 - radio inputs", function () {
+ it("6.1 - validates radio buttons", async function () {
+ document.body.innerHTML = `
+
+
+
+
+
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inps = el.querySelectorAll("[name=colour]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ el.dispatchEvent(events.submit_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "This field is required"
+ );
+
+ inps[0].checked = true;
+ el.addEventListener("submit", (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ });
+ el.dispatchEvent(events.submit_event());
+
+ await utils.timeout(1); // wait a tick for async to settle.
+
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
});
- el.dispatchEvent(events.submit_event());
-
- await utils.timeout(1); // wait a tick for async to settle.
-
- expect(el.querySelectorAll("em.warning").length).toBe(0);
});
- it("7.1 - can check for password confirmation", async function () {
- document.body.innerHTML = `
-
-
-
-
-
- `;
-
- const el = document.querySelector(".pat-validation");
- const inp_p = el.querySelector("[name=password]");
- const inp_c = el.querySelector("[name=password-confirmation]");
-
- const instance = new Pattern(el);
- await events.await_pattern_init(instance);
-
- inp_p.value = "foo";
- inp_c.value = "bar";
- inp_c.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(1);
- expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
- "I would like this to be equal to password"
- );
- expect(el.querySelector("#form-buttons-create").disabled).toBe(true);
-
- inp_c.value = "foo";
- inp_c.dispatchEvent(events.change_event());
- await utils.timeout(1); // wait a tick for async to settle.
- expect(el.querySelectorAll("em.warning").length).toBe(0);
- expect(el.querySelector("#form-buttons-create").disabled).toBe(false);
+ describe("7 - password inputs", function () {
+ it("7.1 - can check for password confirmation", async function () {
+ document.body.innerHTML = `
+
+
+
+
+
+ `;
+
+ const el = document.querySelector(".pat-validation");
+ const inp_p = el.querySelector("[name=password]");
+ const inp_c = el.querySelector("[name=password-confirmation]");
+
+ const instance = new Pattern(el);
+ await events.await_pattern_init(instance);
+
+ inp_p.value = "foo";
+ inp_c.value = "bar";
+ inp_c.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(1);
+ expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
+ "I would like this to be equal to password"
+ );
+ expect(el.querySelector("#form-buttons-create").disabled).toBe(true);
+
+ inp_c.value = "foo";
+ inp_c.dispatchEvent(events.change_event());
+ await utils.timeout(1); // wait a tick for async to settle.
+ expect(el.querySelectorAll("em.warning").length).toBe(0);
+ expect(el.querySelector("#form-buttons-create").disabled).toBe(false);
+ });
});
});