Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(pat-inject): Allow to submit invalid forms when form/novalidate. #1207

Merged
merged 1 commit into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/pat/inject/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,20 @@ const inject = {
const $el = $(e.currentTarget);
let cfgs = $el.data("pat-inject");
if ($el[0].tagName === "FORM" && e.type === "submit") {
if ($el[0].matches(":invalid")) {
// Do not submit invalid forms.
// Works with native form validation and with pat-validation.
const form = $el[0];
const submitter = e.submitter;

// Do not submit invalid forms, if validation is active.
// Works with native form validation and with pat-validation.
if (
!submitter?.matches("[formnovalidate]") &&
!form.matches("[novalidate]") &&
form.matches(":invalid")
) {
log.debug("Form is invalid, aborting");
return;
}

const submitter = e.submitter;
const formaction = submitter?.getAttribute("formaction");
if (formaction) {
const opts = {
Expand Down
122 changes: 122 additions & 0 deletions src/pat/inject/inject.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,128 @@ describe("pat-inject", function () {
expect(pattern.onTrigger).toHaveBeenCalledTimes(1);
});
});

describe("9.2.4.6 - Validation on submit", () => {
it("9.2.4.6.1 - Submit valid forms.", async function () {
document.body.innerHTML = `
<form action="." class="pat-inject">
<input name="ok" />
<button>submit</button>
</form>
`;
jest.spyOn(pattern, "execute");

const form = document.querySelector("form");
const button = form.querySelector("button");

// add submit listener
let catched = false;
form.addEventListener("submit", () => {
catched = true;
});

pattern.init($(form));
await utils.timeout(1); // wait a tick for async to settle.

button.click();

expect(catched).toBe(true);
expect(pattern.execute).toHaveBeenCalled();
});

it("9.2.4.6.2 - Do not submit invalid forms.", async function () {
document.body.innerHTML = `
<form action="." class="pat-inject">
<input name="ok" required />
<button>submit</button>
</form>
`;
jest.spyOn(pattern, "execute");

const form = document.querySelector("form");
const button = form.querySelector("button");

// add submit listener
let catched = false;
form.addEventListener("submit", () => {
catched = true;
});

pattern.init($(form));
await utils.timeout(1); // wait a tick for async to settle.

button.click();

expect(catched).toBe(false);
expect(pattern.execute).not.toHaveBeenCalled();
});

it("9.2.4.6.3 - Respect a form novalidate attribute and allow submission.", async function () {
document.body.innerHTML = `
<form novalidate action="." class="pat-inject">
<input name="ok" required />
<button>submit</button>
</form>
`;
jest.spyOn(pattern, "execute");

const form = document.querySelector("form");
const button = form.querySelector("button");

// add submit listener
let catched = false;
form.addEventListener("submit", () => {
catched = true;
});

pattern.init($(form));
await utils.timeout(1); // wait a tick for async to settle.

button.click();

expect(catched).toBe(true);
expect(pattern.execute).toHaveBeenCalled();
});

// The following test does not work with jsDOM 25.0.1.
// jsDOM supports `form[novalidate]` but not `button[formnovalidate]`
// Ref: https://github.com/jsdom/jsdom/pull/3249
it.skip("9.2.4.6.4 - Respect a formnovalidate attribute on buttons and allow submission.", async function () {
document.body.innerHTML = `
<form action="." class="pat-inject">
<input name="ok" required />
<button class="cancel" formnovalidate>cancel</button>
<button class="submit">submit</button>
</form>
`;
jest.spyOn(pattern, "execute");

const form = document.querySelector("form");
const button_cancel = form.querySelector("button.cancel");
const button_submit = form.querySelector("button.submit");

// add submit listener
let catched = false;
form.addEventListener("submit", () => {
catched = true;
});

pattern.init($(form));
await utils.timeout(1); // wait a tick for async to settle.

button_submit.click();

expect(catched).toBe(false);
expect(pattern.execute).not.toHaveBeenCalled();

button_cancel.click();

expect(catched).toBe(true);
expect(pattern.execute).toHaveBeenCalled();

});

});
});
});
});
Expand Down