JBehave with Selenium is able to create screenshots when scenario fails. It is very useful feature when you want to see what was happening on the screen when the test failed. Unfortunately JBehave Web documentation is not very helpful at this point.
The trader-runner-webdriver project from the examples in JBehave Web source code contains example of the solution. The screenshot feature is implemented through WebDriverScreenshotOnFailure
class. This class just needs to be added to the step candidate list.
JBehave also supports linking these screenshots into the HTML report. Example is available in the tutorial project. This behaviour can be added to above trader-runner-webdriver example project very easily. There is a class WebDriverHtmlOutput
in the JBehave/Selenium module which extends HtmlOutput. All you need to do is to replace HTML format in you format configuration with WebDriverHtmlOutput.WEB_DRIVER_HTML
format. Modify TraderWebStories.configuration()
- change:
.withFormats(CONSOLE, TXT, HTML, XML));
to
.withFormats(CONSOLE, TXT, WebDriverHtmlOutput.WEB_DRIVER_HTML, XML));
This solution is not perfect though. WebDriverScreenshotOnFailure class does not play well with stories executed with "doIgnoreFailureInStories(true)" flag (this setting is useful when you want to have report generated even when scenarios fail). There is a bug in JBehave (3.4.5). In case multiple scenarios in story fail, all screenshots are saved to the same file, i.e. rewriting each other. If you then try to open these screenshots from the HTML report first link opens but it will show a screenshot for the last failure, rest of the links won't work at all.
Trader-runner-webdriver project can be simply modified to show this bug:
- Add this method to TraderWebStories class:
@Before public void init(){ configuredEmbedder().embedderControls() .doGenerateViewAfterStories(true) .doIgnoreFailureInStories(true) .doIgnoreFailureInView(false); }
- Introduce failures to existing stories - add exception throwing to
TraderWebSteps.stepsFound(List
.stepsOrMethods)
Run test and check report for the screenshot problems. You will see the the second link does not work at all and only single screenshot file exists.
There is a workaround for this problem:
- As
WebDriverScreenshotOnFailure
class does not provide required screenshots it is removed. Modify methodTraderWebStories.stepsFactory()
- removeWebDriverScreenshotOnFailure
class from the list of step candidates. - Create a new class
ScreenshootingHtmlOutput
which extends classWebDriverHtmlOutput
. This class will extend failure handling with screenshot generation by callingWebDriverScreenshotOnFailure
:public class ScreenshootingHtmlOutput extends WebDriverHtmlOutput { private WebDriverScreenshotOnFailure screenshotMaker; public ScreenshootingHtmlOutput(PrintStream output, StoryReporterBuilder reporterBuilder, WebDriverProvider webDriverProvider) { super(output, reporterBuilder.keywords()); screenshotMaker = new WebDriverScreenshotOnFailure( webDriverProvider); } @Override public void failed(String step, Throwable storyFailure) { super.failed(step, storyFailure); try { UUIDExceptionWrapper uuidWrappedFailure = (UUIDExceptionWrapper) storyFailure; screenshotMaker.afterScenarioFailure(uuidWrappedFailure); } catch (Exception e) { System.out.println("Screenshot failed"); } } }
- Then a new format class is needed:
public class ScreenshootingHtmlFormat extends Format{ private WebDriverProvider webDriverProvider; public ScreenshootingHtmlFormat(WebDriverProvider webDriverProvider) { super("HTML"); this.webDriverProvider = webDriverProvider; } @Override public StoryReporter createStoryReporter( FilePrintStreamFactory factory, StoryReporterBuilder builder) { factory.useConfiguration( builder.fileConfiguration("html")); return new ScreenshootingHtmlOutput(factory.createPrintStream(), builder, webDriverProvider) .doReportFailureTrace(builder.reportFailureTrace()) .doCompressFailureTrace(builder.compressFailureTrace()); } }
- And finally you need to modify the
TraderWebStories
class. Add field:private Format screenshootingFormat = new ScreenshootingHtmlFormat(driverProvider);
and replaceWebDriverHtmlOutput.WEB_DRIVER_HTML
withscreenshootingFormat
so you get:.withFormats(CONSOLE, TXT, screenshootingFormat, XML));
It is not very nice solution but it works. Hopefully the JBehave bug is going to be fixed soon and this nasty workaround won't be needed any more.