From f320fcf878c6760edcaa9f80ee37a11cf1550290 Mon Sep 17 00:00:00 2001 From: Sam Jones Date: Thu, 21 Jul 2016 17:02:47 -0400 Subject: [PATCH 1/3] Updates error message tested for when test suite fails on a syntax error --- features/halt_on_failure.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/halt_on_failure.feature b/features/halt_on_failure.feature index 3181b9ac0..d9a1bc572 100644 --- a/features/halt_on_failure.feature +++ b/features/halt_on_failure.feature @@ -25,7 +25,7 @@ Feature: halt the build when a spec failure occurs When I run "mvn clean test" Then the build should fail And I should see ".*JavaScript Console Errors:" - And I should see ".*SyntaxError: Parse error" + And I should see ".*SyntaxError:" Scenario: project with no failures From 026a33b859f4fa7ea2cc77fc9e6701a4567118c3 Mon Sep 17 00:00:00 2001 From: Sam Jones Date: Wed, 27 Jul 2016 15:16:58 -0400 Subject: [PATCH 2/3] Adds the ability to define Standard Out reporters through plugin configuration. - Adds `reporters` property to support list of reports. - Adds example project and cucumber test defining custom reporters - Adds documentation for defining custom reporters. - Allows `STANDARD` to be used as a reporter in the list defined reporters. - Defaults to the `STANDARD` reporter if none are provided. - Splits responsibilities out of classes that were growing large and difficult to test. `AbstractJasmineMojo` and `SpecRunnerExecutor`. --- Gemfile.lock | 4 +- features/custom_reporters.feature | 13 +++ .../jasmine/config/JasmineConfiguration.java | 2 + .../searls/jasmine/io/FileUtilsWrapper.java | 16 ++++ .../searls/jasmine/model/JasmineResult.java | 6 +- .../jasmine/mojo/AbstractJasmineMojo.java | 68 ++++++++------- .../jasmine/mojo/ReporterRetriever.java | 46 ++++++++++ .../jasmine/mojo/ResourceRetriever.java | 41 +++++++++ .../github/searls/jasmine/mojo/TestMojo.java | 3 +- .../jasmine/runner/ConsoleErrorChecker.java | 21 +++++ .../jasmine/runner/SpecRunnerExecutor.java | 74 ++++------------ .../jasmine/runner/WebDriverWaiter.java | 43 ++++++++++ src/site/markdown/custom-reporters.md.vm | 53 ++++++++++++ .../jasmine/mojo/AbstractJasmineMojoTest.java | 74 ++++++++-------- .../jasmine/mojo/ReporterRetrieverTest.java | 56 ++++++++++++ .../jasmine/mojo/ResourceRetrieverTest.java | 61 +++++++++++++ .../runner/ConsoleErrorCheckerTest.java | 65 ++++++++++++++ .../runner/SpecRunnerExecutorTest.java | 86 ++++++++----------- .../jasmine/runner/WebDriverWaiterTest.java | 68 +++++++++++++++ .../jasmine-webapp-custom-reporters/pom.xml | 35 ++++++++ .../src/main/javascript/HelloWorld.js | 5 ++ .../src/test/javascript/ExampleTestSpec.js | 11 +++ .../src/test/resources/reporter.js | 7 ++ 23 files changed, 685 insertions(+), 173 deletions(-) create mode 100644 features/custom_reporters.feature create mode 100644 src/main/java/com/github/searls/jasmine/io/FileUtilsWrapper.java create mode 100644 src/main/java/com/github/searls/jasmine/mojo/ReporterRetriever.java create mode 100644 src/main/java/com/github/searls/jasmine/mojo/ResourceRetriever.java create mode 100644 src/main/java/com/github/searls/jasmine/runner/ConsoleErrorChecker.java create mode 100644 src/main/java/com/github/searls/jasmine/runner/WebDriverWaiter.java create mode 100644 src/site/markdown/custom-reporters.md.vm create mode 100644 src/test/java/com/github/searls/jasmine/mojo/ReporterRetrieverTest.java create mode 100644 src/test/java/com/github/searls/jasmine/mojo/ResourceRetrieverTest.java create mode 100644 src/test/java/com/github/searls/jasmine/runner/ConsoleErrorCheckerTest.java create mode 100644 src/test/java/com/github/searls/jasmine/runner/WebDriverWaiterTest.java create mode 100644 src/test/resources/examples/jasmine-webapp-custom-reporters/pom.xml create mode 100644 src/test/resources/examples/jasmine-webapp-custom-reporters/src/main/javascript/HelloWorld.js create mode 100644 src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/javascript/ExampleTestSpec.js create mode 100644 src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/resources/reporter.js diff --git a/Gemfile.lock b/Gemfile.lock index e578b0aa8..b48fe5dbc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -33,7 +33,6 @@ GEM domain_name (~> 0.5) json (1.8.3) mime-types (2.99) - mime-types-data (3.2015.1120) mini_portile (0.6.0) multi_json (1.11.2) multi_test (0.1.2) @@ -89,3 +88,6 @@ DEPENDENCIES relish rspec selenium-webdriver (~> 2.48.1) + +BUNDLED WITH + 1.12.5 diff --git a/features/custom_reporters.feature b/features/custom_reporters.feature new file mode 100644 index 000000000..623fc4399 --- /dev/null +++ b/features/custom_reporters.feature @@ -0,0 +1,13 @@ +Feature: Support custom reporter + + In order to support advanced reporting + I want the maven build to allow a custom reporter + So that values can be stored in tests, and used later by the reporter + + Scenario: project with javascript using a custom reporter + + Given I am currently in the "jasmine-webapp-custom-reporters" project + When I run "mvn clean test -X -e" + Then the build should succeed + And I should see "Results: 2 specs, 0 failures, 0 pending" + And I should see "Hello World" diff --git a/src/main/java/com/github/searls/jasmine/config/JasmineConfiguration.java b/src/main/java/com/github/searls/jasmine/config/JasmineConfiguration.java index 89d9520f6..1ed4da8e8 100644 --- a/src/main/java/com/github/searls/jasmine/config/JasmineConfiguration.java +++ b/src/main/java/com/github/searls/jasmine/config/JasmineConfiguration.java @@ -36,6 +36,8 @@ public interface JasmineConfiguration { File getCustomRunnerConfiguration(); + List getReporters(); + int getAutoRefreshInterval(); boolean isCoffeeScriptCompilationEnabled(); diff --git a/src/main/java/com/github/searls/jasmine/io/FileUtilsWrapper.java b/src/main/java/com/github/searls/jasmine/io/FileUtilsWrapper.java new file mode 100644 index 000000000..e2898e05b --- /dev/null +++ b/src/main/java/com/github/searls/jasmine/io/FileUtilsWrapper.java @@ -0,0 +1,16 @@ +package com.github.searls.jasmine.io; + +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; + +public class FileUtilsWrapper { + public String readFileToString(final File file) throws IOException { + return FileUtils.readFileToString(file, "UTF-8"); + } + + public void writeStringToFile(final File file, final String contents) throws IOException { + FileUtils.writeStringToFile(file, contents, "UTF-8"); + } +} diff --git a/src/main/java/com/github/searls/jasmine/model/JasmineResult.java b/src/main/java/com/github/searls/jasmine/model/JasmineResult.java index 285174528..d490df8e1 100644 --- a/src/main/java/com/github/searls/jasmine/model/JasmineResult.java +++ b/src/main/java/com/github/searls/jasmine/model/JasmineResult.java @@ -2,7 +2,7 @@ public class JasmineResult { - private String details; + private String details = ""; public String getDescription() { return last(getDetails().split("\n")); @@ -20,6 +20,10 @@ public void setDetails(String details) { this.details = details; } + public void appendDetails(String details) { + this.details += details; + } + private T last(T[] array) { return array[array.length - 1]; } diff --git a/src/main/java/com/github/searls/jasmine/mojo/AbstractJasmineMojo.java b/src/main/java/com/github/searls/jasmine/mojo/AbstractJasmineMojo.java index d40f87e53..bedc1466d 100644 --- a/src/main/java/com/github/searls/jasmine/mojo/AbstractJasmineMojo.java +++ b/src/main/java/com/github/searls/jasmine/mojo/AbstractJasmineMojo.java @@ -13,7 +13,6 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.resource.ResourceManager; -import org.codehaus.plexus.resource.loader.FileResourceLoader; import org.eclipse.jetty.server.Connector; import java.io.File; @@ -23,8 +22,6 @@ public abstract class AbstractJasmineMojo extends AbstractMojo implements JasmineConfiguration { - private static final String ERROR_FILE_DNE = "Invalid value for parameter '%s'. File does not exist: %s"; - // Properties in order of most-to-least interesting for client projects to override /** @@ -102,6 +99,19 @@ public abstract class AbstractJasmineMojo extends AbstractMojo implements Jasmin @Parameter protected String customRunnerConfiguration; + /** + *

Specify a custom reporter to be used to print the test report.

+ *

Example usage:

+ *
+   * <reporters>
+   *   <reporter>${project.basedir}/src/test/resources/myCustomReporter.js</reporter>
+   *   <reporter>STANDARD</reporter>
+   * </reporters>
+   * 
+ */ + @Parameter + protected List reporters = new ArrayList(); + /** * Target directory for files created by the plugin. * @@ -364,20 +374,22 @@ public abstract class AbstractJasmineMojo extends AbstractMojo implements Jasmin protected MavenProject mavenProject; @Component - protected ResourceManager locator; + ResourceManager resourceManager; - protected ScriptSearch sources; - protected ScriptSearch specs; + protected ResourceRetriever resourceRetriever; + protected ReporterRetriever reporterRetriever; protected StringifiesStackTraces stringifiesStackTraces = new StringifiesStackTraces(); + protected ScriptSearch sources; + protected ScriptSearch specs; + private File customRunnerTemplateFile; private File customRunnerConfigurationFile; - + private List reporterFiles = new ArrayList(); @Override public void execute() throws MojoExecutionException, MojoFailureException { - this.loadResources(); this.sources = new ScriptSearch(this.jsSrcDir, this.sourceIncludes, this.sourceExcludes); @@ -458,6 +470,11 @@ public File getCustomRunnerConfiguration() { return this.customRunnerConfigurationFile; } + @Override + public List getReporters() { + return this.reporterFiles; + } + @Override public File getBasedir() { return this.mavenProject.getBasedir(); @@ -496,29 +513,22 @@ protected boolean isSkipTests() { } private void loadResources() throws MojoExecutionException { - this.customRunnerTemplateFile = this.getResourceAsFile("customRunnerTemplate", this.customRunnerTemplate); - this.customRunnerConfigurationFile = this.getResourceAsFile("customRunnerConfiguration", this.customRunnerConfiguration); + this.customRunnerTemplateFile = getResourceRetriever().getResourceAsFile("customRunnerTemplate", this.customRunnerTemplate, this.mavenProject); + this.customRunnerConfigurationFile = getResourceRetriever().getResourceAsFile("customRunnerConfiguration", this.customRunnerConfiguration, this.mavenProject); + this.reporterFiles = getReporterRetriever().retrieveReporters(this.reporters, this.mavenProject); + } + + private ResourceRetriever getResourceRetriever() { + if (resourceRetriever == null) { + resourceRetriever = new ResourceRetriever(resourceManager); + } + return resourceRetriever; } - private File getResourceAsFile(String parameter, String resourceLocation) throws MojoExecutionException { - File file = null; - - if (resourceLocation != null) { - this.locator.addSearchPath("url", ""); - this.locator.addSearchPath(FileResourceLoader.ID, this.mavenProject.getFile().getParentFile().getAbsolutePath()); - - ClassLoader origLoader = Thread.currentThread().getContextClassLoader(); - try { - Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); - try { - file = this.locator.getResourceAsFile(resourceLocation); - } catch (Exception e) { - throw new MojoExecutionException(String.format(ERROR_FILE_DNE, parameter, resourceLocation)); - } - } finally { - Thread.currentThread().setContextClassLoader(origLoader); - } + private ReporterRetriever getReporterRetriever() { + if (reporterRetriever == null) { + reporterRetriever = new ReporterRetriever(getResourceRetriever()); } - return file; + return reporterRetriever; } } diff --git a/src/main/java/com/github/searls/jasmine/mojo/ReporterRetriever.java b/src/main/java/com/github/searls/jasmine/mojo/ReporterRetriever.java new file mode 100644 index 000000000..91ec9c157 --- /dev/null +++ b/src/main/java/com/github/searls/jasmine/mojo/ReporterRetriever.java @@ -0,0 +1,46 @@ +package com.github.searls.jasmine.mojo; + +import com.google.inject.Inject; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class ReporterRetriever { + static final String STANDARD_REPORTER = "/lib/buildReport.js"; + private static final String STANDARD_REPORTER_KEY = "STANDARD"; + + private final ResourceRetriever resourceRetriever; + + @Inject + public ReporterRetriever(final ResourceRetriever resourceRetriever) { + this.resourceRetriever = resourceRetriever; + } + + List retrieveReporters(final List reporters, final MavenProject mavenProject) throws MojoExecutionException { + final List reporterFiles = new ArrayList(); + for (String reporter : reporters) { + if (STANDARD_REPORTER_KEY.equals(reporter)) { + reporterFiles.add(getStandardReporter(mavenProject)); + } else { + reporterFiles.add(getReporter(mavenProject, reporter)); + } + } + + if (reporterFiles.isEmpty()) { + reporterFiles.add(getStandardReporter(mavenProject)); + } + + return reporterFiles; + } + + private File getStandardReporter(final MavenProject mavenProject) throws MojoExecutionException { + return getReporter(mavenProject, STANDARD_REPORTER); + } + + private File getReporter(final MavenProject mavenProject, final String reporter) throws MojoExecutionException { + return resourceRetriever.getResourceAsFile("reporter", reporter, mavenProject); + } +} diff --git a/src/main/java/com/github/searls/jasmine/mojo/ResourceRetriever.java b/src/main/java/com/github/searls/jasmine/mojo/ResourceRetriever.java new file mode 100644 index 000000000..f870e6b5f --- /dev/null +++ b/src/main/java/com/github/searls/jasmine/mojo/ResourceRetriever.java @@ -0,0 +1,41 @@ +package com.github.searls.jasmine.mojo; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.resource.ResourceManager; +import org.codehaus.plexus.resource.loader.FileResourceLoader; + +import java.io.File; + +public class ResourceRetriever { + + private final ResourceManager locator; + + static final String ERROR_FILE_DNE = "Invalid value for parameter '%s'. File does not exist: %s"; + + public ResourceRetriever(final ResourceManager locator) { + this.locator = locator; + } + + File getResourceAsFile(final String parameter, final String resourceLocation, final MavenProject mavenProject) throws MojoExecutionException { + File file = null; + + if (resourceLocation != null) { + locator.addSearchPath("url", ""); + locator.addSearchPath(FileResourceLoader.ID, mavenProject.getFile().getParentFile().getAbsolutePath()); + + ClassLoader origLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); + try { + file = locator.getResourceAsFile(resourceLocation); + } catch (Exception e) { + throw new MojoExecutionException(String.format(ERROR_FILE_DNE, parameter, resourceLocation)); + } + } finally { + Thread.currentThread().setContextClassLoader(origLoader); + } + } + return file; + } +} diff --git a/src/main/java/com/github/searls/jasmine/mojo/TestMojo.java b/src/main/java/com/github/searls/jasmine/mojo/TestMojo.java index cc6de22a6..0cd07eaec 100644 --- a/src/main/java/com/github/searls/jasmine/mojo/TestMojo.java +++ b/src/main/java/com/github/searls/jasmine/mojo/TestMojo.java @@ -241,7 +241,8 @@ private JasmineResult executeSpecs(URL runner) throws Exception { this.timeout, this.debug, this.getLog(), - this.format + this.format, + getReporters() ); return result; } diff --git a/src/main/java/com/github/searls/jasmine/runner/ConsoleErrorChecker.java b/src/main/java/com/github/searls/jasmine/runner/ConsoleErrorChecker.java new file mode 100644 index 000000000..7a329c527 --- /dev/null +++ b/src/main/java/com/github/searls/jasmine/runner/ConsoleErrorChecker.java @@ -0,0 +1,21 @@ +package com.github.searls.jasmine.runner; + +import org.apache.commons.lang3.StringUtils; +import org.apache.maven.plugin.logging.Log; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +class ConsoleErrorChecker { + void checkForConsoleErrors(final WebDriver driver, final Log log) { + final WebElement head = driver.findElement(By.tagName("head")); + if (head != null) { + String jserrors = head.getAttribute("jmp_jserror"); + if (StringUtils.isNotBlank(jserrors)) { + String errors = "JavaScript Console Errors:\n\n * " + jserrors.replaceAll(":!:", "\n * ") + "\n\n"; + log.warn(errors); + throw new RuntimeException("There were javascript console errors.\n\n" + errors); + } + } + } +} diff --git a/src/main/java/com/github/searls/jasmine/runner/SpecRunnerExecutor.java b/src/main/java/com/github/searls/jasmine/runner/SpecRunnerExecutor.java index b2f5238b8..2dfce85d0 100644 --- a/src/main/java/com/github/searls/jasmine/runner/SpecRunnerExecutor.java +++ b/src/main/java/com/github/searls/jasmine/runner/SpecRunnerExecutor.java @@ -1,51 +1,54 @@ package com.github.searls.jasmine.runner; +import com.github.searls.jasmine.io.FileUtilsWrapper; import com.github.searls.jasmine.io.IOUtilsWrapper; import com.github.searls.jasmine.model.JasmineResult; -import com.google.common.base.Predicate; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.StringUtils; import org.apache.maven.plugin.logging.Log; -import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.WebDriverWait; import java.io.File; import java.io.IOException; import java.net.URL; +import java.util.List; public class SpecRunnerExecutor { - public static final String BUILD_REPORT_JS = "/lib/buildReport.js"; public static final String CREATE_JUNIT_XML = "/lib/createJunitXml.js"; private final IOUtilsWrapper ioUtilsWrapper; + private final FileUtilsWrapper fileUtilsWrapper; + private final WebDriverWaiter webDriverWaiter; + private final ConsoleErrorChecker consoleErrorChecker; - public SpecRunnerExecutor(IOUtilsWrapper ioUtilsWrapper) { + public SpecRunnerExecutor(IOUtilsWrapper ioUtilsWrapper, FileUtilsWrapper fileUtilsWrapper, WebDriverWaiter webDriverWaiter, ConsoleErrorChecker consoleErrorChecker) { this.ioUtilsWrapper = ioUtilsWrapper; + this.fileUtilsWrapper = fileUtilsWrapper; + this.webDriverWaiter = webDriverWaiter; + this.consoleErrorChecker = consoleErrorChecker; } public SpecRunnerExecutor() { - this(new IOUtilsWrapper()); + this(new IOUtilsWrapper(), new FileUtilsWrapper(), new WebDriverWaiter(), new ConsoleErrorChecker()); } - public JasmineResult execute(URL runnerUrl, File junitXmlReport, WebDriver driver, int timeout, boolean debug, Log log, String format) { + public JasmineResult execute(URL runnerUrl, File junitXmlReport, WebDriver driver, int timeout, boolean debug, Log log, String format, List reporters) { try { if (!(driver instanceof JavascriptExecutor)) { throw new RuntimeException("The provided web driver can't execute JavaScript: " + driver.getClass()); } JavascriptExecutor executor = (JavascriptExecutor) driver; driver.get(runnerUrl.toString()); - this.waitForRunnerToFinish(driver, timeout, debug, log); + webDriverWaiter.waitForRunnerToFinish(driver, timeout, debug, log); - this.checkForConsoleErrors(driver, log); + consoleErrorChecker.checkForConsoleErrors(driver, log); JasmineResult jasmineResult = new JasmineResult(); - jasmineResult.setDetails(this.buildReport(executor, format)); - FileUtils.writeStringToFile(junitXmlReport, this.buildJunitXmlReport(executor, debug), "UTF-8"); + for (File reporter : reporters) { + jasmineResult.appendDetails(this.buildReport(executor, reporter, format)); + } + fileUtilsWrapper.writeStringToFile(junitXmlReport, this.buildJunitXmlReport(executor, debug)); return jasmineResult; } catch (Exception e) { @@ -59,20 +62,9 @@ public JasmineResult execute(URL runnerUrl, File junitXmlReport, WebDriver drive } } - private void checkForConsoleErrors(WebDriver driver, Log log) { - WebElement head = driver.findElement(By.tagName("head")); - if (head != null) { - String jserrors = head.getAttribute("jmp_jserror"); - if (StringUtils.isNotBlank(jserrors)) { - log.warn("JavaScript Console Errors:\n\n * " + jserrors.replaceAll(":!:", "\n * ") + "\n\n"); - throw new RuntimeException("There were javascript console errors."); - } - } - } - - private String buildReport(JavascriptExecutor driver, String format) throws IOException { + private String buildReport(JavascriptExecutor driver, File reporter, String format) throws IOException { String script = - this.ioUtilsWrapper.toString(BUILD_REPORT_JS) + + this.fileUtilsWrapper.readFileToString(reporter) + "return jasmineMavenPlugin.printReport(window.jsApiReporter,{format:'" + format + "'});"; Object report = driver.executeScript(script); return report.toString(); @@ -85,33 +77,5 @@ private String buildJunitXmlReport(JavascriptExecutor driver, boolean debug) thr return junitReport.toString(); } - private void waitForRunnerToFinish(final WebDriver driver, int timeout, boolean debug, Log log) throws InterruptedException { - final JavascriptExecutor executor = (JavascriptExecutor) driver; - new WebDriverWait(driver, timeout, 1000).until(new Predicate() { - @Override - public boolean apply(WebDriver input) { - return SpecRunnerExecutor.this.executionFinished(executor); - } - }); - - if (!this.executionFinished(executor)) { - this.handleTimeout(timeout, debug, log); - } - } - - private void handleTimeout(int timeout, boolean debug, Log log) { - log.warn("Attempted to wait for your specs to finish processing over the course of " + - timeout + - " seconds, but it still appears to be running."); - if (debug) { - log.warn("Debug mode: will attempt to parse the incomplete spec runner results"); - } else { - throw new IllegalStateException("Timeout occurred. Aborting execution of specs. (Try configuring 'debug' to 'true' for more details.)"); - } - } - - private Boolean executionFinished(JavascriptExecutor driver) { - return (Boolean) driver.executeScript("return (window.jsApiReporter === undefined) ? false : window.jsApiReporter.finished"); - } } diff --git a/src/main/java/com/github/searls/jasmine/runner/WebDriverWaiter.java b/src/main/java/com/github/searls/jasmine/runner/WebDriverWaiter.java new file mode 100644 index 000000000..3ceedb5f0 --- /dev/null +++ b/src/main/java/com/github/searls/jasmine/runner/WebDriverWaiter.java @@ -0,0 +1,43 @@ +package com.github.searls.jasmine.runner; + +import com.google.common.base.Predicate; +import org.apache.maven.plugin.logging.Log; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.TimeoutException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.ui.WebDriverWait; + +class WebDriverWaiter { + static final String EXECUTION_FINISHED_SCRIPT = "return (window.jsApiReporter === undefined) ? false : window.jsApiReporter.finished"; + + void waitForRunnerToFinish(final WebDriver driver, final int timeout, final boolean debug, final Log log) throws InterruptedException { + final JavascriptExecutor executor = (JavascriptExecutor) driver; + try { + new WebDriverWait(driver, timeout, 1000).until(new Predicate() { + @Override + public boolean apply(WebDriver input) { + return executionFinished(executor); + } + }); + } catch (TimeoutException e) { + handleTimeout(timeout, debug, log); + } + + } + + private Boolean executionFinished(final JavascriptExecutor driver) { + return (Boolean) driver.executeScript(EXECUTION_FINISHED_SCRIPT); + } + + private void handleTimeout(final int timeout, final boolean debug, final Log log) { + log.warn("Attempted to wait for your specs to finish processing over the course of " + + timeout + + " seconds, but it still appears to be running."); + if (debug) { + log.warn("Debug mode: will attempt to parse the incomplete spec runner results"); + } else { + throw new IllegalStateException("Timeout occurred. Aborting execution of specs. (Try configuring 'debug' to 'true' for more details.)"); + } + } + +} diff --git a/src/site/markdown/custom-reporters.md.vm b/src/site/markdown/custom-reporters.md.vm new file mode 100644 index 000000000..97f713591 --- /dev/null +++ b/src/site/markdown/custom-reporters.md.vm @@ -0,0 +1,53 @@ +Providing Custom Reporters +========================== +It is possible to configure your build to use custom reporters with the jasmine-maven-plugin. +A list of reporters can be defined that will print to Standard Out during the build process. + +This can be leveraged to support reporting on metadata within your test suite. +Store information to `window` during your test execution, then retrieve it within your reporter. + +Note: The final reporter is used to determine the success of the build. +Success is determined by the presence of the string " 0 failures" in the last line of the report. +This is the behavior of the `STANDARD` reporter. + +Here is an example configuration: + +``` xml + + + + ${project.groupId} + ${project.artifactId} + ${currentStableVersion} + + + + test + + + + + + ${project.basedir}${file.separator}src${file.separator}test${file.separator}resources${file.separator}reporter.js + STANDARD + + + + + +``` + +This example configuration will first print to standard out using the custom reporter, then using the `STANDARD` reporter. +The Success of Failure of the build will be determined by the `STANDARD` reporter in this example. + +To define a custom reporter, use this interface as a template: + +``` js +(function() { + var jasmineMavenPlugin = window.jasmineMavenPlugin = window.jasmineMavenPlugin || {}; + + jasmineMavenPlugin.printReport = function(r, config) { + return "Happy Reporting!"; + }; +})(); +``` diff --git a/src/test/java/com/github/searls/jasmine/mojo/AbstractJasmineMojoTest.java b/src/test/java/com/github/searls/jasmine/mojo/AbstractJasmineMojoTest.java index 812cccadf..55197626c 100644 --- a/src/test/java/com/github/searls/jasmine/mojo/AbstractJasmineMojoTest.java +++ b/src/test/java/com/github/searls/jasmine/mojo/AbstractJasmineMojoTest.java @@ -4,7 +4,6 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.resource.ResourceManager; import org.codehaus.plexus.resource.loader.FileResourceCreationException; import org.codehaus.plexus.resource.loader.ResourceNotFoundException; import org.junit.Before; @@ -18,22 +17,19 @@ import org.mockito.runners.MockitoJUnitRunner; import java.io.File; +import java.util.Collections; +import java.util.List; import static com.github.searls.jasmine.Matchers.empty; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) public class AbstractJasmineMojoTest { private static final String ENCODING = "UTF-8"; - private static final String SCRIPT_LOADER_PATH = "scriptloaderpath"; - private static final String PARENT_PROJECT_PATH = "/parent/project/path"; @InjectMocks @Spy @@ -49,10 +45,6 @@ public void run() throws Exception { @Rule public ExpectedException expectedException = ExpectedException.none(); - private static final String CUSTOM_RUNNER_CONFIG = "customRunnerConfiguration"; - - private static final String CUSTOM_RUNNER_TEMPLATE = "customRunnerTemplate"; - @Mock private File baseDir; @@ -66,12 +58,16 @@ public void run() throws Exception { private File parentProjectFile; @Mock - private ResourceManager locator; + private ResourceRetriever resourceRetriever; + + @Mock + private ReporterRetriever reporterRetriever; @Before public void before() { this.subject.sourceEncoding = ENCODING; - this.subject.locator = this.locator; + this.subject.resourceRetriever = resourceRetriever; + this.subject.reporterRetriever = reporterRetriever; } @Test @@ -133,36 +129,40 @@ public void testGetSourceEncoding() { @Test public void testGetCustomRunnerConfiguration() throws ResourceNotFoundException, MojoExecutionException, MojoFailureException, FileResourceCreationException { - File customRunnerConfiguration = mock(File.class); - this.subject.customRunnerConfiguration = CUSTOM_RUNNER_CONFIG; - when(this.mavenProject.getFile()).thenReturn(this.projectFile); - when(this.projectFile.getParentFile()).thenReturn(this.parentProjectFile); - when(this.parentProjectFile.getAbsolutePath()).thenReturn(PARENT_PROJECT_PATH); - when(this.locator.getResourceAsFile(CUSTOM_RUNNER_CONFIG)).thenReturn(customRunnerConfiguration); - this.subject.execute(); - assertThat(this.subject.getCustomRunnerConfiguration(), is(customRunnerConfiguration)); + File configFile = mock(File.class); + String config = "/my/fancy/pants/config"; + subject.customRunnerConfiguration = config; + when(resourceRetriever.getResourceAsFile("customRunnerConfiguration", config, mavenProject)).thenReturn(configFile); + + subject.execute(); + + assertThat(subject.getCustomRunnerConfiguration(), is(configFile)); } @Test public void testGetCustomRunnerTemplate() throws ResourceNotFoundException, MojoExecutionException, MojoFailureException, FileResourceCreationException { - File customRunnerTemplate = mock(File.class); - this.subject.customRunnerTemplate = CUSTOM_RUNNER_TEMPLATE; - when(this.mavenProject.getFile()).thenReturn(this.projectFile); - when(this.projectFile.getParentFile()).thenReturn(this.parentProjectFile); - when(this.parentProjectFile.getAbsolutePath()).thenReturn(PARENT_PROJECT_PATH); - when(this.locator.getResourceAsFile(CUSTOM_RUNNER_TEMPLATE)).thenReturn(customRunnerTemplate); - this.subject.execute(); - assertThat(this.subject.getCustomRunnerTemplate(), is(customRunnerTemplate)); + File templateFile = mock(File.class); + String template = "/my/super/sweet/template"; + subject.customRunnerTemplate = template; + when(resourceRetriever.getResourceAsFile("customRunnerTemplate", template, mavenProject)).thenReturn(templateFile); + + subject.execute(); + + assertThat(subject.getCustomRunnerTemplate(), is(templateFile)); } - @Test(expected = MojoExecutionException.class) - public void testGetCustomRunnerTemplateNotFound() throws ResourceNotFoundException, MojoExecutionException, MojoFailureException, FileResourceCreationException { - this.subject.customRunnerTemplate = CUSTOM_RUNNER_TEMPLATE; - when(this.mavenProject.getFile()).thenReturn(this.projectFile); - when(this.projectFile.getParentFile()).thenReturn(this.parentProjectFile); - when(this.parentProjectFile.getAbsolutePath()).thenReturn(PARENT_PROJECT_PATH); - when(this.locator.getResourceAsFile(CUSTOM_RUNNER_TEMPLATE)).thenThrow(new FileResourceCreationException(CUSTOM_RUNNER_TEMPLATE)); - this.subject.execute(); + @Test + public void testGetReporters() throws ResourceNotFoundException, MojoExecutionException, MojoFailureException, FileResourceCreationException { + File reporterFile = mock(File.class); + List reporterFiles = Collections.singletonList(reporterFile); + String reporter = "/my/super/custom/reporter"; + List reporters = Collections.singletonList(reporter); + subject.reporters = reporters; + when(reporterRetriever.retrieveReporters(eq(reporters), eq(mavenProject))).thenReturn(reporterFiles); + + subject.execute(); + + assertThat(subject.getReporters(), is(reporterFiles)); } @Test diff --git a/src/test/java/com/github/searls/jasmine/mojo/ReporterRetrieverTest.java b/src/test/java/com/github/searls/jasmine/mojo/ReporterRetrieverTest.java new file mode 100644 index 000000000..6b8506490 --- /dev/null +++ b/src/test/java/com/github/searls/jasmine/mojo/ReporterRetrieverTest.java @@ -0,0 +1,56 @@ +package com.github.searls.jasmine.mojo; + +import org.apache.maven.project.MavenProject; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ReporterRetrieverTest { + + @Mock + ResourceRetriever resourceRetriever; + + @Mock + MavenProject mavenProject; + + @Mock + File standardReporter; + + ReporterRetriever subject; + + @Before + public void setUp() throws Exception { + subject = new ReporterRetriever(resourceRetriever); + when(resourceRetriever.getResourceAsFile("reporter", ReporterRetriever.STANDARD_REPORTER, mavenProject)).thenReturn(standardReporter); + } + + @Test + public void itShouldRetrieveReporters() throws Exception { + String customReporterPath = "/foo/bar"; + File customReporter = mock(File.class); + when(resourceRetriever.getResourceAsFile("reporter", customReporterPath, mavenProject)).thenReturn(customReporter); + List reporters = subject.retrieveReporters(Arrays.asList("STANDARD", customReporterPath), mavenProject); + + assertThat(reporters, is(Arrays.asList(standardReporter, customReporter))); + } + + @Test + public void itShouldRetrieveStandardReporterAsDefault() throws Exception { + List reporters = subject.retrieveReporters(Collections.emptyList(), mavenProject); + + assertThat(reporters, is(Collections.singletonList(standardReporter))); + } +} diff --git a/src/test/java/com/github/searls/jasmine/mojo/ResourceRetrieverTest.java b/src/test/java/com/github/searls/jasmine/mojo/ResourceRetrieverTest.java new file mode 100644 index 000000000..896075fac --- /dev/null +++ b/src/test/java/com/github/searls/jasmine/mojo/ResourceRetrieverTest.java @@ -0,0 +1,61 @@ +package com.github.searls.jasmine.mojo; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.resource.ResourceManager; +import org.codehaus.plexus.resource.loader.FileResourceCreationException; +import org.codehaus.plexus.resource.loader.ResourceNotFoundException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.File; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ResourceRetrieverTest { + + @Mock + ResourceManager locator; + + @Mock + MavenProject mavenProject; + + ResourceRetriever subject; + + @Before + public void setUp() throws Exception { + subject = new ResourceRetriever(locator); + File mavenFile = mock(File.class); + when(mavenProject.getFile()).thenReturn(mavenFile); + File mavenDir = mock(File.class); + when(mavenFile.getParentFile()).thenReturn(mavenDir); + when(mavenDir.getAbsolutePath()).thenReturn("/maven/dir"); + } + + @Test + public void testGetResource() throws ResourceNotFoundException, MojoExecutionException, MojoFailureException, FileResourceCreationException { + File expectedFile = mock(File.class); + String resourceLocation = "/foo/bar"; + when(locator.getResourceAsFile(resourceLocation)).thenReturn(expectedFile); + + File actualFile = subject.getResourceAsFile("param", resourceLocation, mavenProject); + + assertThat(actualFile, is(expectedFile)); + } + + @Test(expected = MojoExecutionException.class) + public void testResourceNotFound() throws ResourceNotFoundException, MojoExecutionException, MojoFailureException, FileResourceCreationException { + String resourceLocation = "/foo/bar"; + when(locator.getResourceAsFile(resourceLocation)).thenThrow(new FileResourceCreationException("Bad Things Happen")); + + subject.getResourceAsFile("param", resourceLocation, mavenProject); + } +} diff --git a/src/test/java/com/github/searls/jasmine/runner/ConsoleErrorCheckerTest.java b/src/test/java/com/github/searls/jasmine/runner/ConsoleErrorCheckerTest.java new file mode 100644 index 000000000..f8db07ca3 --- /dev/null +++ b/src/test/java/com/github/searls/jasmine/runner/ConsoleErrorCheckerTest.java @@ -0,0 +1,65 @@ +package com.github.searls.jasmine.runner; + +import org.apache.maven.plugin.logging.Log; +import org.hamcrest.core.StringContains; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +import static org.hamcrest.Matchers.allOf; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ConsoleErrorCheckerTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Mock + WebDriver webDriver; + @Mock + Log log; + + @Mock + WebElement headWithErrors; + private String error = "Bad to the Bone!"; + @Mock + WebElement headWithoutErrors; + + ConsoleErrorChecker subject; + + @Before + public void setUp() throws Exception { + subject = new ConsoleErrorChecker(); + when(headWithErrors.getAttribute("jmp_jserror")).thenReturn(error); + when(headWithoutErrors.getAttribute("jmp_jserro")).thenReturn(""); + } + + @Test + public void shouldPassWhenNoErrors() throws Exception { + when(webDriver.findElement(By.tagName("head"))).thenReturn(headWithoutErrors); + + subject.checkForConsoleErrors(webDriver, log); + } + + @Test + public void shouldThrowWhenErrors() throws Exception { + expectedException.expect(RuntimeException.class); + expectedException.expectMessage("There were javascript console errors."); + + when(webDriver.findElement(By.tagName("head"))).thenReturn(headWithErrors); + + subject.checkForConsoleErrors(webDriver, log); + + verify(log).warn(argThat(allOf(new StringContains("JavaScript Console Errors:"), new StringContains(error)))); + } +} diff --git a/src/test/java/com/github/searls/jasmine/runner/SpecRunnerExecutorTest.java b/src/test/java/com/github/searls/jasmine/runner/SpecRunnerExecutorTest.java index dddac22c9..4dfcc33da 100644 --- a/src/test/java/com/github/searls/jasmine/runner/SpecRunnerExecutorTest.java +++ b/src/test/java/com/github/searls/jasmine/runner/SpecRunnerExecutorTest.java @@ -1,88 +1,76 @@ package com.github.searls.jasmine.runner; -import com.gargoylesoftware.htmlunit.BrowserVersion; +import com.github.searls.jasmine.io.FileUtilsWrapper; import com.github.searls.jasmine.io.IOUtilsWrapper; import com.github.searls.jasmine.model.JasmineResult; -import org.apache.commons.io.FileUtils; import org.apache.maven.plugin.logging.Log; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.InjectMocks; import org.mockito.Mock; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import java.io.File; -import java.io.IOException; import java.net.URL; +import java.util.Collections; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.isA; +import static org.mockito.Matchers.contains; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.doNothing; -import static org.powermock.api.mockito.PowerMockito.spy; -import static org.powermock.api.mockito.PowerMockito.verifyStatic; @RunWith(PowerMockRunner.class) -@PrepareForTest(FileUtils.class) +@PrepareForTest(URL.class) public class SpecRunnerExecutorTest { - private static final String BUILD_REPORT_JS_CONTENTS = "var jasmineMavenPlugin = {printReport: function(){ return 'pants\\nkaka'; }};"; - private static final String JUNIT_RESULTS = "var junitXmlReporter = { report: function(reporter) { return ''; }};"; - private static HtmlUnitDriver driver; - @Mock private IOUtilsWrapper ioUtilsWrapper; + @Mock + private FileUtilsWrapper fileUtilsWrapper; + @Mock + private WebDriverWaiter webDriverWaiter; + @Mock + private ConsoleErrorChecker consoleErrorChecker; + private URL runnerUrl; @Mock - private File file; + private File junitXmlReport; + @Mock + private RemoteWebDriver webDriver; + private int timeout = 2; + private boolean debug = false; @Mock private Log log; + private String format = null; + @Mock + File reporter; + private String report = "report"; - private final URL resource = this.getClass().getResource("/example_nested_specrunner.html"); - - @InjectMocks private SpecRunnerExecutor subject; @Before - public void stubResourceStreams() throws IOException { - spy(FileUtils.class); + public void setUp() throws Exception { + subject = new SpecRunnerExecutor(ioUtilsWrapper, fileUtilsWrapper, webDriverWaiter, consoleErrorChecker); - when(this.ioUtilsWrapper.toString(isA(String.class))).thenReturn(BUILD_REPORT_JS_CONTENTS, JUNIT_RESULTS); - driver = new HtmlUnitDriver(BrowserVersion.FIREFOX_38); - driver.setJavascriptEnabled(true); - } + runnerUrl = PowerMockito.mock(URL.class); - @Test - public void shouldFindSpecsInResults() throws Exception { - doNothing().when(FileUtils.class); - FileUtils.writeStringToFile(this.file, "", "UTF-8"); - - JasmineResult result = this.subject.execute(this.resource, this.file, driver, 300, false, this.log, null); - - assertThat(result, is(not(nullValue()))); - assertThat(result.getDescription(), containsString("kaka")); - assertThat(result.getDetails(), containsString("pants")); - assertThat(result.didPass(), is(false)); - - verifyStatic(); - FileUtils.writeStringToFile(this.file, "", "UTF-8"); + when(fileUtilsWrapper.readFileToString(reporter)).thenReturn("reporter"); + when(ioUtilsWrapper.toString(SpecRunnerExecutor.CREATE_JUNIT_XML)).thenReturn("reporter"); + when(webDriver.executeScript(contains("reporter"))).thenReturn(report); } @Test - public void shouldExportJUnitResults() throws Exception { - doNothing().when(FileUtils.class); - FileUtils.writeStringToFile(this.file, "", "UTF-8"); - - this.subject.execute(this.resource, this.file, driver, 300, false, this.log, null); + public void shouldExecute() throws Exception { + JasmineResult result = subject.execute(runnerUrl, junitXmlReport, webDriver, timeout, debug, log, format, Collections.singletonList(reporter)); - verifyStatic(); - FileUtils.writeStringToFile(this.file, "", "UTF-8"); + verify(webDriver).get(runnerUrl.toString()); + verify(webDriverWaiter).waitForRunnerToFinish(webDriver, timeout, debug, log); + verify(fileUtilsWrapper).writeStringToFile(junitXmlReport, report); + assertThat(result, is(not(nullValue()))); + assertThat(result.getDetails(), containsString(report)); } } diff --git a/src/test/java/com/github/searls/jasmine/runner/WebDriverWaiterTest.java b/src/test/java/com/github/searls/jasmine/runner/WebDriverWaiterTest.java new file mode 100644 index 000000000..2b2070864 --- /dev/null +++ b/src/test/java/com/github/searls/jasmine/runner/WebDriverWaiterTest.java @@ -0,0 +1,68 @@ +package com.github.searls.jasmine.runner; + +import org.apache.maven.plugin.logging.Log; +import org.hamcrest.core.StringContains; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.openqa.selenium.remote.RemoteWebDriver; + +import static org.hamcrest.Matchers.allOf; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.contains; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class WebDriverWaiterTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Mock + RemoteWebDriver webDriver; + int timeout = 2; + @Mock + Log log; + + WebDriverWaiter subject; + + @Before + public void setUp() throws Exception { + subject = new WebDriverWaiter(); + } + + @Test + public void itShouldWait() throws Exception { + boolean debug = false; + when(webDriver.executeScript(WebDriverWaiter.EXECUTION_FINISHED_SCRIPT)).thenReturn(true); + + subject.waitForRunnerToFinish(webDriver, timeout, debug, log); + } + + @Test + public void itShouldThrowWhenTimesOut() throws Exception { + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Timeout occurred."); + + boolean debug = false; + when(webDriver.executeScript(WebDriverWaiter.EXECUTION_FINISHED_SCRIPT)).thenReturn(false); + + subject.waitForRunnerToFinish(webDriver, timeout, debug, log); + } + + @Test + public void itShouldLogWhenTimesOutDebugging() throws Exception { + boolean debug = true; + when(webDriver.executeScript(WebDriverWaiter.EXECUTION_FINISHED_SCRIPT)).thenReturn(false); + + subject.waitForRunnerToFinish(webDriver, timeout, debug, log); + + verify(log).warn(argThat(allOf(new StringContains("Attempted to wait"), new StringContains(timeout + " seconds")))); + verify(log).warn(contains("Debug mode:")); + } +} diff --git a/src/test/resources/examples/jasmine-webapp-custom-reporters/pom.xml b/src/test/resources/examples/jasmine-webapp-custom-reporters/pom.xml new file mode 100644 index 000000000..9542d2526 --- /dev/null +++ b/src/test/resources/examples/jasmine-webapp-custom-reporters/pom.xml @@ -0,0 +1,35 @@ + + 4.0.0 + + com.github.searls + jasmine-example-superpom + %{project.version} + + jasmine-webapp-custom-runner + war + Example Webapp using Jasmine Maven Plugin that overrides the default custom runner template + + + + + com.github.searls + jasmine-maven-plugin + %{project.version} + + + + test + + + + + + ${project.basedir}${file.separator}src${file.separator}test${file.separator}resources${file.separator}reporter.js + STANDARD + + + + + + diff --git a/src/test/resources/examples/jasmine-webapp-custom-reporters/src/main/javascript/HelloWorld.js b/src/test/resources/examples/jasmine-webapp-custom-reporters/src/main/javascript/HelloWorld.js new file mode 100644 index 000000000..fd253fabf --- /dev/null +++ b/src/test/resources/examples/jasmine-webapp-custom-reporters/src/main/javascript/HelloWorld.js @@ -0,0 +1,5 @@ +var HelloWorld = function() { + this.greeting = function() { + return "Hello, World"; + } +} \ No newline at end of file diff --git a/src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/javascript/ExampleTestSpec.js b/src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/javascript/ExampleTestSpec.js new file mode 100644 index 000000000..d98fee7fb --- /dev/null +++ b/src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/javascript/ExampleTestSpec.js @@ -0,0 +1,11 @@ +describe('Default reporters and also reporter that stores custom information',function(){ + + it('should retrieve value stored to window during test',function(){ + window.exampleTest = 'Hello World'; + }); + + it('should say hello with normal test', function() { + var helloWorld = new HelloWorld(); + expect(helloWorld.greeting()).toBe("Hello, World"); + }); +}); diff --git a/src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/resources/reporter.js b/src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/resources/reporter.js new file mode 100644 index 000000000..3a8cb2f16 --- /dev/null +++ b/src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/resources/reporter.js @@ -0,0 +1,7 @@ +(function() { + var jasmineMavenPlugin = window.jasmineMavenPlugin = window.jasmineMavenPlugin || {}; + + jasmineMavenPlugin.printReport = function(r, config) { + return window.exampleTest; + }; +})(); From 911f9ec06c02bbe287de673639bcdbb4e7a58e18 Mon Sep 17 00:00:00 2001 From: Sam Jones Date: Thu, 28 Jul 2016 16:02:01 -0400 Subject: [PATCH 3/3] Adds the ability to define File System reporters through plugin configuration. - Adds `fileSystemReporters` property to support list of reports. - Adds file system reporter to custom reporters example project. - Updates documentation for defining custom reporters. - Allows `JUNIT_XML` to be used as a file system reporter in the list of defined reporters. - Defaults to the `JUNIT_XML` reporter if none are provided. --- features/custom_reporters.feature | 4 +- .../jasmine/config/JasmineConfiguration.java | 6 +- .../jasmine/model/FileSystemReporter.java | 21 +++++++ .../searls/jasmine/model/JasmineResult.java | 4 -- .../github/searls/jasmine/model/Reporter.java | 18 ++++++ .../jasmine/mojo/AbstractJasmineMojo.java | 44 +++++++++++--- .../jasmine/mojo/ReporterRetriever.java | 47 +++++++++------ .../jasmine/mojo/ResourceRetriever.java | 4 +- .../github/searls/jasmine/mojo/TestMojo.java | 12 +--- .../jasmine/runner/SpecRunnerExecutor.java | 57 +++++++++++-------- src/main/resources/lib/createJunitXml.js | 4 +- src/site/markdown/custom-reporters.md.vm | 40 ++++++++++++- .../jasmine/mojo/AbstractJasmineMojoTest.java | 26 +++++++-- .../jasmine/mojo/ReporterRetrieverTest.java | 51 +++++++++++++++-- .../runner/SpecRunnerExecutorTest.java | 13 +++-- .../jasmine-webapp-custom-reporters/pom.xml | 18 +++++- .../src/test/resources/logger.js | 8 +++ 17 files changed, 289 insertions(+), 88 deletions(-) create mode 100644 src/main/java/com/github/searls/jasmine/model/FileSystemReporter.java create mode 100644 src/main/java/com/github/searls/jasmine/model/Reporter.java create mode 100644 src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/resources/logger.js diff --git a/features/custom_reporters.feature b/features/custom_reporters.feature index 623fc4399..82293aba1 100644 --- a/features/custom_reporters.feature +++ b/features/custom_reporters.feature @@ -7,7 +7,9 @@ Feature: Support custom reporter Scenario: project with javascript using a custom reporter Given I am currently in the "jasmine-webapp-custom-reporters" project - When I run "mvn clean test -X -e" + When I run "mvn clean test" Then the build should succeed And I should see "Results: 2 specs, 0 failures, 0 pending" And I should see "Hello World" + And the file "target/jasmine/TEST-jasmine.xml" should have XML "/testsuite[@errors=0 and @tests=2 and @failures=0 and @skipped=0]" + And the file "target/jasmine/TEST-jasmine.log" should contain "Hello World" diff --git a/src/main/java/com/github/searls/jasmine/config/JasmineConfiguration.java b/src/main/java/com/github/searls/jasmine/config/JasmineConfiguration.java index 1ed4da8e8..60c3ec1a9 100644 --- a/src/main/java/com/github/searls/jasmine/config/JasmineConfiguration.java +++ b/src/main/java/com/github/searls/jasmine/config/JasmineConfiguration.java @@ -1,5 +1,7 @@ package com.github.searls.jasmine.config; +import com.github.searls.jasmine.model.FileSystemReporter; +import com.github.searls.jasmine.model.Reporter; import com.github.searls.jasmine.model.ScriptSearch; import com.github.searls.jasmine.mojo.Context; import com.github.searls.jasmine.runner.SpecRunnerTemplate; @@ -36,7 +38,9 @@ public interface JasmineConfiguration { File getCustomRunnerConfiguration(); - List getReporters(); + List getReporters(); + + List getFileSystemReporters(); int getAutoRefreshInterval(); diff --git a/src/main/java/com/github/searls/jasmine/model/FileSystemReporter.java b/src/main/java/com/github/searls/jasmine/model/FileSystemReporter.java new file mode 100644 index 000000000..ead5beae2 --- /dev/null +++ b/src/main/java/com/github/searls/jasmine/model/FileSystemReporter.java @@ -0,0 +1,21 @@ +package com.github.searls.jasmine.model; + +import java.io.File; + +public class FileSystemReporter extends Reporter { + public String fileName; + public File file; + + public FileSystemReporter() { + } + + public FileSystemReporter(String fileName, String reporter) { + super(reporter); + this.fileName = fileName; + } + + public FileSystemReporter(File file, File reporterFile) { + super(reporterFile); + this.file = file; + } +} diff --git a/src/main/java/com/github/searls/jasmine/model/JasmineResult.java b/src/main/java/com/github/searls/jasmine/model/JasmineResult.java index d490df8e1..81e3d503c 100644 --- a/src/main/java/com/github/searls/jasmine/model/JasmineResult.java +++ b/src/main/java/com/github/searls/jasmine/model/JasmineResult.java @@ -20,10 +20,6 @@ public void setDetails(String details) { this.details = details; } - public void appendDetails(String details) { - this.details += details; - } - private T last(T[] array) { return array[array.length - 1]; } diff --git a/src/main/java/com/github/searls/jasmine/model/Reporter.java b/src/main/java/com/github/searls/jasmine/model/Reporter.java new file mode 100644 index 000000000..0e75abcff --- /dev/null +++ b/src/main/java/com/github/searls/jasmine/model/Reporter.java @@ -0,0 +1,18 @@ +package com.github.searls.jasmine.model; + +import java.io.File; + +public class Reporter { + public String reporterName; + public File reporterFile; + + public Reporter() {} + + public Reporter(String reporterName) { + this.reporterName = reporterName; + } + + public Reporter(File reporterFile) { + this.reporterFile = reporterFile; + } +} diff --git a/src/main/java/com/github/searls/jasmine/mojo/AbstractJasmineMojo.java b/src/main/java/com/github/searls/jasmine/mojo/AbstractJasmineMojo.java index bedc1466d..e7c2e7ed6 100644 --- a/src/main/java/com/github/searls/jasmine/mojo/AbstractJasmineMojo.java +++ b/src/main/java/com/github/searls/jasmine/mojo/AbstractJasmineMojo.java @@ -3,6 +3,8 @@ import com.github.searls.jasmine.config.JasmineConfiguration; import com.github.searls.jasmine.exception.StringifiesStackTraces; import com.github.searls.jasmine.io.ScansDirectory; +import com.github.searls.jasmine.model.FileSystemReporter; +import com.github.searls.jasmine.model.Reporter; import com.github.searls.jasmine.model.ScriptSearch; import com.github.searls.jasmine.runner.SpecRunnerTemplate; import com.github.searls.jasmine.thirdpartylibs.ProjectClassLoaderFactory; @@ -104,13 +106,36 @@ public abstract class AbstractJasmineMojo extends AbstractMojo implements Jasmin *

Example usage:

*
    * <reporters>
-   *   <reporter>${project.basedir}/src/test/resources/myCustomReporter.js</reporter>
-   *   <reporter>STANDARD</reporter>
+   *   <reporter>
+   *     <reporterName>${project.basedir}/src/test/resources/myCustomReporter.js</reporterName>
+   *   </reporter>
+   *   <reporter>
+   *     <reporterName>STANDARD</reporterName>
+   *   </reporter>
    * </reporters>
    * 
*/ @Parameter - protected List reporters = new ArrayList(); + protected List reporters = new ArrayList(); + + /** + *

Specify a custom file system reporter to be used to store the test report.

+ *

Example usage:

+ *
+   * <fileSystemReporters>
+   *   <reporter>
+   *     <fileName>MyFile.log</fileName>
+   *     <reporterName>${project.basedir}/src/test/resources/myCustomReporter.js</reporterName>
+   *   </reporter>
+   *   <reporter>
+   *     <fileName>Test-jasmine.xml</fileName>
+   *     <reporterName>JUNIT_XML</reporterName>
+   *   </reporter>
+   * </fileSystemReporters>
+   * 
+ */ + @Parameter + protected List fileSystemReporters = new ArrayList(); /** * Target directory for files created by the plugin. @@ -386,7 +411,6 @@ public abstract class AbstractJasmineMojo extends AbstractMojo implements Jasmin private File customRunnerTemplateFile; private File customRunnerConfigurationFile; - private List reporterFiles = new ArrayList(); @Override public void execute() throws MojoExecutionException, MojoFailureException { @@ -471,8 +495,13 @@ public File getCustomRunnerConfiguration() { } @Override - public List getReporters() { - return this.reporterFiles; + public List getReporters() { + return this.reporters; + } + + @Override + public List getFileSystemReporters() { + return this.fileSystemReporters; } @Override @@ -515,7 +544,8 @@ protected boolean isSkipTests() { private void loadResources() throws MojoExecutionException { this.customRunnerTemplateFile = getResourceRetriever().getResourceAsFile("customRunnerTemplate", this.customRunnerTemplate, this.mavenProject); this.customRunnerConfigurationFile = getResourceRetriever().getResourceAsFile("customRunnerConfiguration", this.customRunnerConfiguration, this.mavenProject); - this.reporterFiles = getReporterRetriever().retrieveReporters(this.reporters, this.mavenProject); + this.reporters = getReporterRetriever().retrieveReporters(this.reporters, this.mavenProject); + this.fileSystemReporters = getReporterRetriever().retrieveFileSystemReporters(this.fileSystemReporters, this.getJasmineTargetDir(), this.mavenProject); } private ResourceRetriever getResourceRetriever() { diff --git a/src/main/java/com/github/searls/jasmine/mojo/ReporterRetriever.java b/src/main/java/com/github/searls/jasmine/mojo/ReporterRetriever.java index 91ec9c157..ddb9a9830 100644 --- a/src/main/java/com/github/searls/jasmine/mojo/ReporterRetriever.java +++ b/src/main/java/com/github/searls/jasmine/mojo/ReporterRetriever.java @@ -1,17 +1,22 @@ package com.github.searls.jasmine.mojo; +import com.github.searls.jasmine.model.FileSystemReporter; +import com.github.searls.jasmine.model.Reporter; import com.google.inject.Inject; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import java.io.File; -import java.util.ArrayList; import java.util.List; public class ReporterRetriever { - static final String STANDARD_REPORTER = "/lib/buildReport.js"; + public static final String STANDARD_REPORTER = "/lib/buildReport.js"; private static final String STANDARD_REPORTER_KEY = "STANDARD"; + private static final String JUNIT_XML_FILENAME = "TEST-jasmine.xml"; + private static final String JUNIT_XML_KEY = "JUNIT_XML"; + public static final String JUNIT_XML_REPORTER = "lib/createJunitXml.js"; + private final ResourceRetriever resourceRetriever; @Inject @@ -19,28 +24,38 @@ public ReporterRetriever(final ResourceRetriever resourceRetriever) { this.resourceRetriever = resourceRetriever; } - List retrieveReporters(final List reporters, final MavenProject mavenProject) throws MojoExecutionException { - final List reporterFiles = new ArrayList(); - for (String reporter : reporters) { - if (STANDARD_REPORTER_KEY.equals(reporter)) { - reporterFiles.add(getStandardReporter(mavenProject)); - } else { - reporterFiles.add(getReporter(mavenProject, reporter)); - } + List retrieveFileSystemReporters(final List reporters, final File targetDirectory, final MavenProject mavenProject) throws MojoExecutionException { + if (reporters.isEmpty()) { + reporters.add(new FileSystemReporter(JUNIT_XML_FILENAME, JUNIT_XML_KEY)); } - if (reporterFiles.isEmpty()) { - reporterFiles.add(getStandardReporter(mavenProject)); + for (FileSystemReporter reporter : reporters) { + if (JUNIT_XML_KEY.equals(reporter.reporterName)) { + reporter.reporterName = JUNIT_XML_REPORTER; + } + reporter.reporterFile = getReporter(reporter.reporterName, mavenProject); + reporter.file = new File(targetDirectory, reporter.fileName); } - return reporterFiles; + return reporters; } - private File getStandardReporter(final MavenProject mavenProject) throws MojoExecutionException { - return getReporter(mavenProject, STANDARD_REPORTER); + List retrieveReporters(final List reporters, final MavenProject mavenProject) throws MojoExecutionException { + if (reporters.isEmpty()) { + reporters.add(new Reporter(STANDARD_REPORTER_KEY)); + } + + for (Reporter reporter : reporters) { + if (STANDARD_REPORTER_KEY.equals(reporter.reporterName)) { + reporter.reporterName = STANDARD_REPORTER; + } + reporter.reporterFile = getReporter(reporter.reporterName, mavenProject); + } + + return reporters; } - private File getReporter(final MavenProject mavenProject, final String reporter) throws MojoExecutionException { + private File getReporter(final String reporter, final MavenProject mavenProject) throws MojoExecutionException { return resourceRetriever.getResourceAsFile("reporter", reporter, mavenProject); } } diff --git a/src/main/java/com/github/searls/jasmine/mojo/ResourceRetriever.java b/src/main/java/com/github/searls/jasmine/mojo/ResourceRetriever.java index f870e6b5f..04feddb26 100644 --- a/src/main/java/com/github/searls/jasmine/mojo/ResourceRetriever.java +++ b/src/main/java/com/github/searls/jasmine/mojo/ResourceRetriever.java @@ -11,13 +11,13 @@ public class ResourceRetriever { private final ResourceManager locator; - static final String ERROR_FILE_DNE = "Invalid value for parameter '%s'. File does not exist: %s"; + private static final String ERROR_FILE_DNE = "Invalid value for parameter '%s'. File does not exist: %s"; public ResourceRetriever(final ResourceManager locator) { this.locator = locator; } - File getResourceAsFile(final String parameter, final String resourceLocation, final MavenProject mavenProject) throws MojoExecutionException { + public File getResourceAsFile(final String parameter, final String resourceLocation, final MavenProject mavenProject) throws MojoExecutionException { File file = null; if (resourceLocation != null) { diff --git a/src/main/java/com/github/searls/jasmine/mojo/TestMojo.java b/src/main/java/com/github/searls/jasmine/mojo/TestMojo.java index 0cd07eaec..260da2b35 100644 --- a/src/main/java/com/github/searls/jasmine/mojo/TestMojo.java +++ b/src/main/java/com/github/searls/jasmine/mojo/TestMojo.java @@ -140,14 +140,6 @@ public class TestMojo extends AbstractJasmineMojo { @Parameter(property = "phantomjs", defaultValue = "${phantomJs}") protected PhantomJsOptions phantomjs; - /** - * The name of the generated JUnit XML report. - * - * @since 1.1.0 - */ - @Parameter(defaultValue = "TEST-jasmine.xml") - protected String junitXmlReportFileName; - /** * Keep the server alive after the jasmine:test goal exists. * Useful if you need to run further analysis on your tests, like collecting code coverage. @@ -236,13 +228,13 @@ private JasmineResult executeSpecs(URL runner) throws Exception { WebDriver driver = this.createDriver(); JasmineResult result = new SpecRunnerExecutor().execute( runner, - new File(this.jasmineTargetDir, this.junitXmlReportFileName), driver, this.timeout, this.debug, this.getLog(), this.format, - getReporters() + getReporters(), + getFileSystemReporters() ); return result; } diff --git a/src/main/java/com/github/searls/jasmine/runner/SpecRunnerExecutor.java b/src/main/java/com/github/searls/jasmine/runner/SpecRunnerExecutor.java index 2dfce85d0..f3dc1ed67 100644 --- a/src/main/java/com/github/searls/jasmine/runner/SpecRunnerExecutor.java +++ b/src/main/java/com/github/searls/jasmine/runner/SpecRunnerExecutor.java @@ -1,8 +1,9 @@ package com.github.searls.jasmine.runner; import com.github.searls.jasmine.io.FileUtilsWrapper; -import com.github.searls.jasmine.io.IOUtilsWrapper; +import com.github.searls.jasmine.model.FileSystemReporter; import com.github.searls.jasmine.model.JasmineResult; +import com.github.searls.jasmine.model.Reporter; import org.apache.maven.plugin.logging.Log; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; @@ -14,26 +15,22 @@ public class SpecRunnerExecutor { - public static final String CREATE_JUNIT_XML = "/lib/createJunitXml.js"; - - private final IOUtilsWrapper ioUtilsWrapper; private final FileUtilsWrapper fileUtilsWrapper; private final WebDriverWaiter webDriverWaiter; private final ConsoleErrorChecker consoleErrorChecker; - public SpecRunnerExecutor(IOUtilsWrapper ioUtilsWrapper, FileUtilsWrapper fileUtilsWrapper, WebDriverWaiter webDriverWaiter, ConsoleErrorChecker consoleErrorChecker) { - this.ioUtilsWrapper = ioUtilsWrapper; + public SpecRunnerExecutor(FileUtilsWrapper fileUtilsWrapper, WebDriverWaiter webDriverWaiter, ConsoleErrorChecker consoleErrorChecker) { this.fileUtilsWrapper = fileUtilsWrapper; this.webDriverWaiter = webDriverWaiter; this.consoleErrorChecker = consoleErrorChecker; } public SpecRunnerExecutor() { - this(new IOUtilsWrapper(), new FileUtilsWrapper(), new WebDriverWaiter(), new ConsoleErrorChecker()); + this(new FileUtilsWrapper(), new WebDriverWaiter(), new ConsoleErrorChecker()); } - public JasmineResult execute(URL runnerUrl, File junitXmlReport, WebDriver driver, int timeout, boolean debug, Log log, String format, List reporters) { + public JasmineResult execute(final URL runnerUrl, final WebDriver driver, final int timeout, final boolean debug, final Log log, final String format, final List reporters, final List fileSystemReporters) { try { if (!(driver instanceof JavascriptExecutor)) { throw new RuntimeException("The provided web driver can't execute JavaScript: " + driver.getClass()); @@ -44,13 +41,12 @@ public JasmineResult execute(URL runnerUrl, File junitXmlReport, WebDriver drive consoleErrorChecker.checkForConsoleErrors(driver, log); - JasmineResult jasmineResult = new JasmineResult(); - for (File reporter : reporters) { - jasmineResult.appendDetails(this.buildReport(executor, reporter, format)); - } - fileUtilsWrapper.writeStringToFile(junitXmlReport, this.buildJunitXmlReport(executor, debug)); + storeFileSystemReports(fileSystemReporters, executor, debug); + JasmineResult jasmineResult = new JasmineResult(); + jasmineResult.setDetails(buildReports(reporters, executor, format)); return jasmineResult; + } catch (Exception e) { throw new RuntimeException(e); } finally { @@ -62,19 +58,34 @@ public JasmineResult execute(URL runnerUrl, File junitXmlReport, WebDriver drive } } - private String buildReport(JavascriptExecutor driver, File reporter, String format) throws IOException { - String script = - this.fileUtilsWrapper.readFileToString(reporter) + - "return jasmineMavenPlugin.printReport(window.jsApiReporter,{format:'" + format + "'});"; - Object report = driver.executeScript(script); + private void storeFileSystemReports(final List fileSystemReporters, final JavascriptExecutor executor, final boolean debug) throws IOException { + for (FileSystemReporter reporter : fileSystemReporters) { + fileUtilsWrapper.writeStringToFile(reporter.file, this.buildFileSystemReport(executor, reporter.reporterFile, debug)); + } + } + + private String buildFileSystemReport(final JavascriptExecutor driver, final File reporter, final boolean debug) throws IOException { + final String command = "return fileSystemReporter.report(window.jsApiReporter," + debug + ");"; + return executeReportCommand(driver, reporter, command); + } + + private String buildReports(final List reporters, final JavascriptExecutor executor, final String format) throws IOException { + final StringBuilder report = new StringBuilder(); + for (Reporter reporter : reporters) { + report.append(buildReport(executor, reporter.reporterFile, format)); + } return report.toString(); } - private String buildJunitXmlReport(JavascriptExecutor driver, boolean debug) throws IOException { - Object junitReport = driver.executeScript( - this.ioUtilsWrapper.toString(CREATE_JUNIT_XML) + - "return junitXmlReporter.report(window.jsApiReporter," + debug + ");"); - return junitReport.toString(); + private String buildReport(final JavascriptExecutor driver, final File reporter, final String format) throws IOException { + final String command = "return jasmineMavenPlugin.printReport(window.jsApiReporter,{format:'" + format + "'});"; + return executeReportCommand(driver, reporter, command); + } + + private String executeReportCommand(final JavascriptExecutor driver, final File reporter, final String command) throws IOException { + final String script = this.fileUtilsWrapper.readFileToString(reporter) + command; + final Object report = driver.executeScript(script); + return report.toString(); } diff --git a/src/main/resources/lib/createJunitXml.js b/src/main/resources/lib/createJunitXml.js index 23de56790..787986ada 100644 --- a/src/main/resources/lib/createJunitXml.js +++ b/src/main/resources/lib/createJunitXml.js @@ -1,4 +1,4 @@ -var junitXmlReporter; +var fileSystemReporter; (function() { var resultForSpec = function(reporter, spec){ @@ -11,7 +11,7 @@ var junitXmlReporter; return {}; }; - junitXmlReporter = { + fileSystemReporter = { prolog: '', report: function(reporter,debug) { if (!reporter) diff --git a/src/site/markdown/custom-reporters.md.vm b/src/site/markdown/custom-reporters.md.vm index 97f713591..192008647 100644 --- a/src/site/markdown/custom-reporters.md.vm +++ b/src/site/markdown/custom-reporters.md.vm @@ -1,7 +1,7 @@ Providing Custom Reporters ========================== It is possible to configure your build to use custom reporters with the jasmine-maven-plugin. -A list of reporters can be defined that will print to Standard Out during the build process. +A list of reporters can be defined that will print to either standard out or save to the file system during the build process. This can be leveraged to support reporting on metadata within your test suite. Store information to `window` during your test execution, then retrieve it within your reporter. @@ -28,15 +28,31 @@ Here is an example configuration: - ${project.basedir}${file.separator}src${file.separator}test${file.separator}resources${file.separator}reporter.js - STANDARD + + ${project.basedir}${file.separator}src${file.separator}test${file.separator}resources${file.separator}reporter.js + + + STANDARD + + + + TEST-jasmine.log + ${project.basedir}${file.separator}src${file.separator}test${file.separator}resources${file.separator}logger.js + + + TEST-jasmine.xml + JUNIT_XML + + ``` +*Standard Out Reporter:* + This example configuration will first print to standard out using the custom reporter, then using the `STANDARD` reporter. The Success of Failure of the build will be determined by the `STANDARD` reporter in this example. @@ -51,3 +67,21 @@ To define a custom reporter, use this interface as a template: }; })(); ``` + +*File System Reporter:* + +This example configuration will first execute the custom logger and store the output to `TEST-jasmine.log`, then using the standard `JUNIT_XML` reporter, store the junit xml report to `TEST-jasmine.xml`. + +To define a custom file system reporter, use this interface as a template: + +``` js +var fileSystemReporter; + +(function() { + fileSystemReporter = { + report: function(reporter,debug) { + return "Happy Reporting!"; + } + }; +})(); +``` diff --git a/src/test/java/com/github/searls/jasmine/mojo/AbstractJasmineMojoTest.java b/src/test/java/com/github/searls/jasmine/mojo/AbstractJasmineMojoTest.java index 55197626c..56e902f9d 100644 --- a/src/test/java/com/github/searls/jasmine/mojo/AbstractJasmineMojoTest.java +++ b/src/test/java/com/github/searls/jasmine/mojo/AbstractJasmineMojoTest.java @@ -1,6 +1,8 @@ package com.github.searls.jasmine.mojo; import com.github.searls.jasmine.exception.StringifiesStackTraces; +import com.github.searls.jasmine.model.FileSystemReporter; +import com.github.searls.jasmine.model.Reporter; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; @@ -51,6 +53,9 @@ public void run() throws Exception { @Mock private MavenProject mavenProject; + @Mock + private File targetDir; + @Mock private File projectFile; @@ -66,6 +71,7 @@ public void run() throws Exception { @Before public void before() { this.subject.sourceEncoding = ENCODING; + this.subject.jasmineTargetDir = targetDir; this.subject.resourceRetriever = resourceRetriever; this.subject.reporterRetriever = reporterRetriever; } @@ -153,16 +159,24 @@ public void testGetCustomRunnerTemplate() throws ResourceNotFoundException, Mojo @Test public void testGetReporters() throws ResourceNotFoundException, MojoExecutionException, MojoFailureException, FileResourceCreationException { - File reporterFile = mock(File.class); - List reporterFiles = Collections.singletonList(reporterFile); - String reporter = "/my/super/custom/reporter"; - List reporters = Collections.singletonList(reporter); + List reporters = Collections.singletonList(mock(Reporter.class)); subject.reporters = reporters; - when(reporterRetriever.retrieveReporters(eq(reporters), eq(mavenProject))).thenReturn(reporterFiles); + when(reporterRetriever.retrieveReporters(reporters, mavenProject)).thenReturn(reporters); + + subject.execute(); + + assertThat(subject.getReporters(), is(reporters)); + } + + @Test + public void testGetFileSystemReporters() throws ResourceNotFoundException, MojoExecutionException, MojoFailureException, FileResourceCreationException { + List fsReporters = Collections.singletonList(mock(FileSystemReporter.class)); + subject.fileSystemReporters = fsReporters; + when(reporterRetriever.retrieveFileSystemReporters(fsReporters, targetDir, mavenProject)).thenReturn(fsReporters); subject.execute(); - assertThat(subject.getReporters(), is(reporterFiles)); + assertThat(subject.getFileSystemReporters(), is(fsReporters)); } @Test diff --git a/src/test/java/com/github/searls/jasmine/mojo/ReporterRetrieverTest.java b/src/test/java/com/github/searls/jasmine/mojo/ReporterRetrieverTest.java index 6b8506490..27709d1ea 100644 --- a/src/test/java/com/github/searls/jasmine/mojo/ReporterRetrieverTest.java +++ b/src/test/java/com/github/searls/jasmine/mojo/ReporterRetrieverTest.java @@ -1,17 +1,21 @@ package com.github.searls.jasmine.mojo; +import com.github.searls.jasmine.model.FileSystemReporter; +import com.github.searls.jasmine.model.Reporter; import org.apache.maven.project.MavenProject; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.internal.matchers.EndsWith; import org.mockito.runners.MockitoJUnitRunner; import java.io.File; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; @@ -26,15 +30,22 @@ public class ReporterRetrieverTest { @Mock MavenProject mavenProject; + File targetDir = new File("."); + @Mock File standardReporter; + @Mock + File junitXmlReporter; + ReporterRetriever subject; @Before public void setUp() throws Exception { subject = new ReporterRetriever(resourceRetriever); + when(resourceRetriever.getResourceAsFile("reporter", ReporterRetriever.STANDARD_REPORTER, mavenProject)).thenReturn(standardReporter); + when(resourceRetriever.getResourceAsFile("reporter", ReporterRetriever.JUNIT_XML_REPORTER, mavenProject)).thenReturn(junitXmlReporter); } @Test @@ -42,15 +53,45 @@ public void itShouldRetrieveReporters() throws Exception { String customReporterPath = "/foo/bar"; File customReporter = mock(File.class); when(resourceRetriever.getResourceAsFile("reporter", customReporterPath, mavenProject)).thenReturn(customReporter); - List reporters = subject.retrieveReporters(Arrays.asList("STANDARD", customReporterPath), mavenProject); + List incomingReporters = Arrays.asList(new Reporter("STANDARD"), new Reporter(customReporterPath)); + + List reporters = subject.retrieveReporters(incomingReporters, mavenProject); - assertThat(reporters, is(Arrays.asList(standardReporter, customReporter))); + assertThat(reporters, hasSize(incomingReporters.size())); + assertThat(reporters.get(0).reporterFile, is(standardReporter)); + assertThat(reporters.get(1).reporterFile, is(customReporter)); } @Test public void itShouldRetrieveStandardReporterAsDefault() throws Exception { - List reporters = subject.retrieveReporters(Collections.emptyList(), mavenProject); + List reporters = subject.retrieveReporters(new ArrayList(), mavenProject); + + assertThat(reporters, hasSize(1)); + assertThat(reporters.get(0).reporterFile, is(standardReporter)); + } + + @Test + public void itShouldRetrieveFileSystemReporters() throws Exception { + String customReporterPath = "/foo/bar"; + File customReporter = mock(File.class); + when(resourceRetriever.getResourceAsFile("reporter", customReporterPath, mavenProject)).thenReturn(customReporter); + List incomingReporters = Arrays.asList(new FileSystemReporter("TEST-file.xml", "JUNIT_XML"), new FileSystemReporter("TEST-custom.file", customReporterPath)); + + List reporters = subject.retrieveFileSystemReporters(incomingReporters, targetDir, mavenProject); + + assertThat(reporters, hasSize(incomingReporters.size())); + assertThat(reporters.get(0).reporterFile, is(junitXmlReporter)); + assertThat(reporters.get(0).file.getAbsolutePath(), new EndsWith("TEST-file.xml")); + assertThat(reporters.get(1).reporterFile, is(customReporter)); + assertThat(reporters.get(1).file.getAbsolutePath(), new EndsWith("TEST-custom.file")); + } + + @Test + public void itShouldRetrieveJUnitFileReporterAsDefault() throws Exception { + List reporters = subject.retrieveFileSystemReporters(new ArrayList(), targetDir, mavenProject); - assertThat(reporters, is(Collections.singletonList(standardReporter))); + assertThat(reporters, hasSize(1)); + assertThat(reporters.get(0).reporterFile, is(junitXmlReporter)); + assertThat(reporters.get(0).file.getAbsolutePath(), new EndsWith("TEST-jasmine.xml")); } } diff --git a/src/test/java/com/github/searls/jasmine/runner/SpecRunnerExecutorTest.java b/src/test/java/com/github/searls/jasmine/runner/SpecRunnerExecutorTest.java index 4dfcc33da..b3d54e166 100644 --- a/src/test/java/com/github/searls/jasmine/runner/SpecRunnerExecutorTest.java +++ b/src/test/java/com/github/searls/jasmine/runner/SpecRunnerExecutorTest.java @@ -1,8 +1,9 @@ package com.github.searls.jasmine.runner; import com.github.searls.jasmine.io.FileUtilsWrapper; -import com.github.searls.jasmine.io.IOUtilsWrapper; +import com.github.searls.jasmine.model.FileSystemReporter; import com.github.searls.jasmine.model.JasmineResult; +import com.github.searls.jasmine.model.Reporter; import org.apache.maven.plugin.logging.Log; import org.junit.Before; import org.junit.Test; @@ -27,8 +28,6 @@ @PrepareForTest(URL.class) public class SpecRunnerExecutorTest { - @Mock - private IOUtilsWrapper ioUtilsWrapper; @Mock private FileUtilsWrapper fileUtilsWrapper; @Mock @@ -40,6 +39,8 @@ public class SpecRunnerExecutorTest { @Mock private File junitXmlReport; @Mock + private File junitXmlReporter; + @Mock private RemoteWebDriver webDriver; private int timeout = 2; private boolean debug = false; @@ -54,18 +55,18 @@ public class SpecRunnerExecutorTest { @Before public void setUp() throws Exception { - subject = new SpecRunnerExecutor(ioUtilsWrapper, fileUtilsWrapper, webDriverWaiter, consoleErrorChecker); + subject = new SpecRunnerExecutor(fileUtilsWrapper, webDriverWaiter, consoleErrorChecker); runnerUrl = PowerMockito.mock(URL.class); when(fileUtilsWrapper.readFileToString(reporter)).thenReturn("reporter"); - when(ioUtilsWrapper.toString(SpecRunnerExecutor.CREATE_JUNIT_XML)).thenReturn("reporter"); + when(fileUtilsWrapper.readFileToString(junitXmlReporter)).thenReturn("reporter"); when(webDriver.executeScript(contains("reporter"))).thenReturn(report); } @Test public void shouldExecute() throws Exception { - JasmineResult result = subject.execute(runnerUrl, junitXmlReport, webDriver, timeout, debug, log, format, Collections.singletonList(reporter)); + JasmineResult result = subject.execute(runnerUrl, webDriver, timeout, debug, log, format, Collections.singletonList(new Reporter(reporter)), Collections.singletonList(new FileSystemReporter(junitXmlReport, junitXmlReporter))); verify(webDriver).get(runnerUrl.toString()); verify(webDriverWaiter).waitForRunnerToFinish(webDriver, timeout, debug, log); diff --git a/src/test/resources/examples/jasmine-webapp-custom-reporters/pom.xml b/src/test/resources/examples/jasmine-webapp-custom-reporters/pom.xml index 9542d2526..477c5dffb 100644 --- a/src/test/resources/examples/jasmine-webapp-custom-reporters/pom.xml +++ b/src/test/resources/examples/jasmine-webapp-custom-reporters/pom.xml @@ -25,9 +25,23 @@ - ${project.basedir}${file.separator}src${file.separator}test${file.separator}resources${file.separator}reporter.js - STANDARD + + ${project.basedir}${file.separator}src${file.separator}test${file.separator}resources${file.separator}reporter.js + + + STANDARD + + + + TEST-jasmine.log + ${project.basedir}${file.separator}src${file.separator}test${file.separator}resources${file.separator}logger.js + + + TEST-jasmine.xml + JUNIT_XML + + diff --git a/src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/resources/logger.js b/src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/resources/logger.js new file mode 100644 index 000000000..6c9d1cc6e --- /dev/null +++ b/src/test/resources/examples/jasmine-webapp-custom-reporters/src/test/resources/logger.js @@ -0,0 +1,8 @@ +var fileSystemReporter; +(function() { + fileSystemReporter = { + report: function(reporter, debug) { + return window.exampleTest; + } + }; +})();