"""Minimal(?) test case for qwebengine userscripts not running on all pages. As reported here at [1][] sometimes userscripts don't run when they should. While that issue title implies the problem happens when using window.open() I have seen (presumably) the same issue occur during regular browsing (Qt 5.9) and particularly on long lived tabs that get manually refreshed regularly. What this test case does is 1. allow javascript to open new windows 2. register a userscript that sets document.title on window idle 3. opens a new tab to a page which opens two new tabs via window.open() 4. checks that all the tabs have had their title set by the userscript 5. close the two child tabs and repeat the two previous steps The repetition seems to be necessary to trigger the buggy behaviour on 5.9 but not on 5.10. I did manage to "fix" the behaviour in 5.9 by setting `UserResourceController::renderViewDestroyed` to NOT clear `m_scripts` if it is called with `globalScriptsIndex` but I don't know enough about how the UserResourceController is supposed to work to say whether that is a reasonable solution or not. For instance it looks like renderViewDestroyed is only called from OnDestruct so why is `render_view()` returning NULL there? [1]: https://github.com/qutebrowser/qutebrowser/issues/3497 """ import sys from urllib.parse import quote from PyQt5.QtWebEngineWidgets import QWebEngineScript, QWebEngineProfile, QWebEngineSettings, QWebEngineView, QWebEnginePage from PyQt5.QtCore import QUrl, QTimer from PyQt5.QtWidgets import QApplication # Something something nvidia propietary diversions if sys.platform.startswith('linux'): import ctypes, ctypes.util ctypes.CDLL(ctypes.util.find_library("GL"), mode=ctypes.RTLD_GLOBAL) def to_data_url(html): return "data:text/html,{}".format(quote(html)) newpage = """

Test Page runscripthere

""" startpage = """ Click here """.format(newpage=to_data_url(newpage)) app = QApplication([]) default_profile = QWebEngineProfile.defaultProfile() default_profile.settings().setAttribute( QWebEngineSettings.JavascriptCanOpenWindows, True) default_profile.settings().setAttribute( QWebEngineSettings.JavascriptEnabled, True) # Userscript to set the title after document load script = QWebEngineScript() script.setInjectionPoint(QWebEngineScript.Deferred) script.setSourceCode("console.log('It runs:'+window.location); document.title = 'userscripts work';") default_profile.scripts().insert(script) tabs = [] run = 1 def on_run_finished(): global tabs, run #for idx, tab in enumerate(tabs): # print(idx, tab.title()) if [tab for tab in tabs if tab.title() != "userscripts work"]: print("run {}: userscripts didn't run on all tabs".format(run), flush=True) else: print("run {}: userscripts ran on all tabs".format(run), flush=True) if run == 1: run += 1 for tab in tabs[1:]: tab.deleteLater() tabs = [tabs[0]] tabs[0].reload() elif run == 2: app.exit(0) class mywebview(QWebEngineView): finished = False def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.loadFinished.connect(self.on_load_finished) def createWindow(self, wintype): tab = mywebview(parent=self) tab.show() tabs.append(tab) return tab def on_load_finished(self, okay): self.finished = True #if 'Test Page runscripthere' in self.title(): # print('child tab finished') if not [tab for tab in tabs if not tab.finished]: # If all tabs are finished loading then trigger checking # their state. # The small timeout is just to make sure the deferred # scripts have a chance to run. QTimer.singleShot(100, on_run_finished) view = mywebview() view.show() tabs.append(view) view.load(QUrl(to_data_url(startpage))) ret = app.exec() # Sometimes the last line of output from on_run_finished gets eated. print("") sys.exit(ret)