This is an automated email from the ASF dual-hosted git repository. benweidig pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 4a38af4394d0d5ac38503b4aceb1f19494808b1f Author: Ben Weidig <[email protected]> AuthorDate: Sun Jul 26 14:31:17 2026 +0200 TAP5-2817: SeleniumTestCase improve error handling during testStartup --- .../apache/tapestry5/test/SeleniumTestCase.java | 216 ++++++++++++--------- 1 file changed, 125 insertions(+), 91 deletions(-) diff --git a/tapestry-test/src/main/java/org/apache/tapestry5/test/SeleniumTestCase.java b/tapestry-test/src/main/java/org/apache/tapestry5/test/SeleniumTestCase.java index fe4dfef27..ec7bc2891 100644 --- a/tapestry-test/src/main/java/org/apache/tapestry5/test/SeleniumTestCase.java +++ b/tapestry-test/src/main/java/org/apache/tapestry5/test/SeleniumTestCase.java @@ -246,128 +246,162 @@ public abstract class SeleniumTestCase extends Assert implements Selenium final Runnable stopWebServer = launchWebServer(container, webAppFolder, contextPath, port, sslPort); - FirefoxDriverManager.firefoxdriver().setup(); + FirefoxDriver driver = null; - DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); - FirefoxOptions options = new FirefoxOptions(desiredCapabilities); - - // TAP5-2819: Run headless on CI - if (Boolean.parseBoolean(System.getProperty("ci", "false"))) + try { - options.addArguments("-headless", "--width=1920", "--height=1080"); - } + FirefoxDriverManager.firefoxdriver().setup(); - File ffProfileTemplate = new File(TapestryRunnerConstants.MODULE_BASE_DIR, "src/test/conf/ff_profile_template"); - // From https://forums.parasoft.com/discussion/5682/using-selenium-with-firefox-snap-ubuntu - String osName = System.getProperty("os.name"); - String snapProfileRoot = osName.contains("Linux") && new File("/snap/firefox").exists() - ? createProfileRootInUserHome() - : null; + DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); + FirefoxOptions options = new FirefoxOptions(desiredCapabilities); - FirefoxProfile profile; - if (ffProfileTemplate.isDirectory()) - { - LOGGER.info("Loading Firefox profile from: {}", ffProfileTemplate); - profile = new FirefoxProfile(ffProfileTemplate); - } - else if (snapProfileRoot != null) - { - File snapSafeDir = new File(snapProfileRoot, "tmp-profile"); - snapSafeDir.mkdirs(); - LOGGER.info("Creating Snap-compatible Firefox profile in: {}", snapSafeDir); + // TAP5-2819: Run headless on CI + if (Boolean.parseBoolean(System.getProperty("ci", "false"))) + { + options.addArguments("-headless", "--width=1920", "--height=1080"); + } - profile = new FirefoxProfile(snapSafeDir); - profile.setPreference("intl.accept_languages", "en,fr,de"); - } - else - { - LOGGER.info("Using default Firefox profile"); - profile = new FirefoxProfile(); - profile.setPreference("intl.accept_languages", "en,fr,de"); - } + File ffProfileTemplate = new File(TapestryRunnerConstants.MODULE_BASE_DIR, "src/test/conf/ff_profile_template"); + // From https://forums.parasoft.com/discussion/5682/using-selenium-with-firefox-snap-ubuntu + String osName = System.getProperty("os.name"); + String snapProfileRoot = osName.contains("Linux") && new File("/snap/firefox").exists() + ? createProfileRootInUserHome() + : null; - options.setProfile(profile); + FirefoxProfile profile; + if (ffProfileTemplate.isDirectory()) + { + LOGGER.info("Loading Firefox profile from: {}", ffProfileTemplate); + profile = new FirefoxProfile(ffProfileTemplate); + } + else if (snapProfileRoot != null) + { + File snapSafeDir = new File(snapProfileRoot, "tmp-profile"); + snapSafeDir.mkdirs(); + LOGGER.info("Creating Snap-compatible Firefox profile in: {}", snapSafeDir); - FirefoxDriver driver = snapProfileRoot != null - ? new FirefoxDriver(createGeckoDriverService(snapProfileRoot), options) - : new FirefoxDriver(options); + profile = new FirefoxProfile(snapSafeDir); + profile.setPreference("intl.accept_languages", "en,fr,de"); + } + else + { + LOGGER.info("Using default Firefox profile"); + profile = new FirefoxProfile(); + profile.setPreference("intl.accept_languages", "en,fr,de"); + } - // Implicit waiting can interfere with WebDriverWait - // driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10L)); + options.setProfile(profile); - CommandProcessor webDriverCommandProcessor = new WebDriverCommandProcessor(baseURL, driver); + driver = snapProfileRoot != null + ? new FirefoxDriver(createGeckoDriverService(snapProfileRoot), options) + : new FirefoxDriver(options); - final ErrorReporterImpl errorReporter = new ErrorReporterImpl(driver, testContext); + // Implicit waiting can interfere with WebDriverWait + // driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10L)); - ErrorReportingCommandProcessor commandProcessor = new ErrorReportingCommandProcessor(webDriverCommandProcessor, - errorReporter); + CommandProcessor webDriverCommandProcessor = new WebDriverCommandProcessor(baseURL, driver); - Selenium selenium = new WebDriverBackedSelenium(driver, baseURL); + final ErrorReporterImpl errorReporter = new ErrorReporterImpl(driver, testContext); - testContext.setAttribute(TapestryTestConstants.BASE_URL_ATTRIBUTE, baseURL); - testContext.setAttribute(TapestryTestConstants.SELENIUM_ATTRIBUTE, selenium); - testContext.setAttribute(TapestryTestConstants.ERROR_REPORTER_ATTRIBUTE, errorReporter); - testContext.setAttribute(TapestryTestConstants.COMMAND_PROCESSOR_ATTRIBUTE, commandProcessor); + ErrorReportingCommandProcessor commandProcessor = new ErrorReportingCommandProcessor(webDriverCommandProcessor, + errorReporter); - testContext.setAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE, new Runnable() - { - @Override - public void run() + Selenium selenium = new WebDriverBackedSelenium(driver, baseURL); + + testContext.setAttribute(TapestryTestConstants.BASE_URL_ATTRIBUTE, baseURL); + testContext.setAttribute(TapestryTestConstants.SELENIUM_ATTRIBUTE, selenium); + testContext.setAttribute(TapestryTestConstants.ERROR_REPORTER_ATTRIBUTE, errorReporter); + testContext.setAttribute(TapestryTestConstants.COMMAND_PROCESSOR_ATTRIBUTE, commandProcessor); + + testContext.setAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE, new Runnable() { - try + @Override + public void run() { - LOGGER.info("Shutting down selenium client ..."); - try { - selenium.stop(); - } catch (RuntimeException e) - { - LOGGER.error("Selenium client shutdown failure.", e); - } + LOGGER.info("Shutting down selenium client ..."); + + try + { + selenium.stop(); + } catch (RuntimeException e) + { + LOGGER.error("Selenium client shutdown failure.", e); + } - LOGGER.info("Shutting down webdriver ..."); + LOGGER.info("Shutting down webdriver ..."); - try - { - if (webDriver != null) { // is sometimes null... but why? - webDriver.quit(); + try + { + if (webDriver != null) { // is sometimes null... but why? + webDriver.quit(); + } + } catch (RuntimeException e) + { + LOGGER.error("Webdriver shutdown failure.", e); } - } catch (RuntimeException e) - { - LOGGER.error("Webdriver shutdown failure.", e); - } - LOGGER.info("Shutting down selenium server ..."); + LOGGER.info("Shutting down selenium server ..."); - LOGGER.info("Shutting web server ..."); + LOGGER.info("Shutting web server ..."); - try - { - stopWebServer.run(); - } catch (RuntimeException e) + try + { + stopWebServer.run(); + } catch (RuntimeException e) + { + LOGGER.error("Web server shutdown failure.", e); + } + + // Output, at the end of the Test, any html capture or screen shots (this makes it much easier + // to locate them at the end of the run; there's such a variance on where they end up based + // on whether the tests are running from inside an IDE or via one of the command line + // builds. + + errorReporter.writeOutputPaths(); + } finally { - LOGGER.error("Web server shutdown failure.", e); + testContext.removeAttribute(TapestryTestConstants.BASE_URL_ATTRIBUTE); + testContext.removeAttribute(TapestryTestConstants.SELENIUM_ATTRIBUTE); + testContext.removeAttribute(TapestryTestConstants.ERROR_REPORTER_ATTRIBUTE); + testContext.removeAttribute(TapestryTestConstants.COMMAND_PROCESSOR_ATTRIBUTE); + testContext.removeAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE); + testContext.removeAttribute(TapestryTestConstants.PAGE_LOAD_TIMEOUT_PARAMETER); + testContext.removeAttribute(TapestryTestConstants.WEBDRIVER_WAIT_TIMEOUT_PARAMETER); } + } + }); + } catch (Exception ex) + { + // Nothing has been stored in the test context yet, so testShutdown() has no way + // of cleaning up after a failure here. Release the browser and the web server now; otherwise + // the port stays bound for the rest of the JVM's life and every later <test> in the suite + // fails with "Failed to bind". - // Output, at the end of the Test, any html capture or screen shots (this makes it much easier - // to locate them at the end of the run; there's such a variance on where they end up based - // on whether the tests are running from inside an IDE or via one of the command line - // builds. + LOGGER.error("Startup of the integration test environment failed; releasing resources.", ex); - errorReporter.writeOutputPaths(); - } finally + if (driver != null) + { + try + { + driver.quit(); + } catch (RuntimeException e) { - testContext.removeAttribute(TapestryTestConstants.BASE_URL_ATTRIBUTE); - testContext.removeAttribute(TapestryTestConstants.SELENIUM_ATTRIBUTE); - testContext.removeAttribute(TapestryTestConstants.ERROR_REPORTER_ATTRIBUTE); - testContext.removeAttribute(TapestryTestConstants.COMMAND_PROCESSOR_ATTRIBUTE); - testContext.removeAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE); - testContext.removeAttribute(TapestryTestConstants.PAGE_LOAD_TIMEOUT_PARAMETER); - testContext.removeAttribute(TapestryTestConstants.WEBDRIVER_WAIT_TIMEOUT_PARAMETER); + LOGGER.error("Webdriver shutdown failure.", e); } } - }); + + try + { + stopWebServer.run(); + } catch (RuntimeException e) + { + LOGGER.error("Web server shutdown failure.", e); + } + + throw ex; + } } private static String createProfileRootInUserHome() {
