From 3cfdc67e832a9fb9562c0f1be349520800ddf9d9 Mon Sep 17 00:00:00 2001 From: labkey-tchad Date: Wed, 24 Jun 2026 16:44:45 -0700 Subject: [PATCH] Leave browser windows open after test failures --- src/org/labkey/test/BaseWebDriverTest.java | 30 +++++++++++++++++++--- src/org/labkey/test/TestProperties.java | 5 ++++ test.properties.template | 3 +++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/org/labkey/test/BaseWebDriverTest.java b/src/org/labkey/test/BaseWebDriverTest.java index 9b8d6fdb2d..8799899942 100644 --- a/src/org/labkey/test/BaseWebDriverTest.java +++ b/src/org/labkey/test/BaseWebDriverTest.java @@ -44,9 +44,9 @@ import org.labkey.remoteapi.CommandException; import org.labkey.remoteapi.CommandResponse; import org.labkey.remoteapi.Connection; -import org.labkey.remoteapi.admin.ClearCachesCommand; import org.labkey.remoteapi.SimpleGetCommand; import org.labkey.remoteapi.SimplePostCommand; +import org.labkey.remoteapi.admin.ClearCachesCommand; import org.labkey.remoteapi.collections.CaseInsensitiveHashMap; import org.labkey.remoteapi.query.ContainerFilter; import org.labkey.remoteapi.query.Filter; @@ -2929,17 +2929,41 @@ private void tearDown(boolean closeOldBrowser) } finally { - clear(); + clear(closeOldBrowser); } } private void clear() { - if (getDriverService() != null && getDriverService().isRunning()) + clear(true); + } + + private void clear(boolean closedOldBrowser) + { + if (getDriverService() != null && getDriverService().isRunning() && !shouldLeaveDriverServiceRunning(closedOldBrowser)) getDriverService().stop(); // Don't clear _downloadDir. Cleanup steps might still need it after tearDown _driverAndService = new ImmutablePair<>(null, null); } + + /** + * Starting with Geckodriver v0.37.0, shutting down the driver service also shuts down the browser. + * We need to leave the FirefoxDriverService running after test failures to allow manual inspection of the + * browser state. + * We can remove this if they add a 'detach' flag to Geckodriver, similar to the one in Chromedriver. + * https://github.com/mozilla/geckodriver/issues/2247 + * https://bugzilla.mozilla.org/show_bug.cgi?id=2046321 + * + * @param closedOldBrowser Indicates that WebDriver was closed + * @return true if the DriverService should be left running + */ + private boolean shouldLeaveDriverServiceRunning(boolean closedOldBrowser) + { + return !closedOldBrowser // Don't leave DriverService running if browser was closed + && BrowserType.FIREFOX.matchesDriver(getWebDriver()) + && TestProperties.allowZombieGeckodriver() + && !TestProperties.isTestRunningOnTeamCity(); + } } private static class CspCheckPageLoadListener implements PageLoadListener diff --git a/src/org/labkey/test/TestProperties.java b/src/org/labkey/test/TestProperties.java index 81cf829a8a..2349c1bf36 100644 --- a/src/org/labkey/test/TestProperties.java +++ b/src/org/labkey/test/TestProperties.java @@ -183,6 +183,11 @@ public static boolean isNewWebDriverForEachTest() return !getBooleanProperty("selenium.reuseWebDriver", false); } + public static boolean allowZombieGeckodriver() + { + return getBooleanProperty("webtest.allowZombieGeckodriver", false); + } + public static boolean isViewCheckSkipped() { return !getBooleanProperty("viewCheck", true); diff --git a/test.properties.template b/test.properties.template index fe7b97bac9..67946aa98e 100644 --- a/test.properties.template +++ b/test.properties.template @@ -68,6 +68,9 @@ cleanOnly=false #webtest.log.level=DEBUG ## Set whether DeferredErrorCollector should fail immediately when errors are encountered (default: false) #webtest.checker.fatal=true +## Set to leave Geckodriver running after test failures (https://github.com/mozilla/geckodriver/issues/2247) +## Note: requires you to manually kill 'geckodriver' processes (`killall geckodriver`) +#webtest.allowZombieGeckodriver=true #==============================================================================