All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.searls.jasmine.mojo.AbstractJasmineMojo Maven / Gradle / Ivy

Go to download

A JavaScript unit test plugin that processes JavaScript sources and Jasmine specs, prepares test runner HTML files, executes Jasmine specs headlessly with HtmlUnit, and produces JUnit XML reports

There is a newer version: 3.0-beta-02
Show newest version
package com.github.searls.jasmine.mojo;

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.ScriptSearch;
import com.github.searls.jasmine.runner.SpecRunnerTemplate;
import com.github.searls.jasmine.thirdpartylibs.ProjectClassLoaderFactory;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

	/**
	 * Directory storing your JavaScript.
	 * @since 1.1.0
	 */
	@Parameter(
			property="jsSrcDir",
			defaultValue="${project.basedir}${file.separator}src${file.separator}main${file.separator}javascript")
	private File jsSrcDir;

	/**
	 * Directory storing your Jasmine Specs.
	 * @since 1.1.0
	 */
	@Parameter(
			property="jsTestSrcDir",
			defaultValue="${project.basedir}${file.separator}src${file.separator}test${file.separator}javascript")
	private File jsTestSrcDir;

	/**
	 * Determines the Selenium WebDriver class we'll use to execute the tests. See the Selenium documentation for more details.
	 * The plugin uses HtmlUnit by default.
	 *
	 * 

Some valid examples:

*
    *
  • org.openqa.selenium.htmlunit.HtmlUnitDriver
  • *
  • org.openqa.selenium.phantomjs.PhantomJSDriver
  • *
  • org.openqa.selenium.firefox.FirefoxDriver
  • *
  • org.openqa.selenium.ie.InternetExplorerDriver
  • *
*

* For org.openqa.selenium.phantomjs.PhantomJSDriver, see the webDriverCapabilities property. * * @since 1.1.0 */ @Parameter(defaultValue="org.openqa.selenium.htmlunit.HtmlUnitDriver") protected String webDriverClassName; /** *

Web driver capabilities used to initialize a DesiredCapabilities instance when creating a web driver.

* *

Capabilities value can be either a String, a List, or a Map.

* *

Example:

*
   * <webDriverCapabilities>
   *   <capability>
   *     <name>phantomjs.binary.path</name>
   *     <value>/opt/phantomjs/bin/phantomjs</value>
   *   </capability>
   *   <capability>
   *     <name>phantomjs.cli.args</name>
   *     <list>
   *       <value>--disk-cache=true</value>
   *       <value>--max-disk-cache-size=256</value>
   *     </list>
   *   </capability>
   *   <capability>
   *     <name>proxy</name>
   *     <map>
   *       <httpProxy>myproxyserver.com:8000</httpProxy>
   *     </map>
   *   </capability>
   * </webDriverCapabilities>
   * 
* * @since 1.3.1.1 */ @Parameter protected List webDriverCapabilities = Collections.emptyList(); /** *

Determines the browser and version profile that HtmlUnit will simulate. This setting does nothing if the plugin is configured not to use HtmlUnit. * This maps 1-to-1 with the public static instances found in {@link com.gargoylesoftware.htmlunit.BrowserVersion}.

* *

Some valid examples: CHROME, FIREFOX_17, INTERNET_EXPLORER_9, INTERNET_EXPLORER_10

* * @since 1.1.0 */ @Parameter(defaultValue="FIREFOX_17") protected String browserVersion; /** *

Determines the format that jasmine:test will print to console.

*

Valid options:

*
    *
  • "documentation" - (default) - print specs in a nested format
  • *
  • "progress" - more terse, with a period for a passed specs and an 'F' for failures (e.g. '...F...')
  • *
* * @since 1.1.0 */ @Parameter(defaultValue="documentation") protected String format; /** *

JavaScript sources (typically vendor/lib dependencies) that need to be loaded * before other sources (and specs) in a particular order. Each source will first be * searched for relative to ${jsSrcDir}, then ${jsTestSrcDir}, * then (if it's not found in either) it will be included exactly as it appears in your POM.

* *

Therefore, if jquery.js is in ${jsSrcDir}/vendor, you would configure:

*
	 * <preloadSources>
	 *   <source>vendor/jquery.js</source>
	 * </preloadSources>
	 * 
* *

And jquery.js would load before all the other sources and specs.

* * @since 1.1.0 */ @Parameter protected List preloadSources; /** *

It may be the case that the jasmine-maven-plugin doesn't currently suit all of your needs, * and as a result the generated SpecRunner HTML files are set up in a way that you can't run * your specs. Have no fear! Simply specify a custom spec runner template in the plugin configuration * and make the changes you need.

* *

Potential values are a filesystem path, a URL, or a classpath resource. The default template is * stored in src/main/resources/jasmine-templates/SpecRunner.htmltemplate, and the * required template strings are tokenized in "$*$" patterns.

* *

Example usage:

*
	 * <customRunnerTemplate>${project.basedir}/src/test/resources/myCustomRunner.template</customRunnerTemplate>
	 * 
* * @since 1.1.0 */ @Parameter protected String customRunnerTemplate; /** *

Sometimes you want to have full control over how scriptloaders are configured. In order to * interpolate custom configuration into the generated runnerTemplate, specify a file containing * the additional config. Potential values are a filesystem path, a URL, or a classpath resource.

* *

Example usage:

*
	 * <customRunnerConfiguration>${project.basedir}/src/test/resources/myCustomConfig.txt</customRunnerConfiguration>
	 * 
* * @since 1.1.0 */ @Parameter protected String customRunnerConfiguration; /** * Target directory for files created by the plugin. * * @since 1.1.0 */ @Parameter(defaultValue="${project.build.directory}${file.separator}jasmine") protected File jasmineTargetDir; /** * Skip execution of tests. * * @since 1.1.0 * @see http://maven.apache.org/general.html#skip-test */ @Parameter(property="skipTests") protected boolean skipTests; /** * Skip compilation and execution of tests. * * @since 1.3.1.3 * @see http://maven.apache.org/general.html#skip-test */ @Parameter(property="maven.test.skip") protected boolean mvnTestSkip; /** * Skip only jasmine tests * * @since 1.3.1.3 */ @Parameter(property="skipJasmineTests") protected boolean skipJasmineTests; /** * Halt the build on test failure. * * @since 1.1.0 */ @Parameter(property="haltOnFailure", defaultValue="true") protected boolean haltOnFailure; /** * Timeout for spec execution in seconds. * * @since 1.1.0 */ @Parameter(defaultValue="300") protected int timeout; /** * True to increase HtmlUnit output and attempt reporting on specs even if a timeout occurred. * * @since 1.1.0 */ @Parameter(defaultValue="false") protected boolean debug; /** * The name of the Spec Runner file. * * @since 1.1.0 */ @Parameter(defaultValue="SpecRunner.html") protected String specRunnerHtmlFileName; /** * The name of the Manual Spec Runner. * * @since 1.1.0 */ @Parameter(defaultValue="ManualSpecRunner.html") protected String manualSpecRunnerHtmlFileName; /** * The name of the generated JUnit XML report. * * @since 1.1.0 */ @Parameter(defaultValue="TEST-jasmine.xml") protected String junitXmlReportFileName; /** * The name of the directory the specs will be deployed to on the server. * * @since 1.1.0 */ @Parameter(defaultValue="spec") protected String specDirectoryName; /** * The name of the directory the sources will be deployed to on the server. * * @since 1.1.0 */ @Parameter(defaultValue="src") protected String srcDirectoryName; /** * The source encoding. * * @since 1.1.0 */ @Parameter(defaultValue="${project.build.sourceEncoding}") protected String sourceEncoding; /** * 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. * * @since 1.3.1.0 */ @Parameter(property="keepServerAlive", defaultValue="false") protected boolean keepServerAlive; /** *

Allows specifying which source files should be included and in what order.

*
	 * <sourceIncludes>
	 *   <include>vendor/**/*.js</include>
	 *   <include>myBootstrapFile.js</include>
	 *   <include>**/*.js</include>
	 *   <include>**/*.coffee</include>
	 * </sourceIncludes>
	 * 
