Skip to main content

Create a groovy console and bind to selenium

Required groovy files

In the previous posting we defined the pom file that we need for our build environment. Now we will setup some groovy files to get selenium and groovy running interactively.

ConsoleWaiter.groovy

The idea of Groovy Console I found on some other sides. Honour goes for instance too: http://josefbetancourt.wordpress.com/tag/eclipse-2/ I copied some code of this, and put it under src/test/groovy/com/jankester/selenium/test/utils:
package com.jankester.selenium.test.utils

/**
 * File:  ConsoleWaiter.groovy
 */

import groovy.lang.Binding;
import groovy.ui.Console;

/**
 * Provides a wrapper for the console.
 *
 * Based on source by John Green
 * Adapted from:  http://www.oehive.org/files/ConsoleWaiter.groovy
 * Released under the Eclipse Public License
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * I added methods to allow use from Java.
 *
 * The run() method launches the console and causes this thread
 * to sleep until the console's window is closed.
 * Allows easy interaction with the objects alive at a given
 * point in an application's execution, like in a debugger
 * session.
 *
 * Example 1:
 * new ConsoleWaiter().run()
 *
* * Example 2:
 * def waiter = new ConsoleWaiter()
 * waiter.console.setVariable("node", node)
 * waiter.run()
 *
*/ class ConsoleWaiter { Console console Object source boolean done = false; /** */ public ConsoleWaiter(Console inConsole){ this.console = inConsole } /** */ public ConsoleWaiter(Object source){ console = new Console(getClass().classLoader, new Binding()) this.source = source console.setVariable("source", source) } /** */ public void setVar(String key, Object value){ console.setVariable(key, value) } /** */ public void setVar(String key, List values){ console.setVariable(key, values) } /** */ public void setVar(String key, Object[] values){ console.setVariable(key, values) } /** */ public void run() { console.run() // I'm a little surprised that this exit() can be private. console.frame.windowClosing = this.&exit console.frame.windowClosed = this.&exit while (!done) { sleep 1000 } } /** */ public boolean isDone(){ return done; } /** */ public void exit(EventObject evt = null) { done = true } /** */ public Console getConsole(){ return console; } }
The Groovy console is supposed to get started by my main program, and blocks the thread of my main program. Only when you close the Groovy Console, the main program will continue (and exit). You can give the groovy console a binding, and thus put it in direct contact with any context you set up before. In our case, we want to have selenium driver loaded in our context.

Selenium setup

The groovy class to start our selenium, uses following code:
package com.jankester.selenium.test

import java.io.File
import java.util.logging.Level

import org.apache.log4j.LogManager
import org.apache.log4j.Logger
import org.openqa.selenium.By
import org.openqa.selenium.WebDriver
import org.openqa.selenium.chrome.ChromeDriverService
import org.openqa.selenium.firefox.FirefoxDriver
import org.openqa.selenium.firefox.FirefoxProfile
import org.openqa.selenium.ie.InternetExplorerDriver
import org.openqa.selenium.logging.LoggingPreferences
import org.openqa.selenium.remote.DesiredCapabilities
import org.openqa.selenium.remote.RemoteWebDriver
import org.openqa.selenium.logging.LogType
import org.openqa.selenium.remote.CapabilityType
import com.opera.core.systems.OperaDriver


class WebDriverSetup {

 private static WebDriverSetup setup;
 protected static Logger logger = LogManager.getLogger(WebDriverSetup.class);
 protected WebDriver driver;
 protected Utils utils;
 protected String startUrl;
 protected String username;
 protected String password;

 public static WebDriverSetup getInstance() {
  if (setup == null) {
   setup = new WebDriverSetup();
  }
 }
 
 private WebDriverSetup() {
  startUrl = PropertyHolder.testProperties.getProperty("StartUrl");
  String browser = PropertyHolder.testProperties.getProperty("BrowserType");
  username = PropertyHolder.testProperties.getProperty("LoginUserName");
  password = PropertyHolder.testProperties.getProperty("LoginPassword");

  if (browser.equalsIgnoreCase("*firefox")) {
   driver = getFirefoxDriver();
   logger.info("Started firefox driver");
  }
  else if (browser.equalsIgnoreCase("*iexplore")) {
   driver = getIEDriver();
   logger.info("Started internetexplorer driver");
  }
  else if (browser.equalsIgnoreCase("*googlechrome")) {
   driver = getGoogleChromeDriver();
   logger.info("Started Googlechrome driver");
  }
  else if (browser.equalsIgnoreCase("*opera")) {
   driver = new OperaDriver();
   logger.info("Started opera driver");
  }

  /*  open the url */
  logger.info("Connecting to starturl: " + startUrl);
  driver.get(startUrl);
  logger.info("Connected to starturl");
  
 }

 private WebDriver getFirefoxDriver() {
  logger.info("Starting firefox driver");
  DesiredCapabilities caps = DesiredCapabilities.firefox(); 
  FirefoxProfile firefoxProfile = new FirefoxProfile();
  caps.setCapability(FirefoxDriver.PROFILE, firefoxProfile);
  
  //use setting in log4j to switch on logging of firefox driver
  Logger log4jLogger = LogManager.getLogger("org.openqa");
  if (log4jLogger.isInfoEnabled()) {
   LoggingPreferences logs = new LoggingPreferences(); 
   logs.enable(LogType.DRIVER, Level.INFO); 
   caps.setCapability(CapabilityType.LOGGING_PREFS, logs); 
   logger.info("Logging of firefox driver is enabled");
   String userDir = System.getProperty("user.dir"); 
   System.setProperty("webdriver.firefox.logfile", "target/firefox-console.log");
   System.setProperty("webdriver.log.file","${userDir}/target/firefox-driver.log");
  }

  WebDriver ffDriver = new FirefoxDriver(caps);
  return ffDriver;
 }



 private WebDriver getIEDriver() {
  logger.info("Starting iexplorer driver");
  DesiredCapabilities ieCapabilities = DesiredCapabilities.internetExplorer();
  ieCapabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
  InternetExplorerDriver ieDriver = new InternetExplorerDriver(ieCapabilities);
  return ieDriver;

 }

 private WebDriver getGoogleChromeDriver() {
  logger.info("Starting googlechrome driver");
  DesiredCapabilities chromeCapabilities = DesiredCapabilities.chrome();

  System.setProperty("webdriver.chrome.driver", PropertyHolder.testProperties.("ChromedriverPath"));

  ChromeDriverService service = new ChromeDriverService.Builder()
    .usingChromeDriverExecutable(new File(PropertyHolder.testProperties.("ChromedriverPath")))
    .usingAnyFreePort().build();

  logger.info("Starting chrome driver service..");
  service.start();

  WebDriver driverGC = new RemoteWebDriver(service.getUrl(),chromeCapabilities);
  return driverGC;
 }
 
 public void close() {
  logger.info("Closing driver now");
  driver.close();
 }
}

PropertyHolder

In our pom profiles we define several variables. They get merged into src/test/resources/test.properties. Our groovy classes need these variables, and get access to these variables over a PropertyHolder class:
package com.jankester.selenium.test

class PropertyHolder {

 public static Properties testProperties = new Properties(); 
 
 static {
  InputStream is = PropertyHolder.class.classLoader.getResourceAsStream('test.properties');
  testProperties.load(is);
        //def theConfig = new ConfigSlurper().parse(is.getText());
 }
}

RunSeleniumConsole

Now the final part is about starting the main program. You can do this with:
package com.jankester.selenium.test

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.By as By;
import com.jankester.selenium.test.SeleniumConstants as SeleniumConstants;

import com.jankester.selenium.test.utils.ConsoleWaiter;
import com.jankester.selenium.test.utils.Utils;

class RunSeleniumConsole {

 private static Logger logger = LogManager.getLogger(RunSeleniumConsole.class);


 static main(args) {
  logger.info("Starting selenium session with console");
  WebDriverSetup setup = WebDriverSetup.getInstance();

  //set bindings
  Actions actions = new Actions(setup.driver);

  ConsoleWaiter waiter = new ConsoleWaiter(setup);

  logger.info("Setting bindings for driver,actions,utils,logger");
  waiter.setVar("driver", setup.driver);
  waiter.setVar("actions",actions);
  waiter.setVar("logger",logger);
  waiter.setVar("startUrl",setup.startUrl);
  waiter.setVar("By",By);
  waiter.run();
  
  setup.close();
 }
}

With this all in plae, you should be able to run your first console with: mvn clean test -P firefox,development,run-console You may get a failure for log4j initialisation. But you can just add a log4j.xml to your src/main/resources folder, and that problem should be solved. Good Luck!

Next

Remaining topics are:
  • create your own utils directory
  • examples
  • save your groovy scripts
  • replay your saved groovy scripts as junit tests
  • add firebug xpi during startup
At the end of the series I will also add complete source code example.

Comments

Unknown said…
Hi Jan, Thank you very much for this. I have successfully implemented a java project and ran by the console using import. Here what problem I face is code change in the project's methods is not reflected. I need for a re-run to launch the console to get the code changes. Kindly help on this.

For example, when I run using console I get an exception then I change in the project which I have added to selenium-groovy-console public project. Now I do not get the changed method invoked. class files are not reloaded.

Popular posts from this blog

SSL handshake failed: Secure connection truncated

Got this problem on Ubuntu 9.10 and 10.10. svn co --username=xx https:/yy zz “SSL handshake failed: Secure connection truncated” According to this link bug-ubuntu The solution is: sudo apt-get install libneon27 cd /usr/lib/ sudo rm libneon-gnutls.so.27 sudo ln -s /usr/lib/libneon.so.27 libneon-gnutls.so.27

Junit4 running parallel junit classes

To run junit testcases parallel, you can create your own class to run junit with: Add this tag to your class declaration. @RunWith(Parallelized.class) Implementation of this class looks like: package mypackage; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.junit.runners.Parameterized; import org.junit.runners.model.RunnerScheduler; public class Parallelized extends Parameterized {         private static class ThreadPoolScheduler implements RunnerScheduler     {         private ExecutorService executor;                 public ThreadPoolScheduler()         {             String threads = System.getProperty("junit.parallel.threads", "16");    ...