Skip to content

Instantly share code, notes, and snippets.

@isuftin
Last active December 19, 2017 13:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save isuftin/553d83378f8cee112e0d to your computer and use it in GitHub Desktop.
Save isuftin/553d83378f8cee112e0d to your computer and use it in GitHub Desktop.
Combining RequireJS, Jasmine, Webjars and the maven-jasmine plugin to create clean, testable and maintainable javascript

Main Goal: To create a WAR packaged using Maven that takes advantage of javascript libraries using WebJars that is tested using Jasmine and have that javascript loaded using RequireJS.

Project Repository: https://github.com/isuftin/amd-jasmine-mvn/

For a while I've had the itch to learn RequireJS. Working in a primarily Java/Maven shop, the applications I write using RequireJS would be tested and packaged into WARs using Maven and run on Tomcat containers. I chose to use Jasmine since we are using it pretty heavily throughout our projects. I needed the project to test my javascript in the test phase as I build it. I also wanted to be able to run my project and view my tests in a browser. All of the third party javascript I will use will either be coming in as dependencies from the WebJars project or a CDN. During the building of the project, I need to be able to automate all of the javascript testing so it can be done by our continuous integration solution.

Building The Application

The prototypeis a Java web application that is packaged into a WAR using Maven and run on a Tomcat container. It uses Jersey as the JAX-RS implementation. During the Maven testing phase, Jasmine testing is performed against RequireJS modules I create. I also include a way to run these tests while running the application if you want.

I won't go into the Jersey configuration for the project here since using Jersey is optional and I only include it because we, as a development shop, have been making heavy use of it and other developers in our shop that use this project as a prototype may find it convenient.

I also won't touch much on working with RequireJS itself (structure, syntax, etc). RequireJS is very well documented already.

Goal 1: Load a web page that loads RequireJS and runs some user-defined require modules.

Version Declaration

To get started, I want to write a few RequireJS modules and use Jasmine to test them in the browser.

One of the issues that we run into in every one of our WebJars applications is the handling of versioning. Versions are included in the paths for WebJars libraries. For example, if I want to load JQuery version 2.1.4, my script tag has to look something like <script src="webjars/jquery/2.1.4/jquery.js"></script>. The obvious problem is that if you use this declaration in multiple pages in your application, it makes it increasingly difficult to switch out to another version of JQuery. You now have to go into each page you've declared JQuery in and change it. As your application grows more complex, this becomes a headache.

We solve this by declaring the version in the Maven pom.xml using Maven properties. At the top of the pom, I assign versions to every WebJars library I pull into the project.

The Maven properties I defined:

<properties>
  <version.jquery>2.1.4</version.jquery>
  <version.require>2.1.18</version.require>
  <version.jasmine>2.2.0</version.jasmine>
</properties>

As you can see, I've defined the versions for the three libraries I will be pulling in via WebJars.

In the <dependency> section of the pom, I use those properties to define the version for each depedency like so:

<dependencies>
  [...]
  <dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>${version.jquery}</version>
  </dependency>
  <dependency>
    <groupId>org.webjars</groupId>
    <artifactId>requirejs</artifactId>
    <version>${version.require}</version>
  </dependency>
  <dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jasmine</artifactId>
    <version>${version.jasmine}</version>
  </dependency>
  [...]
</dependencies>

When I want to change the version of any of my WebJars dependencies, I just change the version number in the Maven property and rebuild the project.

Using dynamic versioning in JSP

But how does this solve changing the version in the script tag in my rendered HTML? I employ Maven filtering against a properties file along with JSP server-side rendering. When a JSP loads, I first read in a properties file with a map of library name to version number and inject that into the HTML for my script tags.

I first create a properties file in the /src/main/resources path that has keys matching those of the maven properties I've created and the values are Maven tokens that will be replaced during build time in the Maven compile phase. An example looks like this:

version.jquery=${version.jquery}
version.require=${version.require}
version.jasmine=${version.jasmine}

When compiled, the properties file looks like:

version.jquery=2.1.4
version.require=2.1.18
version.jasmine=2.2.0

In the index.jsp, I read in the properties file using an in-house, but publically available file reader which allows me to fill a Properties object with the contents of the transformed properties file. You are, of course, free to use whatever method you like to pull string values from a properties file.

I then use those property values in my script tags:

<%@page import="gov.usgs.cida.config.DynamicReadOnlyProperties"%>
<%@page import="java.io.File"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%!	protected DynamicReadOnlyProperties props = new DynamicReadOnlyProperties();

	{
		try {
			File propsFile = new File(getClass().getClassLoader().getResource("application.properties").toURI());
			props = new DynamicReadOnlyProperties(propsFile);
			props = props.addJNDIContexts(new String[0]);
		} catch (Exception e) {
			System.out.println("Could not find JNDI - Application will probably not function correctly");
		}
	}

	private String getProp(String key) {
		String result = props.getProperty(key, "");
		return result;
	}
%>
<%
	ServletContext ctx = request.getServletContext();
	String contextPath = props.getProperty("application.context", ctx.getContextPath());
%>
  [...]
		<script data-main="scripts/main" src="<%=contextPath%>/webjars/requirejs/<%= getProp("version.require") %>/require.js"></script>
  [...]

Also notice that I am including the context path in the script tag. This allows me to deploy the application with a configured JNDI variable or default to the context path in the request. This is useful when the application is sitting behind a proxy which may change the name of the application from the context it is deployed under. You may be confused as to how I am picking up JNDI properties using my properties file reader. The DynamicProperties utility library I use to read the properties file also reads JNDI variable and merges them with other properties it already has. If I've defined the application.context JNDI property, it will be used as the context path. Otherwise, I depend on the servlet context to feed me the correct context path.

The result in HTML looks like:

[...]
<script data-main="scripts/main" src="/amd-jasmine-mvn/webjars/requirejs/2.1.18/require.js"></script>
[...]

I also use this same pattern to create the require configuration to define a base URL as well as define the jquery dependency I use in my modules:

[...]
<script>
  require.config({
    baseUrl: "<%=contextPath%>/scripts/",
    paths: {
      "jquery": "<%=contextPath%>/webjars/jquery/<%= getProp("version.jquery") %>/jquery"
    }
  });
</script>
[...]

From the requirejs declaration and the configuration we can see that require will first load the main.js file in the scripts/ subdirectory. main.js depends on JQuery and printer.js inside of the scripts/messages/ subdirectory and printer.js depends on messages.js inside of the same directory. When loaded in the browser, the order of loaded modules should be:

  1. require.js
  2. main.js
  3. jquery.js
  4. printer.js
  5. messages.js

I now compile my project, deploy it to a Tomcat container and load it in a browser. I configured Jersey to serve the index.jsp at the /ui context, so I point my browser at http://localhost:8080/amd-jasmine-mvn/ui and the result is a simple Hello World display. If I go into Chrome's developer tools, I make sure that the scripts are loaded as expected and sure enough, they are:

script ordering

Also, my main.js require module calls a function in printer to print a message to the console, so in developer tools I make sure that happened and sure enough, it did:

console message

Using only Maven filtering, I am now able to use WebJars to pull in RequireJS as well as other third party libraries and easily use them in my project.

Goal 2: Run in-browser Jasmine tests against the existing RequireJS modules using RequireJS to bootstrap the testing

Now that I have RequireJS running in my project, I want to be be able to test my javascript using Jasmine. I will ultimately be doing this using the jasmine-maven plugin, but first I want to just be able to load a JSP in the browser and get immediate feedback that my tests are running. Jasmine is also loaded through WebJars dependencies.

I create a JSP called SpecRunner.jsp under /src/main/webapp/test. This JSP mimics a lot of the functionality that the index.jsp performs in the previous section. However, it also adds the Jasmine libraries to RequireJS and uses RequireJS to bootstrap the testing.

I added the Jasmine CSS file in the <head> section of the JSP (note the use of context paths and properties again. This is a recurring pattern throughout most of our JSPs). All of the Jasmine content (jasmine, jasmine-boot, jasmine0html, css, etc) is provided via WebJars:

[...]
<link rel="shortcut icon" type="image/png" href="<%=contextPath%>/webjars/jasmine/<%=getProp("version.jasmine")%>/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="<%=contextPath%>/webjars/jasmine/<%=getProp("version.jasmine")%>/jasmine.css">
[...]

I changed the entry point in require to point to jasmine-entry.js:

[...]
<script data-main="jasmine-entry" src="<%=contextPath%>/webjars/requirejs/<%=getProp("version.require")%>/require.js"></script>
[...]

I also add the requisite jasmine libraries to RequireJS to map as named dependencies:

[...]
<script>
			require.config({
				baseUrl: '<%=contextPath%>/scripts',in
				paths: {
					'jasmine-entry': ['<%=contextPath%>/test/jasmine-entry'],
					'jasmine': ['<%=contextPath%>/webjars/jasmine/<%=getProp("version.jasmine")%>/jasmine'],
					'jasmine-html': ['<%=contextPath%>/webjars/jasmine/<%=getProp("version.jasmine")%>/jasmine-html'],
					'jasmine-boot': ['<%=contextPath%>/webjars/jasmine/<%=getProp("version.jasmine")%>/boot'],
					'jquery': ["<%=contextPath%>/webjars/jquery/<%= getProp("version.jquery")%>/jquery"]
				},
				shim: {
					'jasmine-html': {
						deps: ['jasmine']
					},
					'jasmine-boot': {
						deps: ['jasmine', 'jasmine-html']
					}
				}
			});
		</script>
[...]

If you take a peek at jasmine-entry.js, you'll notice that this is where I define all of the test specs that I intend to run and wrap that inside of a "jasmine-boot" requirement:

require(['jasmine-boot'], function () {
	require([
		'spec/messages/messages-spec.js',
		'spec/messages/printer-spec.js',
		'spec/utility/extend-spec.js'
	], function () {
		//trigger Jasmine
		window.onload();
	});
});

Jasmine's boot.js is new under version 2.0 of Jasmine and performs all needed initialization steps required to run our specs. It's included with the WebJars Jasmine dependency. It responds to the window.onload() event and that's why that's the only function called in my jasmine-entry module. Jasmine boot will then run my specs in the order defined in the require block leading into the module's function.

The specs I wrote are very light and just serve as confirmation that everything loaded correctly for RequireJS and Jasmine.

I can now compile my project, point my browser to http://localhost:8080/amd-jasmine-mvn/test/SpecRunner.jsp and verify that Jasmine has loaded and all of my tests pass:

in browser jasmine

Cool! So now we are able to load RequireJS and using RequireJS, we can load and run Jasmine tests.

Of course, in practice I will never load my tests through a JSP. Our tests will usually be run using the jasmine-maven plugin either during the test phase of project compilation or I can run the jasmine:bdd goal to run in-browser tests. Creating the SpecRunner.jsp is just a proof of concept, so we'll move on.

Goal 3: Run Jasmine tests during Maven project compilation, failing the build if any tests fail and finishing the build if all tests pass

Ultimately, this is the goal that I set out to achieve since this allows us to check-in javascript code changes and have our continuous integration fail the build if we have errors in our javascript tests.

The key piece in this puzzle is using the jasmine-maven plugin as part of our build process. This plugin will run Jasmine tests against your javascript by starting a Jetty servlet container in the test phase and using PhantomJS to run the tests and report back to the plugin whether all tests have passed or if there are any failures. By default, if there are any failures, the build will fail. At the end of the test phase, the Jetty server is shut down.

The first step is to include the jasmine-maven plugin in the <plugins> section of the pom.xml:

<build>
	<plugins>
		[...]
		<plugin>
			<groupId>com.github.searls</groupId>
			<artifactId>jasmine-maven-plugin</artifactId>
			<version>2.0-beta-02</version>
			<executions>
				<execution>
					<goals>
						<goal>test</goal>
					</goals>
				</execution>
			</executions>
			<configuration>
				<debug>true</debug>
				<specRunnerTemplate>REQUIRE_JS</specRunnerTemplate>
				<jsSrcDir>${project.basedir}/src/main/webapp/scripts</jsSrcDir>
				<jsTestSrcDir>${project.basedir}/src/main/webapp/test/spec</jsTestSrcDir>
				<customRunnerConfiguration>${project.build.directory}/test-classes/customJasmineConfig.txt</customRunnerConfiguration>
				<srcDirectoryName>scripts</srcDirectoryName>
				<preloadSources>
					<source>/webjars/requirejs/${version.require}/require.js</source>
				</preloadSources>
			</configuration>
		</plugin>
	</plugins>
</build>

