Skip to content

Commit

Permalink
Improved Geb integration
Browse files Browse the repository at this point in the history
Geb tests now show up as a separate test type; made a few style changes to the test results too
  • Loading branch information
clarkdave committed Nov 7, 2011
1 parent ca04314 commit ceb687e
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 12 deletions.
171 changes: 171 additions & 0 deletions app/controllers/TestRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package controllers;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;

import play.Logger;
import play.Play;
import play.cache.Cache;
import play.libs.IO;
import play.libs.Mail;
import play.mvc.*;
import play.templates.Template;
import play.templates.TemplateLoader;
import play.test.*;
import play.vfs.*;

/**
* This is a copy of the testrunner module's controller
* so we can add support for running Geb tests separately
*/
public class TestRunner extends Controller {

public static void index() {
List<Class> unitTests = TestEngine.allUnitTests();
List<Class> gebTests = TestEngine.allGebTests();
List<Class> functionalTests = TestEngine.allFunctionalTests();
List<String> seleniumTests = TestEngine.allSeleniumTests();
render(unitTests, gebTests, functionalTests, seleniumTests);
}

public static void list() {
StringWriter list = new StringWriter();
PrintWriter p = new PrintWriter(list);
p.println("---");
p.println(Play.getFile("test-result").getAbsolutePath());
p.println(Router.reverse(Play.modules.get("_testrunner").child("/public/test-runner/selenium/TestRunner.html")));
for(Class c : TestEngine.allUnitTests()) {
p.println(c.getName() + ".class");
}
for(Class c : TestEngine.allGebTests()) {
p.println(c.getname() + ".class");
}
for(Class c : TestEngine.allFunctionalTests()) {
p.println(c.getName() + ".class");
}
for(String c : TestEngine.allSeleniumTests()) {
p.println(c);
}
renderText(list);
}

public static void run(String test) throws Exception {
if (test.equals("init")) {
File testResults = Play.getFile("test-result");
if (!testResults.exists()) {
testResults.mkdir();
}
for(File tr : testResults.listFiles()) {
if ((tr.getName().endsWith(".html") || tr.getName().startsWith("result.")) && !tr.delete()) {
Logger.warn("Cannot delete %s ...", tr.getAbsolutePath());
}
}
renderText("done");
}
if (test.equals("end")) {
File testResults = Play.getFile("test-result/result." + params.get("result"));
IO.writeContent(params.get("result"), testResults);
renderText("done");
}
if (test.endsWith(".class")) {
Play.getFile("test-result").mkdir();
java.lang.Thread.sleep(250);
TestEngine.TestResults results = TestEngine.run(test.substring(0, test.length() - 6));
response.status = results.passed ? 200 : 500;
Template resultTemplate = TemplateLoader.load("TestRunner/results.html");
Map<String, Object> options = new HashMap<String, Object>();
options.put("test", test);
options.put("results", results);
String result = resultTemplate.render(options);
File testResults = Play.getFile("test-result/" + test + (results.passed ? ".passed" : ".failed") + ".html");
IO.writeContent(result, testResults);
try {
// Write xml output
options.remove("out");
resultTemplate = TemplateLoader.load("TestRunner/results-xunit.xml");
String resultXunit = resultTemplate.render(options);
File testXunitResults = Play.getFile("test-result/TEST-" + test.substring(0, test.length()-6) + ".xml");
IO.writeContent(resultXunit, testXunitResults);
} catch(Exception e) {
Logger.error(e, "Cannot ouput XML unit output");
}
response.contentType = "text/html";
Logger.info(response.status.toString())
renderText(result);
}
if (test.endsWith(".test.html.suite")) {
test = test.substring(0, test.length() - 6);
render("TestRunner/selenium-suite.html", test);
}
if (test.endsWith(".test.html")) {
File testFile = Play.getFile("test/" + test);
if (!testFile.exists()) {
for(VirtualFile root : Play.roots) {
File moduleTestFile = Play.getFile(root.relativePath()+"/test/" + test);
if(moduleTestFile.exists()) {
testFile = moduleTestFile;
}
}
}
if (testFile.exists()) {
Template testTemplate = TemplateLoader.load(VirtualFile.open(testFile));
Map<String, Object> options = new HashMap<String, Object>();
response.contentType = "text/html";
renderText(testTemplate.render(options));
} else {
renderText("Test not found, %s", testFile);
}
}
if (test.endsWith(".test.html.result")) {
flash.keep();
test = test.substring(0, test.length() - 7);
File testResults = Play.getFile("test-result/" + test.replace("/", ".") + ".passed.html");
if (testResults.exists()) {
response.contentType = "text/html";
response.status = 200;
renderText(IO.readContentAsString(testResults));
}
testResults = Play.getFile("test-result/" + test.replace("/", ".") + ".failed.html");
if (testResults.exists()) {
response.contentType = "text/html";
response.status = 500;
renderText(IO.readContentAsString(testResults));
}
response.status = 404;
renderText("No test result");
}
}

public static void saveResult(String test, String result) throws Exception {
String table = params.get("testTable.1");
File testResults = Play.getFile("test-result/" + test.replace("/", ".") + "." + result + ".html");
Template resultTemplate = TemplateLoader.load("TestRunner/selenium-results.html");
Map<String, Object> options = new HashMap<String, Object>();
options.put("test", test);
options.put("table", table);
options.put("result", result);
String rf = resultTemplate.render(options);
IO.writeContent(rf, testResults);
renderText("done");
}

public static void mockEmail(String by) {
String email = Mail.Mock.getLastMessageReceivedBy(by);
if(email == null) {
notFound();
}
renderText(email);
}

public static void cacheEntry(String key){
String value = Cache.get(key,String.class);
if(value == null){
notFound();
}
renderText(value);
}

}

30 changes: 26 additions & 4 deletions app/views/TestRunner/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@
.testResult table pre.trace {
display: none;
}
.testResult table pre.error {
font-size: 125%;
}
.testResult table .sourceLine {
border-left: 3px solid #c00;
padding: 4px 3px;
Expand Down Expand Up @@ -358,13 +361,17 @@
dataType: 'html',
url: '@{TestRunner.run("XXX")}'.replace('XXX', testId),
complete: function(res, status) {
var results = jQuery("<div/>").append(res.responseText).find('table');
var body = jQuery('<div/>').append(res.responseText)
var results = body.find('table');

if(!results || !results.size()) {
results = '<strong class="error">Error, the test has not been properly run. Check the server logs, or open this test in another browser tab to see the error page.</strong>';
testFail(test, results);
}
if(status == 'success') {
else if (body.find('.block.success').size()) {
testSuccess(test, results);
} else {
}
else {
testFail(test, results);
};
}
Expand Down Expand Up @@ -409,7 +416,7 @@
runNextTest();
};

var testFail = function(test, result) {
var testFail = function(test, result) {console.log('hi')
test.removeClass('passing').addClass('failed');
$('.touch', test).html('-');
$('.testResult', test).html(result).show();
Expand Down Expand Up @@ -598,6 +605,21 @@ <h2><span>There ${unitTests.size().pluralize('is', 'are')} ${unitTests.size()} u
</ul>
%{ tis = true; }%
#{/if}

#{if gebTests}
<h2><span>${tis ? '' : 'There '+gebTests.size().pluralize('is', 'are')} ${tis && !functionalTests ? 'and' : ''} ${gebTests.size()} geb test${gebTests.size().pluralize()},</span></h2>
<ul>
#{list items:gebTests, as:'test'}
<li>
<div class="test" id="${test.name}.class">
<span class="touch">+</span><a href="@{TestRunner.run(test.name+'.class')}">${test.name.replace('.','/').replace('$','.')}</a>
<div class="testResult"></div>
</div>
</li>
#{/list}
</ul>
%{ tis = true; }%
#{/if}

#{if functionalTests}
<h2><span>${tis ? '' : 'There '+functionalTests.size().pluralize('is', 'are')} ${tis && !seleniumTests ? 'and' : ''} ${functionalTests.size()} functional test${functionalTests.size().pluralize()},</span></h2>
Expand Down
2 changes: 1 addition & 1 deletion app/views/TestRunner/results.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ <h1>
</td>
<td class="${result.error ? 'error' : ''}" valign="top">
#{if result.error}
<strong><pre>${result.error}</pre></strong>
<strong><pre class='error'>${result.error}</pre></strong>
#{if result.sourceInfos}
<div class="source">
<span>${result.sourceInfos} :</span>
Expand Down
22 changes: 16 additions & 6 deletions src/play/groovysupport/GroovyPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,15 @@ class GroovyPlugin extends PlayPlugin {
.plus(Play.classloader.getAssignableClasses(Specification.class))
.findAll {
!Modifier.isAbstract(it.getModifiers()) &&
!FunctionalTest.class.isAssignableFrom(it)
!FunctionalTest.class.isAssignableFrom(it) &&
!GebTest.class.isAssignableFrom(it)
}
}

TestEngine.metaClass.static.allGebTests << {
Play.classloader.getAssignableClasses(GebTest.class)
.findAll { !Modifier.isAbstract(it.getModifiers()) }
}

Logger.info('Groovy support is active')
}
Expand Down Expand Up @@ -112,11 +118,10 @@ class GroovyPlugin extends PlayPlugin {
result.updatedClasses.each {
def appClass = new ApplicationClass()
appClass.name = it.name
println Play.javaPath
appClass.javaFile = new VirtualFile(it.source)
// TODO: if the javaFile can't be located for some reason
// (i.e. if the package name was messed up), it will cause serious
// problems later on, so it needs to be handled here
// it will cause serious problems later on, so it needs to
// be handled here
appClass.refresh()
appClass.compiled(it.code)
Play.classes.add(appClass)
Expand Down Expand Up @@ -149,14 +154,19 @@ class GroovyPlugin extends PlayPlugin {
Play.javaPath.each {
GroovyCompiler.getSourceFiles(it.getRealFile()).each { f -> map[f] = f.lastModified()}
}
return map
return map.findAll { file, lastModified ->
// we'd like to override the testrunner controller with our own, so
// let's make sure it never gets compiled... bit of a hack but I couldn't
// see any other way to override a controller in an included module
!(file.toString() =~ /(?i)testrunner.+TestRunner\.java/)
}
}

def update() {

// get the latest sources
def newSources = sources()

if (currentSources != newSources) {
// sources have changed, so compile them
def result = compiler.update(newSources.keySet().toList())
Expand Down
2 changes: 1 addition & 1 deletion src/play/test/GebTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class GebTest extends GebSpec {
// TODO: removed the asynchronous execution for now as it was
// breaking static file requests. At the moment any requests for static
// stuff (/public) will just return as 200 OKs with empty strings
// stuff still works but it means anything testing css/js functionality
// things still work but it means anything testing css/js functionality
// won't work

try {
Expand Down

0 comments on commit ceb687e

Please sign in to comment.