Repository: electron/electron (language: cpp)

Issue:
[Bug]: When `window.webContents.navigationHistory.goBack()` is called, the title set by the HTML's `<title>` tag will override the title set by `window.setTitle()`.
### Preflight Checklist

- [x] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
- [x] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
- [x] I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a bug report that matches the one I want to file, without success.

### Electron Version

32.0.1

### What operating system(s) are you using?

Windows

### Operating System Version

Windows 11	23H2	22631.4169	Windows Feature Experience Pack 1000.22700.1034.0

### What arch are you using?

x64

### Last Known Working Electron version

_No response_

### Expected Behavior

```
const window = new BrowserWindow();
window.setTitle('myTitle');
// After a route change in my HTML file, execute:
window.webContents.navigationHistory.goBack();
// => The title of the window should not be overridden by the HTML's title when `goBack()` is called.
```

### Actual Behavior

```
const window = new BrowserWindow();
window.setTitle('myTitle');
// After a route change in my HTML file, execute:
window.webContents.navigationHistory.goBack();
// => At this point, the title of the window is no longer 'myTitle', but the content of the title tag in the HTML file.
```

### Testcase Gist URL

_No response_

### Additional Information

The front-end uses Vue.js + Vue-Router


Discussion / hints:
<!-- blocked/need-repro -->

Hello @an78mK89fy. Thanks for reporting this and helping to make Electron better!

