Bug 1874684 - Part 28: Return DateDuration from DifferenceISODateTime. r=mgaudet
[gecko.git] / docshell / test / unit / test_subframe_stop_after_parent_error.js
blobb7ae25ee84eb19fdffaf25b831f4799a4db4cca6
1 "use strict";
2 // Tests that pending subframe requests for an initial about:blank
3 // document do not delay showing load errors (and possibly result in a
4 // crash at docShell destruction) for failed document loads.
6 const { PromiseTestUtils } = ChromeUtils.importESModule(
7   "resource://testing-common/PromiseTestUtils.sys.mjs"
8 );
9 PromiseTestUtils.allowMatchingRejectionsGlobally(/undefined/);
11 const { XPCShellContentUtils } = ChromeUtils.importESModule(
12   "resource://testing-common/XPCShellContentUtils.sys.mjs"
15 XPCShellContentUtils.init(this);
17 const server = XPCShellContentUtils.createHttpServer({
18   hosts: ["example.com"],
19 });
21 // Registers a URL with the HTTP server which will not return a response
22 // until we're ready to.
23 function registerSlowPage(path) {
24   let result = {
25     url: `http://example.com/${path}`,
26   };
28   let finishedPromise = new Promise(resolve => {
29     result.finish = resolve;
30   });
32   server.registerPathHandler(`/${path}`, async (request, response) => {
33     response.processAsync();
35     response.setHeader("Content-Type", "text/html");
36     response.write("<html><body>Hello.</body></html>");
38     await finishedPromise;
40     response.finish();
41   });
43   return result;
46 let topFrameRequest = registerSlowPage("top.html");
47 let subFrameRequest = registerSlowPage("frame.html");
49 let thunks = new Set();
50 function promiseStateStop(webProgress) {
51   return new Promise(resolve => {
52     let listener = {
53       onStateChange(aWebProgress, request, stateFlags) {
54         if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
55           webProgress.removeProgressListener(listener);
57           thunks.delete(listener);
58           resolve();
59         }
60       },
62       QueryInterface: ChromeUtils.generateQI([
63         "nsIWebProgressListener",
64         "nsISupportsWeakReference",
65       ]),
66     };
68     // Keep the listener alive, since it's stored as a weak reference.
69     thunks.add(listener);
70     webProgress.addProgressListener(
71       listener,
72       Ci.nsIWebProgress.NOTIFY_STATE_NETWORK
73     );
74   });
77 async function runTest(waitForErrorPage) {
78   let page = await XPCShellContentUtils.loadContentPage("about:blank");
80   // Watch for the HTTP request for the top frame so that we can cancel
81   // it with an error.
82   let requestPromise = TestUtils.topicObserved(
83     "http-on-modify-request",
84     subject => subject.QueryInterface(Ci.nsIRequest).name == topFrameRequest.url
85   );
87   await page.spawn(
88     [topFrameRequest.url, subFrameRequest.url],
89     function (topFrameUrl, subFrameRequestUrl) {
90       // Create a frame with a source URL which will not return a response
91       // before we cancel it with an error.
92       let doc = this.content.document;
93       let frame = doc.createElement("iframe");
94       frame.src = topFrameUrl;
95       doc.body.appendChild(frame);
97       // Create a subframe in the initial about:blank document for the above
98       // frame which will not return a response before we cancel the
99       // document request.
100       let frameDoc = frame.contentDocument;
101       let subframe = frameDoc.createElement("iframe");
102       subframe.src = subFrameRequestUrl;
103       frameDoc.body.appendChild(subframe);
104     }
105   );
107   let [req] = await requestPromise;
109   info("Cancel request for parent frame");
110   req.cancel(Cr.NS_ERROR_PROXY_CONNECTION_REFUSED);
112   // Request cancelation is not synchronous, so wait for the STATE_STOP
113   // event to fire.
114   await promiseStateStop(page.browsingContext.webProgress);
116   // And make a trip through the event loop to give the DocLoader a
117   // chance to update its state.
118   await new Promise(executeSoon);
120   if (waitForErrorPage) {
121     // Make sure that canceling the request with an error code actually
122     // shows an error page without waiting for a subframe response.
123     await TestUtils.waitForCondition(() =>
124       page.browsingContext.children[0]?.currentWindowGlobal?.documentURI?.spec.startsWith(
125         "about:neterror?"
126       )
127     );
128   }
130   await page.close();
133 add_task(async function testRemoveFrameImmediately() {
134   await runTest(false);
137 add_task(async function testRemoveFrameAfterErrorPage() {
138   await runTest(true);
141 add_task(async function () {
142   // Allow the document requests for the frames to complete.
143   topFrameRequest.finish();
144   subFrameRequest.finish();