public class LocalFrameContextView implements ContextView {

    private JFrame frame;
    private JLabel label;
    private int width;
    private int height;
    private int x;
    private int y;

    /**
     * Creates view frame of default size - (380 x 85)
     */
    public LocalFrameContextView() {
        sized(380, 85);
        located(0, 0); // origin by default
    }

    /**
     * Builder-style way to set the preferred size for the frame
     * @param width width
     * @param height height
     * @return The SwingContextView
     */
    public LocalFrameContextView sized(final int width, final int height) {
        this.width = width;
        this.height = height;
        return this;
    }

    /**
     * Builder-style way to set the preferred location for the frame
     * @param x x position on screen
     * @param y y position on screen
     * @return The SwingContextView
     */
    public LocalFrameContextView located(final int x, final int y) {
        this.x = x;
        this.y = y;
        return this;
    }

    public synchronized void show(String scenario, String step) {
        if (frame == null) {
            initialize();
        }
        label.setText("<html><b>" + StringEscapeUtils.escapeHtml4(scenario) + "</b><br/>" + StringEscapeUtils.escapeHtml4(step) + "</html>");
    }

    public synchronized void close() {
        if (frame != null) {
            frame.setVisible(false);
            frame.dispose();
            frame = null;
            label = null;
        }
    }

    private void initialize() {
        frame = new JFrame();
        label = new JLabel();
        frame.setAlwaysOnTop(true);
        frame.setSize(width, height);
        frame.setLocation(x, y);
        frame.setUndecorated(true);
        JPanel panel = new JPanel();
        frame.setContentPane(panel);
        panel.setLayout(new BorderLayout());
        label.setBorder(new EmptyBorder(3,3,3,3));
        panel.add(label, BorderLayout.CENTER);

        MouseInputAdapter mia = new MouseInputAdapter() {
            private Point mousePressedScreenCoords;
            private Point mousePressedCompCoords;
            public void mouseReleased(MouseEvent e) {
                mousePressedScreenCoords = null;
                mousePressedCompCoords = null;
            }
            public void mousePressed(MouseEvent e) {
                mousePressedScreenCoords = e.getLocationOnScreen();
                mousePressedCompCoords = e.getPoint();
            }
            public void mouseDragged(MouseEvent e) {
                Point currCoords = e.getLocationOnScreen();
                x = mousePressedScreenCoords.x + (currCoords.x - mousePressedScreenCoords.x) - mousePressedCompCoords.x;
                y = mousePressedScreenCoords.y + (currCoords.y - mousePressedScreenCoords.y) - mousePressedCompCoords.y;
                frame.setLocation(x,y);
            }
        };

        frame.addMouseListener(mia);
        frame.addMouseMotionListener(mia);

        frame.setVisible(true);
    }

} public class PerStoryWebDriverSteps extends WebDriverSteps {

    public PerStoryWebDriverSteps(WebDriverProvider driverProvider) {
        super(driverProvider);
    }

    @BeforeStory
    public void beforeStory() throws Exception {
        driverProvider.initialize();
    }

    @AfterStory
    public void afterStory() throws Exception {
        driverProvider.end();
    }

} public class SauceContextOutput extends Format {

    private final WebDriverProvider webDriverProvider;
    private final SeleniumContext seleniumContext;
    private final java.util.Map<String, String> storyToSauceUrlMap;

    public SauceContextOutput(WebDriverProvider webDriverProvider, SeleniumContext seleniumContext, java.util.Map<String, String> storyToSauceUrlMap) {
        super("SAUCE_CONTEXT");
        this.webDriverProvider = webDriverProvider;
        this.seleniumContext = seleniumContext;
        this.storyToSauceUrlMap = storyToSauceUrlMap;
    }

    @Override
    public StoryReporter createStoryReporter(FilePrintStreamFactory filePrintStreamFactory,
                                             StoryReporterBuilder storyReporterBuilder) {
        return new SauceContextStoryReporter(webDriverProvider, seleniumContext, storyToSauceUrlMap);
    }

    public static class SauceLabsXRefRoot extends CrossReference.XRefRoot {

        protected final transient Map<String, String> storyToSauceUrlMap;

        public SauceLabsXRefRoot(java.util.Map<String, String> storyToSauceUrlMap) {
            this.storyToSauceUrlMap = storyToSauceUrlMap;
        }

        protected CrossReference.XRefStory createXRefStory(StoryReporterBuilder storyReporterBuilder, Story story, boolean passed, boolean pending) {
            return new SauceLabsXRefStory(story, storyReporterBuilder, passed, pending, storyToSauceUrlMap.get(story.getPath()));
        }
    }

    public static class SauceLabsXRefStory extends CrossReference.XRefStory {

        private String sauceLabsUrl;

        public SauceLabsXRefStory(Story story, StoryReporterBuilder storyReporterBuilder, boolean passed, boolean pending, String sauceLabsUrl) {
            this.sauceLabsUrl = sauceLabsUrl;
        }
    }

    public static class SauceLabsCrossReference extends CrossReference {

        protected final transient Map<String, String> storyToSauceUrlMap;

        public SauceLabsCrossReference(Map<String, String> storyToSauceUrlMap) {
            this.storyToSauceUrlMap = storyToSauceUrlMap;
        }

        @Override
        protected XRefRoot newXRefRoot() {
            return new SauceContextOutput.SauceLabsXRefRoot(storyToSauceUrlMap);
        }

        @Override
        protected void aliasForXRefRoot(XStream xstream) {
            xstream.alias("xref", SauceContextOutput.SauceLabsXRefRoot.class);
        }

        @Override
        protected void aliasForXRefStory(XStream xstream) {
            xstream.alias("story", SauceContextOutput.SauceLabsXRefStory.class);
        }

    }


} public class SauceLabsContextView implements ContextView {

    private WebDriverProvider webDriverProvider;

    public SauceLabsContextView(WebDriverProvider webDriverProvider) {
        this.webDriverProvider = webDriverProvider;
    }

    public void show(String scenario, String step) {
        sendContextMessage(step);
    }

    private void sendContextMessage(String step) {
        try {
            JavascriptExecutor je = (JavascriptExecutor) webDriverProvider.get();
            je.executeScript("sauce:context=Step: " + step);
        } catch (Exception e) {
        }
    }

    public void close() {
    }
} public class SauceWebDriverProvider extends RemoteWebDriverProvider {

    /**
     *
     * @param desiredCapabilities
     */
    public SauceWebDriverProvider(DesiredCapabilities desiredCapabilities) {
        super(desiredCapabilities);
    }

    /**
     * With default capabilities and a selenium version specified in getSeleniumVersion()
     * @see RemoteWebDriverProvider#makeDesiredCapabilities
     * @see SauceWebDriverProvider#getSeleniumVersion()
     */
    public SauceWebDriverProvider() {
        super();
    }

    @Override
    protected DesiredCapabilities makeDesiredCapabilities() {
        DesiredCapabilities dc = super.makeDesiredCapabilities();
        dc.setCapability("name", "JBehave");
        dc.setCapability("selenium-version", getSeleniumVersion());
        dc.setCapability("max-duration", getMaxDuration());
        dc.setCapability("command-timeout", getCommandTimeout());
        dc.setCapability("idle-timeout", getIdleTimeout());
        return dc;
    }

    /**
     * Get selenium version from System property 'selenium.version' if there.
     * User '2.13.0' if property not set.
     * @return Selenium version.
     */
    protected String getSeleniumVersion() {
        String seVersion = System.getProperty("selenium.version");
        if (seVersion == null) {
            return getDefaultSeleniumVersion();
        }
        return seVersion;
    }

    protected String getDefaultSeleniumVersion() {
        return "2.14.0";
    }

    @Override
    public URL createRemoteURL() throws MalformedURLException {
        return new URL("http://" + getSauceCredentials() + "@ondemand.saucelabs.com/wd/hub");
    }

    public static String getSauceUser() {
        String username = System.getProperty("SAUCE_USERNAME");
        if (username == null) {
            throw new UnsupportedOperationException("SAUCE_USERNAME property name variable not specified");
        }
        return username;
    }

    public static String getSauceAccessKey() {
        String access_key = System.getProperty("SAUCE_ACCESS_KEY");
        if (access_key == null) {
            throw new UnsupportedOperationException("SAUCE_ACCESS_KEY property name variable not specified");
        }
        return access_key;
    }

    public static String getSauceCredentials() {
        return getSauceUser() + ":" + getSauceAccessKey();
    }

    /**
     * Max duration of Job on Sauce Labs.  If you don't override this,
     * and have not set a value on system property 'SAUCE_MAX_DURATION',
     * 30 minutes is the default.
     * @return max duration in seconds
     */
    protected String getMaxDuration() {
        String maxDuration = System.getProperty("SAUCE_MAX_DURATION");
        if (maxDuration == null) {
            return "" + (30 * 60);
        }
        return maxDuration;
    }

    /**
     * Command Timeout for an individual command for a Job on Sauce Labs.
     * If you don't override this, and you don't specify a value on
     * a system property 'SAUCE_COMMAND_TIMEOUT', then 300 seconds is the default.
     * @return command timeout in seconds
     */
    protected String getCommandTimeout() {
        String commandTimeout = System.getProperty("SAUCE_COMMAND_TIMEOUT");
        if (commandTimeout == null) {
            return "300";
        }
        return commandTimeout;
    }

    /**
     * Idle Timeout for a Job on Sauce Labs.
     * If you don't override this, and don't specify a value on the system
     * property 'SAUCE_IDLE_TIMEOUT', then 90 seconds is the default.
     * @return command timeout in seconds
     */
    protected String getIdleTimeout() {
        String idleTimeout = System.getProperty("SAUCE_IDLE_TIMEOUT");
        if (idleTimeout == null) {
            return "90";
        }
        return idleTimeout;
    }



} public class SeleniumConfiguration extends Configuration {

    private Selenium selenium;
    private SeleniumContext seleniumContext;
    private WebDriverProvider driverProvider;

    public SeleniumConfiguration() {
    }

    public Selenium selenium() {
        synchronized (this) {
            if (selenium == null) {
                selenium = defaultSelenium();
            }
        }
        return selenium;
    }

    public SeleniumConfiguration useSelenium(Selenium selenium){
        this.selenium = selenium;
        return this;
    }
    
    public SeleniumContext seleniumContext() {
        synchronized (this) {
            if (seleniumContext == null) {
                seleniumContext = new SeleniumContext();
            }
        }
        return seleniumContext;
    }

    public SeleniumConfiguration useSeleniumContext(SeleniumContext seleniumContext) {
        this.seleniumContext = seleniumContext;
        return this;
    }
    
    public WebDriverProvider webDriverProvider() {
        return driverProvider;
    }

    public SeleniumConfiguration useWebDriverProvider(WebDriverProvider webDriverProvider){
        this.driverProvider = webDriverProvider;
        return this;
    }
    
    /**
     * Creates default Selenium instance: {@link DefaultSelenium("localhost",
     * 4444, "*firefox", "http://localhost:8080")}
     * 
     * @return A Selenium instance
     */
    public static Selenium defaultSelenium() {
        return new DefaultSelenium("localhost", 4444, "*firefox", "http://localhost:8080");
    }

    /**
     * Creates default ConditionRunner: {@link JUnitConditionRunner(selenium,
     * 10, 100, 1000)}.
     * 
     * @param selenium
     *            the Selenium instance
     * @return A ConditionRunner
     */
    public static ConditionRunner defaultConditionRunner(Selenium selenium) {
        return new JUnitConditionRunner(selenium, 10, 100, 1000);
    }
    

} public class SeleniumContext {
	
	private ThreadLocal<String> currentScenario = new ThreadLocal<String>();

    public String getCurrentScenario() {
		return currentScenario.get();
	}

	public void setCurrentScenario(String currentScenario) {
		this.currentScenario.set(currentScenario);
	}

} public class SeleniumContextOutput extends org.jbehave.core.reporters.Format {
        private final SeleniumContext seleniumContext;

        public SeleniumContextOutput(SeleniumContext seleniumContext) {
            super("SELENIUM_CONTEXT");
            this.seleniumContext = seleniumContext;
        }

        @Override
        public StoryReporter createStoryReporter(FilePrintStreamFactory filePrintStreamFactory, StoryReporterBuilder storyReporterBuilder) {
            return new SeleniumContextStoryReporter(seleniumContext);
        }
    } public class SeleniumStepMonitor extends DelegatingStepMonitor {

    private final ContextView contextView;
    private final SeleniumContext context;

    public SeleniumStepMonitor(Selenium selenium, SeleniumContext context, StepMonitor delegate) {
        this(new SeleniumContextView(selenium), context, delegate);
    }

    public SeleniumStepMonitor(ContextView contextView, SeleniumContext context, StepMonitor delegate) {
        super(delegate);
        this.contextView = contextView;
        this.context = context;
    }

    public void performing(String step, boolean dryRun) {
        String currentScenario = context.getCurrentScenario();
        contextView.show(currentScenario, step);
        super.performing(step, dryRun);
    }

} public interface WebDriverProvider {
    
    WebDriver get();

    void initialize();

    boolean saveScreenshotTo(String path);

    void end();
}
import org.jbehave.core.annotations.AfterStories;
import org.jbehave.core.annotations.BeforeStory;
import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.embedder.StoryControls;
import org.jbehave.core.failures.FailingUponPendingStep;
import org.jbehave.core.failures.PendingStepStrategy;
import org.jbehave.core.failures.RethrowingFailure;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.io.StoryFinder;
import org.jbehave.core.junit.JUnitStories;
import org.jbehave.core.reporters.CrossReference;
import org.jbehave.core.reporters.Format;
import org.jbehave.core.reporters.StoryReporterBuilder;
import org.jbehave.core.steps.pico.PicoStepsFactory;
import org.jbehave.web.selenium.ContextView;
import org.jbehave.web.selenium.FirefoxWebDriverProvider;
import org.jbehave.web.selenium.LocalFrameContextView;
import org.jbehave.web.selenium.PerStoryWebDriverSteps;
import org.jbehave.web.selenium.RemoteWebDriverProvider;
import org.jbehave.web.selenium.SauceContextOutput;
import org.jbehave.web.selenium.SauceLabsContextView;
import org.jbehave.web.selenium.SauceWebDriverProvider;
import org.jbehave.web.selenium.SeleniumConfiguration;
import org.jbehave.web.selenium.SeleniumContext;
import org.jbehave.web.selenium.SeleniumContextOutput;
import org.jbehave.web.selenium.SeleniumStepMonitor;
import org.jbehave.web.selenium.WebDriverProvider;
import org.jbehave.web.selenium.WebDriverScreenshotOnFailure;
import org.picocontainer.Characteristics;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.PicoBuilder;
import org.picocontainer.behaviors.Storing;
import org.picocontainer.behaviors.ThreadCaching;
import org.picocontainer.classname.ClassLoadingPicoContainer;
import org.picocontainer.classname.ClassName;
import org.picocontainer.classname.DefaultClassLoadingPicoContainer;
import org.picocontainer.injectors.CompositeInjection;
import org.picocontainer.injectors.ConstructorInjection;
import org.picocontainer.injectors.SetterInjection;
import java.util.HashMap;
import java.util.List;
import static java.util.Arrays.asList;
import static org.jbehave.core.io.CodeLocations.codeLocationFromClass;
import static org.jbehave.core.reporters.Format.CONSOLE;
import static org.jbehave.web.selenium.WebDriverHtmlOutput.WEB_DRIVER_HTML;
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
package ${package}.etsy;




public class EtsyDotComStories extends JUnitStories {

    public EtsyDotComStories() {

        PendingStepStrategy pendingStepStrategy = new FailingUponPendingStep();
        CrossReference crossReference = new SauceContextOutput.SauceLabsCrossReference(new HashMap<String, String>())
                .withJsonOnly().withOutputAfterEachStory(true).withPendingStepStrategy(pendingStepStrategy)
                .excludingStoriesWithNoExecutedScenarios(true);

        SeleniumContext seleniumContext = new SeleniumContext();
        WebDriverProvider driverProvider;