Would it be possible for you to make a standalone testcase with only the code necessary to reproduce the issue? For example, [Electron Fiddle](https://www.electronjs.org/fiddle) is a great tool for making small test cases and makes it easy to publish your test case to a [gist](https://gist.github.com) that Electron maintainers can use.

Stand-alone test cases make fixing issues go more smoothly: it ensure everyone's looking at the same issue, it removes all unnecessary variables from the equation, and it can also provide the basis for automated regression tests.

Now adding the https://github.com/electron/electron/labels/blocked%2Fneed-repro label for this reason. After you make a test case, please link to it in a followup comment. This issue will be closed in 10 days if the above is not addressed.
Please provide a title for your issue.
> Hello [@an78mK89fy](https://github.com/an78mK89fy). Thanks for reporting this and helping to make Electron better!
> 
> Would it be possible for you to make a standalone testcase with only the code necessary to reproduce the issue? For example, [Electron Fiddle](https://www.electronjs.org/fiddle) is a great tool for making small test cases and makes it easy to publish your test case to a [gist](https://gist.github.com) that Electron maintainers can use.
> 
> Stand-alone test cases make fixing issues go more smoothly: it ensure everyone's looking at the same issue, it removes all unnecessary variables from the equation, and it can also provide the basis for automated regression tests.
> 
> Now adding the [ blocked/need-repro](https://github.com/electron/electron/labels/blocked%2Fneed-repro) Needs a test case to reproduce the bug label for this reason. After you make a test case, please link to it in a followup comment. This issue will be closed in 10 days if the above is not addressed.



> Hello [@an78mK89fy](https://github.com/an78mK89fy). Thanks for reporting this and helping to make Electron better!
> 
> Would it be possible for you to make a standalone testcase with only the code necessary to reproduce the issue? For example, [Electron Fiddle](https://www.electronjs.org/fiddle) is a great tool for making small test cases and makes it easy to publish your test case to a [gist](https://gist.github.com) that Electron maintainers can use.
> 
> Stand-alone test cases make fixing issues go more smoothly: it ensure everyone's looking at the same issue, it removes all unnecessary variables from the equation, and it can also provide the basis for automated regression tests.
> 
> Now adding the [ blocked/need-repro](https://github.com/electron/electron/labels/blocked%2Fneed-repro) Needs a test case to reproduce the bug label for this reason. After you make a test case, please link to it in a followup comment. This issue will be closed in 10 days if the above is not addressed.

example:
https://github.com/an78mK89fy/electron-nhgoBackTitleBug.git

@an78mK89fy this repro still includes Vite - we need a repro that demonstrates this is an issue with Electron, which is made more difficult when the app is rife with third-party dependencies.
> [@an78mK89fy](https://github.com/an78mK89fy) this repro still includes Vite - we need a repro that demonstrates this is an issue with Electron, which is made more difficult when the app is rife with third-party dependencies.

https://github.com/an78mK89fy/electron-nhgoBackTitleBug.git
is update
Confirmed on v33.0.1 using this Fiddle gist: https://gist.github.com/f356a50a0dad57d13f13a48919b05709

Fix patch:
diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc
index 53a24ac6f5943..c01e3c5fda2aa 100644
--- a/shell/browser/api/electron_api_web_contents.cc
+++ b/shell/browser/api/electron_api_web_contents.cc
@@ -2057,6 +2057,17 @@ void WebContents::DidFinishNavigation(
       if (is_main_frame) {
         Emit("did-navigate", url, http_response_code, http_status_text);
       }
+
+      content::NavigationEntry* entry = navigation_handle->GetNavigationEntry();
+
+      // This check is needed due to an issue in Chromium
+      // Upstream is open to patching:
+      // https://bugs.chromium.org/p/chromium/issues/detail?id=1178663
+      // If a history entry has been made and the forward/back call has been
+      // made, proceed with setting the new title
+      if (entry &&
+          (entry->GetTransitionType() & ui::PAGE_TRANSITION_FORWARD_BACK))
+        WebContents::TitleWasSet(entry);
     }
     if (is_guest())
       Emit("load-commit", url, is_main_frame);
@@ -2077,15 +2088,6 @@ void WebContents::DidFinishNavigation(
            frame_process_id, frame_routing_id);
     }
   }
-  content::NavigationEntry* entry = navigation_handle->GetNavigationEntry();
-
-  // This check is needed due to an issue in Chromium
-  // Check the Chromium issue to keep updated:
-  // https://bugs.chromium.org/p/chromium/issues/detail?id=1178663
-  // If a history entry has been made and the forward/back call has been made,
-  // proceed with setting the new title
-  if (entry && (entry->GetTransitionType() & ui::PAGE_TRANSITION_FORWARD_BACK))
-    WebContents::TitleWasSet(entry);
 }
 
 void WebContents::TitleWasSet(content::NavigationEntry* entry) {
diff --git a/spec/api-web-contents-spec.ts b/spec/api-web-contents-spec.ts
index aa2c7d5297453..3f529c118d2e3 100644
--- a/spec/api-web-contents-spec.ts
+++ b/spec/api-web-contents-spec.ts
@@ -631,6 +631,17 @@ describe('webContents module', () => {
         w.webContents.navigationHistory.goBack();
         expect(w.webContents.navigationHistory.getActiveIndex()).to.equal(0);
       });
+
+      it('should have the same window title if navigating back within the page', async () => {
+        const title = 'Test';
+        w.webContents.on('did-finish-load', () => {
+          w.setTitle(title);
+          w.loadURL(`file://${fixturesPath}/pages/navigation-history-anchor-in-page.html#next`);
+        });
+        await w.loadURL(`file://${fixturesPath}/pages/navigation-history-anchor-in-page.html`);
+        w.webContents.navigationHistory.goBack();
+        expect(w.getTitle()).to.equal(title);
+      });
     });
 
     describe('navigationHistory.canGoForward and navigationHistory.goForward API', () => {
@@ -653,6 +664,16 @@ describe('webContents module', () => {
         w.webContents.navigationHistory.goForward();
         expect(w.webContents.navigationHistory.getActiveIndex()).to.equal(1);
       });
+
+      it('should have the same window title if navigating forward within the page', async () => {
+        const title = 'Test';
+        w.webContents.on('did-finish-load', () => {
+          w.setTitle(title);
+          w.loadURL(`file://${fixturesPath}/pages/navigation-history-anchor-in-page.html#next`);
+        });
+        await w.loadURL(`file://${fixturesPath}/pages/navigation-history-anchor-in-page.html`);
+        expect(w.getTitle()).to.equal(title);
+      });
     });
 
     describe('navigationHistory.canGoToOffset(index) and navigationHistory.goToOffset(index) API', () => {
diff --git a/spec/fixtures/pages/navigation-history-anchor-in-page.html b/spec/fixtures/pages/navigation-history-anchor-in-page.html
new file mode 100644
index 0000000000000..03406b81f2a39
--- /dev/null
+++ b/spec/fixtures/pages/navigation-history-anchor-in-page.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+  <span id="next">This is content.</span>
+</body>
+</html>


Test patch: