browser_submission_flush.js (3775B)
1 "use strict"; 2 // Form submissions triggered by the Javascript 'submit' event listener are 3 // deferred until the event listener finishes. However, changes to specific 4 // attributes ("action" and "target" attributes) need to cause an immediate 5 // flush of any pending submission to prevent the form submission from using the 6 // wrong action or target. This test ensures that such flushes happen properly. 7 8 const kTestPage = 9 "https://example.org/browser/dom/html/test/submission_flush.html"; 10 // This is the page pointed to by the form action in the test HTML page. 11 const kPostActionPage = 12 "https://example.org/browser/dom/html/test/post_action_page.html"; 13 14 const kFormId = "test_form"; 15 const kFrameId = "test_frame"; 16 const kSubmitButtonId = "submit_button"; 17 18 // Take in a variety of actions (in the form of setting and unsetting form 19 // attributes). Then submit the form in the submit event listener to cause a 20 // deferred form submission. Then perform the test actions and ensure that the 21 // form used the correct attribute values rather than the changed ones. 22 async function runTest(aTestActions) { 23 let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, kTestPage); 24 registerCleanupFunction(() => BrowserTestUtils.removeTab(tab)); 25 26 /* eslint-disable no-shadow */ 27 let frame_url = await SpecialPowers.spawn( 28 gBrowser.selectedBrowser, 29 [{ kFormId, kFrameId, kSubmitButtonId, aTestActions }], 30 async function ({ kFormId, kFrameId, kSubmitButtonId, aTestActions }) { 31 let form = content.document.getElementById(kFormId); 32 33 form.addEventListener( 34 "submit", 35 event => { 36 // Need to trigger the deferred submission by submitting in the submit 37 // event handler. To prevent the form from being submitted twice, the 38 // <form> tag contains the attribute |onsubmit="return false;"| to cancel 39 // the original submission. 40 form.submit(); 41 42 if (aTestActions.setattr) { 43 for (let { attr, value } of aTestActions.setattr) { 44 form.setAttribute(attr, value); 45 } 46 } 47 if (aTestActions.unsetattr) { 48 for (let attr of aTestActions.unsetattr) { 49 form.removeAttribute(attr); 50 } 51 } 52 }, 53 { capture: true, once: true } 54 ); 55 56 // Trigger the above event listener 57 content.document.getElementById(kSubmitButtonId).click(); 58 59 // Test that the form was submitted to the correct target (the frame) with 60 // the correct action (kPostActionPage). 61 let frame = content.document.getElementById(kFrameId); 62 await new Promise(resolve => { 63 frame.addEventListener("load", resolve, { once: true }); 64 }); 65 return frame.contentWindow.location.href; 66 } 67 ); 68 /* eslint-enable no-shadow */ 69 is( 70 frame_url, 71 kPostActionPage, 72 "Form should have submitted with correct target and action" 73 ); 74 } 75 76 add_task(async function () { 77 info("Changing action should flush pending submissions"); 78 await runTest({ setattr: [{ attr: "action", value: "about:blank" }] }); 79 }); 80 81 add_task(async function () { 82 info("Changing target should flush pending submissions"); 83 await runTest({ setattr: [{ attr: "target", value: "_blank" }] }); 84 }); 85 86 add_task(async function () { 87 info("Unsetting action should flush pending submissions"); 88 await runTest({ unsetattr: ["action"] }); 89 }); 90 91 // On failure, this test will time out rather than failing an assert. When the 92 // target attribute is not set, the form will submit the active page, navigating 93 // it away and preventing the wait for iframe load from ever finishing. 94 add_task(async function () { 95 info("Unsetting target should flush pending submissions"); 96 await runTest({ unsetattr: ["target"] }); 97 });