Skip to content

Commit 1272ac5

Browse files
committed
fix(pat-close-panel): Do not prevent closing for formnovalidate buttons.
Do not prevent closing of panels when a form with invalid data is submitted when a button with the formnovalidate attribute is pressed. This is useful for cases where a "cancel" button actually needs to submit to roll back any changes which were already made.
1 parent 27b0a3f commit 1272ac5

File tree

2 files changed

+90
-23
lines changed

2 files changed

+90
-23
lines changed

src/pat/close-panel/close-panel.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export default Base.extend({
2525
await utils.timeout(0); // Wait for other patterns, like pat-validation.
2626

2727
if (
28+
e.target.matches(":not([formnovalidate])") &&
2829
e.target.matches("[type=submit], button:not([type=button])") &&
2930
this.el.closest("form")?.checkValidity() === false
3031
) {

src/pat/close-panel/close-panel.test.js

Lines changed: 89 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe("pat close-panel", function () {
1010
document.body.innerHTML = "";
1111
});
1212

13-
it("Closes a modal's panel.", async function () {
13+
it("1 - Closes a modal's panel.", async function () {
1414
document.body.innerHTML = `
1515
<div id="pat-modal" class="pat-modal">
1616
<button id="close-modal" class="close-panel">close</button>
@@ -42,7 +42,7 @@ describe("pat close-panel", function () {
4242
expect(document.querySelectorAll(".pat-modal").length).toBe(0);
4343
});
4444

45-
it("Closes a dialog's panel.", async function () {
45+
it("2 - Closes a dialog's panel.", async function () {
4646
document.body.innerHTML = `
4747
<dialog open>
4848
<button class="close-panel">close</button>
@@ -61,32 +61,98 @@ describe("pat close-panel", function () {
6161
expect(dialog.open).toBe(false);
6262
});
6363

64-
it("Prevents closing a panel with an invalid form when submitting but allow to cancel and close.", async function () {
65-
const spy_destroy_modal = jest.spyOn(pat_modal.prototype, "destroy");
64+
describe("3 - Prevents closing a panel with an invalid form when submitting but allow to cancel and close.", function () {
65+
it("3.1 - ... when the cancel button is not a submit button", async function () {
66+
const spy_destroy_modal = jest.spyOn(pat_modal.prototype, "destroy");
67+
68+
document.body.innerHTML = `
69+
<div class="pat-modal">
70+
<form action="." class="pat-validation">
71+
<input name="ok" required />
72+
<button class="close-panel submit">submit</button>
73+
<button class="close-panel cancel" type="button">cancel</button>
74+
</form>
75+
</div>
76+
`;
77+
const el = document.querySelector("form");
6678

67-
document.body.innerHTML = `
68-
<div class="pat-modal">
69-
<form action="." class="pat-validation">
70-
<input name="ok" required />
71-
<button class="close-panel submit">submit</button>
72-
<button class="close-panel cancel" type="button">cancel</button>
73-
</form>
74-
</div>
75-
`;
76-
const el = document.querySelector("form");
79+
registry.scan(document.body);
80+
await utils.timeout(1); // wait a tick for async to settle.
81+
82+
el.querySelector("button.submit").click();
83+
await utils.timeout(1); // wait a tick for async to settle.
84+
85+
expect(spy_destroy_modal).not.toHaveBeenCalled();
86+
87+
// A non-submit close-panel button does not check for validity.
88+
el.querySelector("button.cancel").click();
89+
await utils.timeout(1); // wait a tick for async to settle.
90+
91+
expect(spy_destroy_modal).toHaveBeenCalled();
92+
93+
spy_destroy_modal.mockRestore();
94+
});
95+
96+
it("3.2 - ... when the cancel button is a submit button but has the formnovalidate attribute set", async function () {
97+
const spy_destroy_modal = jest.spyOn(pat_modal.prototype, "destroy");
98+
99+
document.body.innerHTML = `
100+
<div class="pat-modal">
101+
<form action="." class="pat-validation">
102+
<input name="ok" required />
103+
<button class="close-panel submit">submit</button>
104+
<button class="close-panel cancel" formnovalidate>cancel</button>
105+
</form>
106+
</div>
107+
`;
108+
const el = document.querySelector("form");
109+
110+
registry.scan(document.body);
111+
await utils.timeout(1); // wait a tick for async to settle.
112+
113+
el.querySelector("button.submit").click();
114+
await utils.timeout(1); // wait a tick for async to settle.
115+
116+
expect(spy_destroy_modal).not.toHaveBeenCalled();
117+
118+
// A non-submit close-panel button does not check for validity.
119+
el.querySelector("button.cancel").click();
120+
await utils.timeout(1); // wait a tick for async to settle.
121+
122+
expect(spy_destroy_modal).toHaveBeenCalled();
123+
124+
spy_destroy_modal.mockRestore();
125+
});
126+
127+
it("3.3 - ... when the cancel button is a submit input but has the formnovalidate attribute set", async function () {
128+
const spy_destroy_modal = jest.spyOn(pat_modal.prototype, "destroy");
129+
130+
document.body.innerHTML = `
131+
<div class="pat-modal">
132+
<form action="." class="pat-validation">
133+
<input name="ok" required />
134+
<button class="close-panel submit">submit</button>
135+
<input type="submit" value="cancel" class="close-panel cancel" formnovalidate />
136+
</form>
137+
</div>
138+
`;
139+
const el = document.querySelector("form");
140+
141+
registry.scan(document.body);
142+
await utils.timeout(1); // wait a tick for async to settle.
77143

78-
registry.scan(document.body);
79-
await utils.timeout(1); // wait a tick for async to settle.
144+
el.querySelector("button.submit").click();
145+
await utils.timeout(1); // wait a tick for async to settle.
80146

81-
el.querySelector("button.submit").click();
82-
await utils.timeout(1); // wait a tick for async to settle.
147+
expect(spy_destroy_modal).not.toHaveBeenCalled();
83148

84-
expect(spy_destroy_modal).not.toHaveBeenCalled();
149+
// A non-submit close-panel button does not check for validity.
150+
el.querySelector("input.cancel").click();
151+
await utils.timeout(1); // wait a tick for async to settle.
85152

86-
// A non-submit close-panel button does not check for validity.
87-
el.querySelector("button.cancel").click();
88-
await utils.timeout(1); // wait a tick for async to settle.
153+
expect(spy_destroy_modal).toHaveBeenCalled();
89154

90-
expect(spy_destroy_modal).toHaveBeenCalled();
155+
spy_destroy_modal.mockRestore();
156+
});
91157
});
92158
});

0 commit comments

Comments
 (0)