Browse Source

fix: promise resolved to early when browser initiated in-page navigation v2 (#39680)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Tomasz Malinowski <[email protected]>
trop[bot] 1 year ago
parent
commit
43d0dcfc27

+ 9 - 2
lib/browser/api/web-contents.ts

@@ -446,6 +446,7 @@ WebContents.prototype.loadURL = function (url, options) {
     };
 
     let navigationStarted = false;
+    let browserInitiatedInPageNavigation = false;
     const navigationListener = (event: Electron.Event, url: string, isSameDocument: boolean, isMainFrame: boolean) => {
       if (isMainFrame) {
         if (navigationStarted && !isSameDocument) {
@@ -460,6 +461,7 @@ WebContents.prototype.loadURL = function (url, options) {
           // as the routing does not leave the document
           return rejectAndCleanup(-3, 'ERR_ABORTED', url);
         }
+        browserInitiatedInPageNavigation = navigationStarted && isSameDocument;
         navigationStarted = true;
       }
     };
@@ -474,17 +476,22 @@ WebContents.prototype.loadURL = function (url, options) {
       // would be more appropriate.
       rejectAndCleanup(-2, 'ERR_FAILED', url);
     };
+    const finishListenerWhenUserInitiatedNavigation = () => {
+      if (!browserInitiatedInPageNavigation) {
+        finishListener();
+      }
+    };
     const removeListeners = () => {
       this.removeListener('did-finish-load', finishListener);
       this.removeListener('did-fail-load', failListener);
-      this.removeListener('did-navigate-in-page', finishListener);
+      this.removeListener('did-navigate-in-page', finishListenerWhenUserInitiatedNavigation);
       this.removeListener('did-start-navigation', navigationListener);
       this.removeListener('did-stop-loading', stopLoadingListener);
       this.removeListener('destroyed', stopLoadingListener);
     };
     this.on('did-finish-load', finishListener);
     this.on('did-fail-load', failListener);
-    this.on('did-navigate-in-page', finishListener);
+    this.on('did-navigate-in-page', finishListenerWhenUserInitiatedNavigation);
     this.on('did-start-navigation', navigationListener);
     this.on('did-stop-loading', stopLoadingListener);
     this.on('destroyed', stopLoadingListener);

+ 10 - 0
spec/api-web-contents-spec.ts

@@ -375,6 +375,16 @@ describe('webContents module', () => {
       await expect(w.loadURL(w.getURL() + '#foo')).to.eventually.be.fulfilled();
     });
 
+    it('resolves after browser initiated navigation', async () => {
+      let finishedLoading = false;
+      w.webContents.on('did-finish-load', function () {
+        finishedLoading = true;
+      });
+
+      await w.loadFile(path.join(fixturesPath, 'pages', 'navigate_in_page_and_wait.html'));
+      expect(finishedLoading).to.be.true();
+    });
+
     it('rejects when failing to load a file URL', async () => {
       await expect(w.loadURL('file:non-existent')).to.eventually.be.rejected()
         .and.have.property('code', 'ERR_FILE_NOT_FOUND');

+ 15 - 0
spec/fixtures/pages/navigate_in_page_and_wait.html

@@ -0,0 +1,15 @@
+<html>
+<header>
+<script type="text/javascript">
+  window.history.replaceState(window.location.href, "Sample Title", window.location.href);
+  // Simulate that we load web page.
+  let d = new Date();
+  const endTime = new Date(d.getTime() + (10 * 1000));
+  while(d.getTime() < endTime) {
+    d = new Date();
+  }
+</script>
+</header>
+<body>
+</body>
+</html>