* *

Default sourceIncludes:

*
	 * <sourceIncludes>
	 *   <include>**/*.js</include>
	 *   <include>**/*.coffee</include>
	 * </sourceIncludes>
	 * 
* * @since 1.1.0 */ @Parameter private final List sourceIncludes = ScansDirectory.DEFAULT_INCLUDES; /** *

Just like sourceIncludes, but will exclude anything matching the provided patterns.

*

There are no sourceExcludes by default.

* * @since 1.1.0 */ @Parameter private final List sourceExcludes = Collections.emptyList(); /** *

I often find myself needing control of the spec include order * when I have some global spec helpers or spec-scoped dependencies, like:

*
	 * <specIncludes>
	 *   <include>jasmine-jquery.js</include>
	 *   <include>spec-helper.js</include>
	 *   <include>**/*.js</include>
	 *   <include>**/*.coffee</include>
	 * </specIncludes>
	 * 
* *

Default specIncludes:

*
	 * <specIncludes>
	 *   <include>**/*.js</include>
	 *   <include>**/*.coffee</include>
	 * </specIncludes>
	 * 
* * @since 1.1.0 */ @Parameter private final List specIncludes = ScansDirectory.DEFAULT_INCLUDES; /** *

Just like specIncludes, but will exclude anything matching the provided patterns.

*

There are no specExcludes by default.

* * @since 1.1.0 */ @Parameter private final List specExcludes = Collections.emptyList(); /** *

Used by the jasmine:bdd goal to specify port to run the server under.

* *

The jasmine:test goal always uses a random available port so this property is ignored.

* * @since 1.1.0 */ @Parameter(property="jasmine.serverPort", defaultValue="8234") protected int serverPort; /** *

Specify the URI scheme in which to access the SpecRunner.

* * @since 1.3.1.4 */ @Parameter(property="jasmine.uriScheme", defaultValue="http") protected String uriScheme; /** *

Not used by the jasmine:bdd goal.

* *

The jasmine:test goal to specify hostname where the server is running. Useful when using * the RemoteWebDriver.

* * @since 1.3.1.4 */ @Parameter(property="jasmine.serverHostname", defaultValue = "localhost") protected String serverHostname; /** *

Determines the strategy to use when generation the JasmineSpecRunner. This feature allows for custom * implementation of the runner generator. Typically this is used when using different script runners.

* *

Some valid examples: DEFAULT, REQUIRE_JS

* * @since 1.1.0 */ @Parameter(property="jasmine.specRunnerTemplate", defaultValue="DEFAULT") protected SpecRunnerTemplate specRunnerTemplate; /** *

Path to loader script, relative to jsSrcDir. Defaults to jsSrcDir/nameOfScript.js. Which script to look for is determined by * the selected spcRunnerTemplate. I.e require.js is used when REQUIRE_JS is selected as specRunnerTemplate.

* * @since 1.1.0 * @deprecated Specify script loader path using the preloadSources parameter instead. */ @Parameter @Deprecated protected String scriptLoaderPath; /** *

Automatically refresh the test runner at the given interval (specified in seconds) when using the jasmine:bdd goal.

*

A value of 0 disables the automatic refresh (which is the default).

* * @since 1.3.1.1 */ @Parameter(property="jasmine.autoRefreshInterval", defaultValue="0") protected int autoRefreshInterval; /** *

Control the Coffee Script compilation. e.g. When using RequireJS the compilation * happens within the Coffee Script AMD loader plugin; we therefore need to disable the * compilation here.

* * @since 1.3.1.4 */ @Parameter(property="coffeeScriptCompilationEnabled", defaultValue="true") protected boolean coffeeScriptCompilationEnabled; /** *

Type of {@link org.eclipse.jetty.server.Connector} to use on the jetty server.

* *

Most users won't need to change this from the default value. It should only be used * by advanced users.

* * @since 1.3.1.4 */ @Parameter( property="jasmine.connectorClass", defaultValue="org.eclipse.jetty.server.nio.SelectChannelConnector" ) protected String connectorClass; /** *

Specify additional contexts to make available.

*
   * <additionalContexts>
   *   <context>
   *     <contextRoot>lib</contextRoot>
   *     <directory>${project.basedir}/src/main/lib</directory>
   *   </context>
   *   <context>
   *     <contextRoot>test/lib</contextRoot>
   *     <directory>${project.basedir}/src/test/lib</directory>
   *   </context>
   * </additionalContexts>
   * 
* * @since 1.3.1.5 */ @Parameter private List additionalContexts = Collections.emptyList(); @Parameter(defaultValue="${project}", readonly=true) protected MavenProject mavenProject; @Component protected ResourceManager locator; protected ScriptSearch sources; protected ScriptSearch specs; protected StringifiesStackTraces stringifiesStackTraces = new StringifiesStackTraces(); private File customRunnerTemplateFile; private File customRunnerConfigurationFile; @Override public void execute() throws MojoExecutionException, MojoFailureException { this.loadResources(); this.sources = new ScriptSearch(this.jsSrcDir,this.sourceIncludes,this.sourceExcludes); this.specs = new ScriptSearch(this.jsTestSrcDir,this.specIncludes,this.specExcludes); try { this.run(); } catch(MojoFailureException e) { throw e; } catch(Exception e) { throw new MojoExecutionException("The jasmine-maven-plugin encountered an exception: \n"+this.stringifiesStackTraces.stringify(e),e); } } public abstract void run() throws Exception; @Override public String getSourceEncoding() { return this.sourceEncoding; } @Override public File getCustomRunnerTemplate() { return this.customRunnerTemplateFile; } @Override public SpecRunnerTemplate getSpecRunnerTemplate() { return this.specRunnerTemplate; } @Override public File getJasmineTargetDir() { return this.jasmineTargetDir; } @Override public String getSrcDirectoryName() { return this.srcDirectoryName; } @Override public ScriptSearch getSources() { return this.sources; } @Override public ScriptSearch getSpecs() { return this.specs; } @Override public String getSpecDirectoryName() { return this.specDirectoryName; } @Override public List getPreloadSources() { this.addRequireJsIfNecessary(); // This is temporary until the scriptLoaderPath parameter is removed return this.preloadSources; } private void addRequireJsIfNecessary() { String scriptLoaderPath = this.getScriptLoaderPath() == null ? "require.js" : this.getScriptLoaderPath(); String requireJsPath = String.format("%s/%s", this.jsSrcDir, scriptLoaderPath); if (SpecRunnerTemplate.REQUIRE_JS.equals(this.specRunnerTemplate)) { File requireJsFile = new File(requireJsPath); if (requireJsFile.exists()) { if (this.preloadSources == null) { this.preloadSources = new ArrayList(); } this.preloadSources.add(requireJsPath); } } } @Override public int getAutoRefreshInterval() { return this.autoRefreshInterval; } @Override public boolean isCoffeeScriptCompilationEnabled() { return this.coffeeScriptCompilationEnabled; } public MavenProject getMavenProject() { return this.mavenProject; } @Override public File getCustomRunnerConfiguration() { return this.customRunnerConfigurationFile; } @Deprecated @Override public String getScriptLoaderPath() { return this.scriptLoaderPath; } @Override public File getBasedir() { return this.mavenProject.getBasedir(); } @Override public ClassLoader getProjectClassLoader() { return new ProjectClassLoaderFactory(mavenProject.getArtifacts()).create(); } @Override public List getContexts() { List contexts = new ArrayList(); contexts.add(new Context(this.srcDirectoryName, this.jsSrcDir)); contexts.add(new Context(this.specDirectoryName, this.jsTestSrcDir)); contexts.addAll(additionalContexts); return contexts; } protected Connector getConnector() throws MojoExecutionException { try { @SuppressWarnings("unchecked") Class c = (Class) Class.forName(connectorClass); return c.newInstance(); } catch(InstantiationException e) { throw new MojoExecutionException("Unable to instantiate.",e); } catch (IllegalAccessException e) { throw new MojoExecutionException("Unable to instantiate.",e); } catch (ClassNotFoundException e) { throw new MojoExecutionException("Unable to instantiate.",e); } } protected boolean isSkipTests() { return this.skipTests || this.mvnTestSkip || this.skipJasmineTests; } private void loadResources() throws MojoExecutionException { this.customRunnerTemplateFile = this.getResourceAsFile("customRunnerTemplate", this.customRunnerTemplate); this.customRunnerConfigurationFile = this.getResourceAsFile("customRunnerConfiguration", this.customRunnerConfiguration); } 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 ); } } return file; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy