package org.codehaus.mojo.javascript; /* * Copyright 2001-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.net.URL; import java.util.Arrays; import java.util.Collections; import junit.framework.TestSuite; import net.jsunit.Configuration; import net.jsunit.ConfigurationException; import net.jsunit.JsUnitServer; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.surefire.junit.JUnitTestSet; import org.apache.maven.surefire.report.FileReporter; import org.apache.maven.surefire.report.ReportEntry; import org.apache.maven.surefire.report.Reporter; import org.apache.maven.surefire.report.ReporterManager; import org.apache.maven.surefire.testset.AbstractTestSet; import org.codehaus.plexus.util.DirectoryScanner; import org.codehaus.plexus.util.IOUtil; import org.mortbay.util.MultiException; /** * Goal which runs javascript tests using jsunit framework. Tests can be writter * either inside an html page, as documented by jsunit, or simply as javascript. * * @goal jsunit * @phase test * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a> */ public class JsUnitMojo extends AbstractJavascriptMojo { /** * Set this to 'true' to bypass unit tests entirely. Its use is NOT * RECOMMENDED, but quite convenient on occasion. * * @parameter expression="${maven.test.skip}" */ private boolean skip; /** * Set this to true to ignore a failure during testing. Its use is NOT * RECOMMENDED, but quite convenient on occasion. * * @parameter expression="${maven.test.failure.ignore}" */ private boolean testFailureIgnore; /** * Base directory where all reports are written to. * * @parameter expression="${project.build.directory}/surefire-reports" */ private File reportsDirectory; /** * Base directory where jsunit will run. * * @parameter expression="${project.build.directory}/test-scripts" */ private File workDirectory; /** * Base directory for jsunit test. * * @parameter expression="${basedir}/src/test/javascript" */ private File testSourceDirectory; /** * Browsers to run the jsunit tests * * @parameter */ private String[] browsers; private String[] DEFAULT_BROWSERS = { "firefox" }; /** * The local port to use for the jsunit HTTP server * * @parameter default-value="8080" */ private int port; /** * Exclusion pattern. * * @parameter */ private String[] excludes; /** * Inclusion pattern. * * @parameter */ private String[] includes; private static final String[] DEFAULT_INCLUDES = { "**/*.html", "**/*.htm", "**/*.js" }; /** * @parameter expression="${javascript.jsunit.firefox.path}" default-value="c:/program files/Mozilla Firefox/firefox.exe" */ private String firefoxPath; /** * @parameter expression="${javascript.jsunit.ie.path}" default-value="c:/program files/internet explorer/iexplore.exe" */ private String iePath; /** * {@inheritDoc} * * @see org.apache.maven.plugin.Mojo#execute() */ public void execute() throws MojoExecutionException, MojoFailureException { if ( skip ) { getLog().warn( "tests are skipped." ); return; } String[] tests = getTestsToRun(); if ( tests == null || tests.length == 0 ) { getLog().info( "no jsunit tests to run." ); return; } unpackJavascriptDependency( "net.jsunit:jsunit-testRunner", workDirectory ); if ( browsers == null ) { browsers = DEFAULT_BROWSERS; } for ( int i = 0; i < browsers.length; i++ ) { if ( new File( browsers[i] ).exists() ) { continue; } if ( "firefox".equalsIgnoreCase( browsers[i] ) ) { browsers[i] = firefoxPath; } if ( "iexplorer".equalsIgnoreCase( browsers[i] ) ) { browsers[i] = iePath; } } JsUnitServer server = new JsUnitServer(); try { runJsUnitTests( server, tests ); } catch ( Exception e ) { throw new MojoExecutionException( "Failed to run JsUnit tests", e ); } finally { try { server.stop(); } catch ( InterruptedException e ) { // Ignore; } } } private void runJsUnitTests( JsUnitServer server, String[] tests ) throws Exception { setupServer( server ); Reporter reporter = new FileReporter( reportsDirectory, Boolean.FALSE ); ReporterManager reportManager = new ReporterManager( Collections.singletonList( reporter ) ); ReportEntry report = new ReportEntry( this, "jsunit", "test Starting" ); reportManager.testSetStarting( report ); for ( int i = 0; i < tests.length; i++ ) { String test = tests[i]; String path = workDirectory.toURI().getPath(); String name = test.substring( 0, test.lastIndexOf( '.' ) ); if ( test.toLowerCase().endsWith( ".js" ) ) { test = buildMinimalHtml( test ); } server.setTestURL( new URL( "file://" + path + "testRunner.html?autoRun=true&submitresults=true" + "&resultid=TEST-" + name + "&testPage=" + path.substring( 1 ) + test ) ); JsUnitTestCase.setSuite( new TestSuite( JsUnitTestCase.class, name ) ); AbstractTestSet testSet = new JUnitTestSet( JsUnitTestCase.class ); testSet.execute( reportManager, getClass().getClassLoader() ); } report = new ReportEntry( this, "jsunit", "test Completed" ); reportManager.testSetCompleted( report ); checkFailure( reportManager ); } /** * @param test * @return * @throws IOException */ private String buildMinimalHtml( String test ) throws IOException { String name = test.substring( 0, test.lastIndexOf( '.' ) ); String html = name + ".html"; File file = new File( workDirectory, html ); file.getParentFile().mkdirs(); test = test.replace( '\\', '/' ); String basedir = ""; int i = 0; while ( ( i = test.indexOf( "/" ) ) > 0 ) { test = test.substring( i ); basedir += "../"; } if ( basedir.trim().length() == 0 ) { basedir = "."; } Writer w = new FileWriter( file ); w.write( "<html>\n" ); w.write( "<head>\n" ); w.write( "<script type='text/javascript' src='" + basedir + "/app/jsUnitCore.js'></script>\n" ); w.write( "<script type='text/javascript' src='" + test + "'></script>\n" ); w.write( "</head>\n" ); w.write( "<body>\n" ); w.write( "</body>\n" ); w.write( "</html>\n" ); IOUtil.close( w ); return html; } private String[] getTestsToRun() { if ( !testSourceDirectory.exists() ) { return null; } DirectoryScanner scanner = new DirectoryScanner(); scanner.setBasedir( testSourceDirectory ); scanner.setExcludes( excludes ); scanner.addDefaultExcludes(); if ( includes == null ) { includes = DEFAULT_INCLUDES; } scanner.setIncludes( includes ); scanner.scan(); String[] tests = scanner.getIncludedFiles(); return tests; } private void checkFailure( ReporterManager reportManager ) throws MojoFailureException { if ( reportManager.getNumErrors() + reportManager.getNumFailures() > 0 ) { String msg = "There are test failures.\n\nPlease refer to " + reportsDirectory + " for the individual test results."; if ( testFailureIgnore ) { getLog().error( msg ); } else { throw new MojoFailureException( msg ); } } } private void setupServer( JsUnitServer server ) throws ConfigurationException, MultiException { System.setProperty( Configuration.URL, "http://localhost:" + port + "/jsunit/" ); System.setProperty( Configuration.PORT, String.valueOf( port ) ); System.setProperty( Configuration.LOGS_DIRECTORY, reportsDirectory.getAbsolutePath() ); server.initialize(); server.setResourceBase( workDirectory ); server.setLocalBrowserFileNames( Arrays.asList( browsers ) ); server.start(); JsUnitTestCase.setSharedServer( server ); } }