From 5982bd328d72c51d505e624459c399d1f83f76c1 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Wed, 9 Mar 2022 10:57:11 +0100 Subject: [PATCH 1/2] maint(pat tabs): Fix test for error not thrown. Fix an asynchronous test which checks for an error not to be thrown. The problem popped up in node version 16 and was passing in node version 14. The error was: ``` RUNS src/pat/tabs/tabs.test.js node:internal/process/promises:265 triggerUncaughtException(err, true /* fromPromise */); ^ [UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "TypeError: Cannot read properties of undefined (reading 'jquery')".] { code: 'ERR_UNHANDLED_REJECTION' } ``` --- src/pat/tabs/tabs.test.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/pat/tabs/tabs.test.js b/src/pat/tabs/tabs.test.js index 87318fb97..990744f4e 100644 --- a/src/pat/tabs/tabs.test.js +++ b/src/pat/tabs/tabs.test.js @@ -325,9 +325,19 @@ describe("pat-tabs", function () { el.innerHTML = "
"; jest.spyOn(el, "getBoundingClientRect").mockImplementation(() => { return { x: 0, width: 0 }; }); // prettier-ignore - pattern.init(el.querySelector("div")); - await utils.timeout(1); - document.body.dispatchEvent(new Event("pat-update")); - expect(pattern).not.toThrow(TypeError); + let thrown = false; + try { + pattern.init(el.querySelector("div")); + await utils.timeout(1); + document.body.dispatchEvent(new Event("pat-update")); + await utils.timeout(1); + } catch (e) { + if (e instanceof TypeError) { + thrown = true; + } else { + throw e; + } + } + expect(thrown).toBe(false); }); }); From 2fa54cf26abdc49ce7a872a6a944dc23a9115c41 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Fri, 4 Mar 2022 17:25:58 +0100 Subject: [PATCH 2/2] fix(pat validation): With depending date validation also validate the dependend date. Fixes: #970 --- src/pat/validation/validation.js | 31 ++++++++++++-------- src/pat/validation/validation.test.js | 42 +++++++++++++++------------ 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/pat/validation/validation.js b/src/pat/validation/validation.js index 79c5511d2..16187e19b 100644 --- a/src/pat/validation/validation.js +++ b/src/pat/validation/validation.js @@ -57,7 +57,7 @@ export default Base.extend({ for (const [cnt, input] of this.inputs.entries()) { // Cancelable debouncer. const debouncer = utils.debounce((e) => { - this.check_input(input, e); + this.check_input({ input: input, event: e }); }, this.options.delay); events.add_event_listener( @@ -82,12 +82,12 @@ export default Base.extend({ this.el, "submit", `pat-validation--blur-${input.name}--${cnt}--validator`, - (e) => this.check_input(input, e) // immediate check with submit. Otherwise submit is not cancelable. + (e) => this.check_input({ input: input, event: e }) // immediate check with submit. Otherwise submit is not cancelable. ); } }, - check_input(input, e) { + check_input({ input, event, stop = false }) { if (input.disabled) { // No need to check disabled inputs. return; @@ -97,7 +97,7 @@ export default Base.extend({ this.set_validity({ input: input, msg: "" }); const validity_state = input.validity; - if (e.submitter?.hasAttribute("formnovalidate")) { + if (event?.submitter?.hasAttribute("formnovalidate")) { // Do not submit when a button with ``formnovalidate`` was used. return; } @@ -139,6 +139,8 @@ export default Base.extend({ let not_after; let not_before; + let not_after_el; + let not_before_el; const date = new Date(input.value); if (isNaN(date)) { // Should not happen or input only partially typed in. @@ -149,9 +151,8 @@ export default Base.extend({ not_after = new Date(input_options.not.after); if (isNaN(not_after)) { // Handle value as selector - not_after = document.querySelector( - input_options.not.after - )?.value; + not_after_el = document.querySelector(input_options.not.after); + not_after = not_after_el?.value; not_after = not_after && new Date( @@ -167,9 +168,8 @@ export default Base.extend({ not_before = new Date(input_options.not.before); if (isNaN(not_before)) { // Handle value as selector - not_before = document.querySelector( - input_options.not.before - )?.value; + not_before_el = document.querySelector(input_options.not.before); + not_before = not_before_el?.value; not_before = not_before && new Date( @@ -185,6 +185,13 @@ export default Base.extend({ } else if (not_before && date < not_before) { this.set_validity({ input: input, msg: msg }); } + // always check the other input to clear/set errors + !stop && // do not re-check when stop is set to avoid infinite loops + not_after_el && + this.check_input({ input: not_after_el, stop: true }); + !stop && + not_before_el && + this.check_input({ input: not_before_el, stop: true }); } if (!validity_state.customError) { @@ -248,9 +255,9 @@ export default Base.extend({ } } - if (e.type === "submit") { + if (event?.type === "submit") { // Do not submit in error case. - e.preventDefault(); + event.preventDefault(); } this.set_error_message(input, input_options); }, diff --git a/src/pat/validation/validation.test.js b/src/pat/validation/validation.test.js index 226e24ab7..bfdd5838e 100644 --- a/src/pat/validation/validation.test.js +++ b/src/pat/validation/validation.test.js @@ -824,15 +824,6 @@ describe("pat-validation", function () { 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(1); - expect(el.querySelectorAll("em.warning")[0].textContent).toBe( - "The end date must on or before the start date." - ); - - // Violate the before/after constraint - inp_start.value = "2020-10-06"; - 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." @@ -849,6 +840,18 @@ describe("pat-validation", function () { 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()); @@ -947,15 +950,6 @@ describe("pat-validation", function () { 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(1); - expect(el.querySelectorAll("em.warning")[0].textContent).toBe( - "The end date/time must on or before the start date/time." - ); - - // 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." @@ -972,6 +966,18 @@ describe("pat-validation", function () { 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());