Plugin Configuration Settings <debug> Setting debug to true provides extra output in the console to give us extra information should we need it. I keep this on all the time since it never hurts to have it and not need it rather than the alternative.

<specRunnerTemplate> The jasmine-maven plugin actually comes with templating for RequireJS which will automatically create a SpecRunner.html that it loads so we don't have to worry about writing our own like we did in the previous section. In order to make that happen, the plugin is configured to use the REQUIRE_JS specRunnerTemplate. More information about that and other templates can be found at the plugin's documentation site.

<customRunnerConfiguration> We can configure the RequireJS SpecRunner template a bit by passing custom configuration in a text file defined in the <customRunnerConfiguration> configuration node.

In our case, we create a text file at /test-classes/customJasmineConfig.txt:

baseUrl: 'scripts',
paths: {
  'jquery': ['/webjars/jquery/${version.jquery}/jquery']
}

Notice that we are using maven tokens here as well and this file is filtered during the test phase to include the correct version of js dependencies. Also notice that this file is much simpler than the require block we used for our SpecRunner.jsp. That's because most of the heavy lifting is done by the jasmine-maven plugin when creating the SpecRunner.html. The pom.xml <build> section includes the filtering directive to run during test:

<testResources>
  <testResource>
    <directory>${project.basedir}/src/test/resources</directory>
    <filtering>true</filtering>
  </testResource>
</testResources>

The final file looks like:

baseUrl: 'scripts',
paths: {
  'jquery': ['/webjars/jquery/2.1.4/jquery']
}

<preloadSources> We want to tell the jasmine-maven plugin to load our own RequireJS. We define that in the preloadSources node. When the SpecRunner.html is written out, it uses the RequireJS from our WebJar. This functionality is provided by the jasmine-maven plugin once they implemented WebJars support.

<jsTestSrcDir> Using the jsTestSrcDir configuration, we tell the application where all of our test specs live. Any javascript files the plugin finds in this folder it will run as Jasmine specs. If you have a keen eye, you will notice that I placed the specs one folder deeper within /test/ inside of the /test/spec directory. The reason for this is that if I didn't, the plugin would try to load jasmine-entry.js as a spec. This breaks the build. In practice, I probably wouldn't have a jasmine-entry.js file and I would move the spec folder up one level and remove SpecRunner.jsp. Also note that spec is the default name of the folder the plugin will look in for specs.

<jsSrcDir> and <srcDirectoryName> jsSrcDir sets the requireJs base url. I set this to the root scripts directory in the web application. Setting the srcDirectoryName defines where in the web application the js source will be deployed to. By default, both of these are src so I update these accordingly to reflect my directory structure.

Other than defining the plugin in my pom and adding the customJasmineConfig.txt, I've made no other changes to the application. I can now try to build the application to ensure that it runs my tests and builds properly.

$ cd ${APP_DIR}
$ mvn clean install

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building amd-jasmine-mvn 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[...]
[INFO] --- jasmine-maven-plugin:2.0-beta-02:test (default) @ amd-jasmine-mvn ---
[INFO] jetty-8.1.14.v20131031
[INFO] Started SelectChannelConnector@0.0.0.0:54445
[INFO] Executing Jasmine Specs
[INFO] Resolved artifact /Users/isuftin/.m2/repository/com/github/klieber/phantomjs/2.0.0/phantomjs-2.0.0-macosx-fix01.zip from central (https://repo.maven.apache.org/maven2, default, releases)
[INFO] Extracting /Users/isuftin/.m2/repository/com/github/klieber/phantomjs/2.0.0/phantomjs-2.0.0-macosx-fix01.zip/phantomjs-2.0.0-macosx-fix01/bin/phantomjs to /Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/target/phantomjs/phantomjs-2.0.0-macosx-fix01/bin/pha
ntomjs
Jul 12, 2015 12:28:46 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: executable: /Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/target/phantomjs/phantomjs-2.0.0-macosx-fix01/bin/phantomjs
Jul 12, 2015 12:28:46 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: port: 47298
Jul 12, 2015 12:28:46 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: arguments: [--webdriver=47298, --webdriver-logfile=/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/phantomjsdriver.log]
Jul 12, 2015 12:28:46 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: environment: {}
[INFO  - 2015-07-12T17:28:46.886Z] GhostDriver - Main - running on port 47298
[INFO  - 2015-07-12T17:28:47.249Z] Session [73db85b0-28bb-11e5-8af4-cd3b4c964e7c] - page.settings - {"XSSAuditingEnabled":false,"javascriptCanCloseWindows":true,"javascriptCanOpenWindows":true,"javascriptEnabled":true,"loadImages":true,"localToRemoteUrlAccessEnabled":fa
lse,"userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.0.0 Safari/538.1","webSecurityEnabled":true}
[INFO  - 2015-07-12T17:28:47.249Z] Session [73db85b0-28bb-11e5-8af4-cd3b4c964e7c] - page.customHeaders:  - {}
[INFO  - 2015-07-12T17:28:47.249Z] Session [73db85b0-28bb-11e5-8af4-cd3b4c964e7c] - Session.negotiatedCapabilities - {"browserName":"phantomjs","version":"2.0.0","driverName":"ghostdriver","driverVersion":"1.2.0","platform":"mac-10.9 (Mavericks)-64bit","javascriptEnable
d":true,"takesScreenshot":true,"handlesAlerts":false,"databaseEnabled":false,"locationContextEnabled":false,"applicationCacheEnabled":false,"browserConnectionEnabled":false,"cssSelectorsEnabled":true,"webStorageEnabled":false,"rotatable":false,"acceptSslCerts":false,"na
tiveEvents":true,"proxy":{"proxyType":"direct"}}
[INFO  - 2015-07-12T17:28:47.249Z] SessionManagerReqHand - _postNewSessionCommand - New Session Created: 73db85b0-28bb-11e5-8af4-cd3b4c964e7c
[INFO  - 2015-07-12T17:28:47.782Z] ShutdownReqHand - _handle - About to shutdown
[INFO]
-------------------------------------------------------
 J A S M I N E   S P E C S
-------------------------------------------------------
[INFO]
messages
  getMessage
    should greet us with a specific message

printer
  printMessage
    should return true

extend
  deepExtend
    should properly extend one object with another
    should not mutate incoming parameters
    should throw an exception when provided a null or undefined object

Results: 5 specs, 0 failures, 0 pending

[INFO] stopped o.e.j.s.h.ContextHandler{/webjars,file:/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/}
[INFO] stopped o.e.j.s.h.ContextHandler{/classpath,file:/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/}
[INFO] stopped o.e.j.s.h.ContextHandler{/,file:/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/}
[INFO] stopped o.e.j.s.h.ContextHandler{/spec,file:/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/}
[INFO] stopped o.e.j.s.h.ContextHandler{/scripts,file:/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/}
[...]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 9.951 s
[INFO] Finished at: 2015-07-12T12:28:49-05:00
[INFO] Final Memory: 30M/322M
[INFO] ------------------------------------------------------------------------

Great, it worked! 5 of my tests passed as they did in-browser.

We can also run the tests without recompiling the project by running the jasmine:test goal.

Also, we can still test in-browser by running the jasmine:bdd goal:

$  mvn jasmine:bdd
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building amd-jasmine-mvn 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- jasmine-maven-plugin:2.0-beta-02:bdd (default-cli) @ amd-jasmine-mvn ---
[INFO] jetty-8.1.14.v20131031
[INFO] Started SelectChannelConnector@0.0.0.0:8234
[INFO]

Server started--it's time to spec some JavaScript! You can run your specs as you develop by visiting this URL in a web browser:

 http://localhost:8234

The server will monitor these two directories for scripts that you add, remove, and change:

  source directory: src/main/webapp/scripts

  spec directory: src/main/webapp/test/spec

Just leave this process running as you test-drive your code, refreshing your browser window to re-run your specs. You can kill the server with Ctrl-C when you're done.

Now we can point the browser to the address provided: Maven in browser testing

Excellent, it works!

Now, just to make sure that this is working properly, I will change one of the tests to force a failure and verify that my tests do, in fact, fail when the plugin runs them:

$ mvn jasmine:test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building amd-jasmine-mvn 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- jasmine-maven-plugin:2.0-beta-02:test (default-cli) @ amd-jasmine-mvn ---
[INFO] jetty-8.1.14.v20131031
[INFO] Started SelectChannelConnector@0.0.0.0:54494
[INFO] Executing Jasmine Specs
Jul 12, 2015 12:36:22 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: executable: /Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/target/phantomjs/phantomjs-2.0.0-macosx-fix01/bin/phantomjs
Jul 12, 2015 12:36:22 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: port: 15923
Jul 12, 2015 12:36:22 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: arguments: [--webdriver=15923, --webdriver-logfile=/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/phantomjsdriver.log]
Jul 12, 2015 12:36:22 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: environment: {}
[INFO  - 2015-07-12T17:36:22.506Z] GhostDriver - Main - running on port 15923
[INFO  - 2015-07-12T17:36:22.983Z] Session [837f2a20-28bc-11e5-b12e-bf0d9bf8a2cf] - page.settings - {"XSSAuditingEnabled":false,"javascriptCanCloseWindows":true,"javascriptCanOpenWindows":true,"javascriptEnabled":true,"loadImages":true,"localToRemoteUrlAccessEnabled":fa
lse,"userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.0.0 Safari/538.1","webSecurityEnabled":true}
[INFO  - 2015-07-12T17:36:22.983Z] Session [837f2a20-28bc-11e5-b12e-bf0d9bf8a2cf] - page.customHeaders:  - {}
[INFO  - 2015-07-12T17:36:22.983Z] Session [837f2a20-28bc-11e5-b12e-bf0d9bf8a2cf] - Session.negotiatedCapabilities - {"browserName":"phantomjs","version":"2.0.0","driverName":"ghostdriver","driverVersion":"1.2.0","platform":"mac-10.9 (Mavericks)-64bit","javascriptEnable
d":true,"takesScreenshot":true,"handlesAlerts":false,"databaseEnabled":false,"locationContextEnabled":false,"applicationCacheEnabled":false,"browserConnectionEnabled":false,"cssSelectorsEnabled":true,"webStorageEnabled":false,"rotatable":false,"acceptSslCerts":false,"na
tiveEvents":true,"proxy":{"proxyType":"direct"}}
[INFO  - 2015-07-12T17:36:22.983Z] SessionManagerReqHand - _postNewSessionCommand - New Session Created: 837f2a20-28bc-11e5-b12e-bf0d9bf8a2cf
[INFO] Skipping spec runner generation, because an identical spec runner already exists.
[INFO  - 2015-07-12T17:36:24.331Z] ShutdownReqHand - _handle - About to shutdown
[INFO]
-------------------------------------------------------
J A S M I N E   S P E C S
-------------------------------------------------------
[INFO]
messages
 getMessage
   should greet us with a specific message

printer
  printMessage
    should return true

extend
  deepExtend
    should properly extend one object with another <<< FAILURE!
      * Expected 3 to be 4.
    should not mutate incoming parameters
    should throw an exception when provided a null or undefined object

Results: 5 specs, 1 failures, 0 pending

[INFO] stopped o.e.j.s.h.ContextHandler{/webjars,file:/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/}
[INFO] stopped o.e.j.s.h.ContextHandler{/classpath,file:/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/}
[INFO] stopped o.e.j.s.h.ContextHandler{/,file:/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/}
[INFO] stopped o.e.j.s.h.ContextHandler{/spec,file:/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/}
[INFO] stopped o.e.j.s.h.ContextHandler{/scripts,file:/Users/isuftin/Development/Source/CIDA/amd-jasmine-mvn/}
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.528 s
[INFO] Finished at: 2015-07-12T12:36:24-05:00
[INFO] Final Memory: 17M/268M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal com.github.searls:jasmine-maven-plugin:2.0-beta-02:test (default-cli) on project amd-jasmine-mvn: There were Jasmine spec failures. -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

As expected, it failed.

Conclusion

I am now able to write testable RequireJS modules that are able to be automatically tested using our continuous integration solution (Jenkins) when I check in code.

There is a lot more that you can configure in the configuration section of the plugin in the pom. I've provided the minimal configuration needed to get you up and running. You can find out more about the jasmine-maven plugin's AMD support here. You can also delve into having the plugin create code coverage metrics.

Feel free to fork this Gist and contribute back with updated information.

@rharing
Copy link

rharing commented Dec 19, 2017

hmm any change of providing full repo for this? i keep on getting weird parse errors, and starting from a project that works makes the bug chaiser game a bit more easy
thanks
Ronald

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment