Repository: electron/electron
Pull request: fix: BrowserWindow add the same BrowserView

#### Description of Change

Closes https://github.com/electron/electron/issues/48057

Fixed addBrowserView to prevent unnecessary removal and re-adding of the same BrowserView.

#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [ ] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [x] tests are [changed or added](https://github.com/electron/electron/blob/main/docs/development/testing.md)
- [ ] relevant API documentation, tutorials, and examples are updated and follow the [documentation style guide](https://github.com/electron/electron/blob/main/docs/development/style-guide.md)
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: Fixed addBrowserView to prevent unnecessary removal and re-adding of the same BrowserView.


Changed files:
filename: lib/browser/api/browser-window.ts
patch: @@ -199,7 +199,14 @@ BrowserWindow.prototype.setBackgroundThrottling = function (allowed: boolean) {
 };
 
 BrowserWindow.prototype.addBrowserView = function (browserView: BrowserView) {
-  if (browserView.ownerWindow) { browserView.ownerWindow.removeBrowserView(browserView); }
+  if (this._browserViews.includes(browserView)) {
+    return;
+  }
+
+  const ownerWindow = browserView.ownerWindow;
+  if (ownerWindow && ownerWindow !== this) {
+    ownerWindow.removeBrowserView(browserView);
+  }
   this.contentView.addChildView(browserView.webContentsView);
   browserView.ownerWindow = this;
   browserView.webContents._setOwnerWindow(this);

filename: spec/api-browser-view-spec.ts
patch: @@ -471,6 +471,39 @@ describe('BrowserView module', () => {
       w.webContents.loadURL('about:blank');
       await once(w.webContents, 'did-finish-load');
     });
+
+    it('document visibilitychange does not change when adding the same BrowserView multiple times', async () => {
+      w.show();
+      expect(w.isVisible()).to.be.true('w is visible');
+
+      const view = new BrowserView();
+      const [width, height] = w.getSize();
+      view.setBounds({ x: 0, y: 0, width, height });
+      w.addBrowserView(view);
+      expect(view.ownerWindow).to.equal(w);
+
+      await view.webContents.loadURL(`data:text/html,
+        <html>
+          <body>
+            <h1>HELLO BROWSERVIEW</h1>
+            <script>
+              document.visibilityChangeCount = 0;
+              document.addEventListener('visibilitychange', () => {
+                document.visibilityChangeCount++;
+              })
+            </script>
+          </body>
+        </html>
+      `);
+      const query = 'document.visibilityChangeCount';
+      const countBefore = await view.webContents.executeJavaScript(query);
+      expect(countBefore).to.equal(0);
+
+      w.addBrowserView(view);
+      w.addBrowserView(view);
+      const countAfter = await view.webContents.executeJavaScript(query);
+      expect(countAfter).to.equal(countBefore);
+    });
   });
 
   describe('BrowserWindow.removeBrowserView()', () => {