Skip to content

Commit 993d27d

Browse files
committed
fix(pat-inject): Allow to submit invalid forms when form/novalidate.
Respect the form[novalidate] and button[formnovalidate] attributes and allow the submission of invalid forms. This is necessary if a cancel button is a submit button and needs to be allowed to submit even if the form input is invalid.
1 parent da5703c commit 993d27d

File tree

2 files changed

+132
-4
lines changed

2 files changed

+132
-4
lines changed

src/pat/inject/inject.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,20 @@ const inject = {
186186
const $el = $(e.currentTarget);
187187
let cfgs = $el.data("pat-inject");
188188
if ($el[0].tagName === "FORM" && e.type === "submit") {
189-
if ($el[0].matches(":invalid")) {
190-
// Do not submit invalid forms.
191-
// Works with native form validation and with pat-validation.
189+
const form = $el[0];
190+
const submitter = e.submitter;
191+
192+
// Do not submit invalid forms, if validation is active.
193+
// Works with native form validation and with pat-validation.
194+
if (
195+
!submitter?.matches("[formnovalidate]") &&
196+
!form.matches("[novalidate]") &&
197+
form.matches(":invalid")
198+
) {
192199
log.debug("Form is invalid, aborting");
193200
return;
194201
}
195202

196-
const submitter = e.submitter;
197203
const formaction = submitter?.getAttribute("formaction");
198204
if (formaction) {
199205
const opts = {

src/pat/inject/inject.test.js

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,128 @@ describe("pat-inject", function () {
14391439
expect(pattern.onTrigger).toHaveBeenCalledTimes(1);
14401440
});
14411441
});
1442+
1443+
describe("9.2.4.6 - Validation on submit", () => {
1444+
it("9.2.4.6.1 - Submit valid forms.", async function () {
1445+
document.body.innerHTML = `
1446+
<form action="." class="pat-inject">
1447+
<input name="ok" />
1448+
<button>submit</button>
1449+
</form>
1450+
`;
1451+
jest.spyOn(pattern, "execute");
1452+
1453+
const form = document.querySelector("form");
1454+
const button = form.querySelector("button");
1455+
1456+
// add submit listener
1457+
let catched = false;
1458+
form.addEventListener("submit", () => {
1459+
catched = true;
1460+
});
1461+
1462+
pattern.init($(form));
1463+
await utils.timeout(1); // wait a tick for async to settle.
1464+
1465+
button.click();
1466+
1467+
expect(catched).toBe(true);
1468+
expect(pattern.execute).toHaveBeenCalled();
1469+
});
1470+
1471+
it("9.2.4.6.2 - Do not submit invalid forms.", async function () {
1472+
document.body.innerHTML = `
1473+
<form action="." class="pat-inject">
1474+
<input name="ok" required />
1475+
<button>submit</button>
1476+
</form>
1477+
`;
1478+
jest.spyOn(pattern, "execute");
1479+
1480+
const form = document.querySelector("form");
1481+
const button = form.querySelector("button");
1482+
1483+
// add submit listener
1484+
let catched = false;
1485+
form.addEventListener("submit", () => {
1486+
catched = true;
1487+
});
1488+
1489+
pattern.init($(form));
1490+
await utils.timeout(1); // wait a tick for async to settle.
1491+
1492+
button.click();
1493+
1494+
expect(catched).toBe(false);
1495+
expect(pattern.execute).not.toHaveBeenCalled();
1496+
});
1497+
1498+
it("9.2.4.6.3 - Respect a form novalidate attribute and allow submission.", async function () {
1499+
document.body.innerHTML = `
1500+
<form novalidate action="." class="pat-inject">
1501+
<input name="ok" required />
1502+
<button>submit</button>
1503+
</form>
1504+
`;
1505+
jest.spyOn(pattern, "execute");
1506+
1507+
const form = document.querySelector("form");
1508+
const button = form.querySelector("button");
1509+
1510+
// add submit listener
1511+
let catched = false;
1512+
form.addEventListener("submit", () => {
1513+
catched = true;
1514+
});
1515+
1516+
pattern.init($(form));
1517+
await utils.timeout(1); // wait a tick for async to settle.
1518+
1519+
button.click();
1520+
1521+
expect(catched).toBe(true);
1522+
expect(pattern.execute).toHaveBeenCalled();
1523+
});
1524+
1525+
// The following test does not work with jsDOM 25.0.1.
1526+
// jsDOM supports `form[novalidate]` but not `button[formnovalidate]`
1527+
// Ref: https://github.com/jsdom/jsdom/pull/3249
1528+
it.skip("9.2.4.6.4 - Respect a formnovalidate attribute on buttons and allow submission.", async function () {
1529+
document.body.innerHTML = `
1530+
<form action="." class="pat-inject">
1531+
<input name="ok" required />
1532+
<button class="cancel" formnovalidate>cancel</button>
1533+
<button class="submit">submit</button>
1534+
</form>
1535+
`;
1536+
jest.spyOn(pattern, "execute");
1537+
1538+
const form = document.querySelector("form");
1539+
const button_cancel = form.querySelector("button.cancel");
1540+
const button_submit = form.querySelector("button.submit");
1541+
1542+
// add submit listener
1543+
let catched = false;
1544+
form.addEventListener("submit", () => {
1545+
catched = true;
1546+
});
1547+
1548+
pattern.init($(form));
1549+
await utils.timeout(1); // wait a tick for async to settle.
1550+
1551+
button_submit.click();
1552+
1553+
expect(catched).toBe(false);
1554+
expect(pattern.execute).not.toHaveBeenCalled();
1555+
1556+
button_cancel.click();
1557+
1558+
expect(catched).toBe(true);
1559+
expect(pattern.execute).toHaveBeenCalled();
1560+
1561+
});
1562+
1563+
});
14421564
});
14431565
});
14441566
});

0 commit comments

Comments
 (0)